Store date as if they were entered in a specific timezone - javascript

I am using Moment. I need users to enter a date, and make sure that that's always the time for Australia/Perth, regardless of what the browser is set as.
For example, assume the computer is set as Sydney time (which right now is +3 but in winter it's +2). I want the user to enter a date/time, and make sure that that date/time is stored as Perth's time.
Note that visualising the correct date isn't an issue (with moment.tz). What I am worried about, is the date object creation which would need to happen providing a time, and forcing the browser to pretend that they are in that timezone.
I need this to work regardless of daylight savings etc.
UPDATE: this is what I want to achieve:
// MY CURRENT TIMEZONE IS SYDNEY, CURRENTLY PERTH + 3 BUT +2 IN SUMMER
// IN PERTH IT's 10:11AM, and *THAT* is the time I am interested in
// storing, not 13:11:58
var d = new Date()
// => Wed Nov 28 2018 13:11:58 GMT+1100 (Australian Eastern Daylight Time)
// NOTE: the date 13:11:58 SYDNEY time. I don't want this.
// I MUST pretend that users entered the date with their timezone
// is in Perth
// So...
// Create a date string that exclude original timezone and includes new timezone
perthDateString = moment(new Date()).format('YYYY-MM-DDTHH:MM:ss') + '+0800'
// => "2018-11-28T13:11:58+0800"
// Make a new date object using the tinkered date string
var newD = new Date(perthDateString)
// Display the date. Note: the time is "wrong" (since it displays
// a time that is 3 hours ahead), but it's actually the correct
// answer since 'd' is meant to be Perth time in the first place
newD
// => Wed Nov 28 2018 16:11:58 GMT+1100 (Australian Eastern Daylight Time)
// Display the date as the Perth time
moment.tz(newD, 'Australia/Perth').toString()
// => "Wed Nov 28 2018 13:11:58 GMT+0800"
However:
in perthDateString = moment(new Date()).format('YYYY-MM-DDTHH:MM:ss') + '+0800', I would like to specify Australia/Perth, rather than '+0800'
I feel uneasy with dealing with dates by chopping/concatenating strings
I wonder if EVERY browser will be able to parse the date returned by .format('YYYY-MM-DDTHH:MM:ss') + '+0800' or if I am going to have surprises -- especially when/if I have a solution so that I use Australia/Perth instead

If you are anywhere in the world (say, Sydney or Tokyo), and the local time is "12:30", but you want to store the same time-of-day ("12:30") as if you were in Perth -- you can use the moment-timezone package together with moment.
For example, this snippet will give you a moment for "12:30" in Perth:
let x = moment.tz('2019-01-01T12:30:00', 'Australia/Perth')
console.log(x.format()); // Show that it is 12:30 in Perth time
console.log(new Date(x)); // Generate Date for that time
<script src="https://momentjs.com/downloads/moment.js"></script>
<script src="http://momentjs.com/downloads/moment-timezone-with-data.js"></script>

Related

What does the values before "Z" indicate in a ISO8601 date string?

I'm trying to understand ISO8601 time format
What does this value mean?
2019-11-14T00:55:31.820Z
I understand this as such
2019-11-14 // November 14th, 2019
T00:55:31 // 12:55 AM in GMT time (London)
.820 // why is this needed or specified?
Z // The "Z" indicates to store this as GMT time (London)
I don't understand why the .820 is needed here. Reading into it, this refers to timezone 820, which is California.
If I were to go to the Javascript console and write this with and without that 820 value, I would get the same results, based on my locale (EST time zone)
new Date('2019-11-14T00:55:31.820Z') // Wed Nov 13 2019 19:55:31 GMT-0500 (Eastern Standard Time)
new Date('2019-11-14T00:55:31Z') // Wed Nov 13 2019 19:55:31 GMT-0500 (Eastern Standard Time)
What does the prefix value before the Z actually do?
The "Z" indicates to store this as GMT time (London)
No, it indicates that the time value presented is in UTC, not that you should store it in GMT/UTC. It tells you what time zone to interpret the information provided in.
I don't understand why the .820 is needed here. Reading into it, this refers to timezone 820, which is California.
That's milliseconds, not a time zone. It's 820ms into 00:55:31 (e.g., it's 180ms away from being 00:55:32).
If I were to go to the Javascript console and write this with and without that 820 value, I would get the same results, based on my locale (EST time zone)
Only because the output of whatever console you're quoting doesn't include milliseconds. If you check the actual dates, you'll see that they're 820ms apart:
const dt1 = new Date('2019-11-14T00:55:31.820Z');
const dt2 = new Date('2019-11-14T00:55:31Z');
console.log(dt1.valueOf() - dt2.valueOf()); // 820
(The underlying value of a Date instance is the number of milliseconds it represents since Jan 1st 1970 at midnight UTC. So if we subtract d2 [which doesn't have the .820] from d1 [which does], we see they're 820ms apart.)

Convert date from UK GMT string to local date in JavaScript

I have a situation where I am always returned the date from the server as a UK date time string.
E.g. '2020-07-19 16:40:00'
This would be 4:40PM in UK at +01:00, or 3:40PM UTC.
I want to be able to convert this time from GMT to the local time on the computer;
If I do this when in the UK...
var date = new Date('2020-06-19 16:40:00 GMT');
it returns Fri Jun 19 2020 17:40:00 GMT+0100 (British Summer Time)
Which is an hour out.
If I do the date in winter time (without daylight savings), this is correct.
var date = new Date('2020-01-19 16:40:00 GMT');
returns Sun Jan 19 2020 16:40:00 GMT+0000 (Greenwich Mean Time)
Is there a way I can correctly adjust this to always give the correct time regardless of what timezone the computer is set in, based on UK clock times.
Thanks in advance
As I understand your question, you don't know if the timestamp from the server is GMT or BST as the offset isn't included. You can work it out using plain JS but it's somewhat kludgy and error prone, see Calculate Timezone offset only for one particular timezone.
It would be much better to get the server to use an ISO 8601 format supported by ECMAScript and either send the offset or always use UTC/GMT.
If that isn't an option, you can use a library like Luxon to specify the location (and hence offset rules) to use for parsing, e.g.
let DateTime = luxon.DateTime;
['2020-07-19 16:40:00', // BST +1
'2020-01-19 16:40:00' // GMT +0
].forEach(ts => console.log(
DateTime.fromFormat(ts, 'yyyy-LL-dd HH:mm:ss', {zone: 'Europe/London'}))
);
<script src="https://cdn.jsdelivr.net/npm/luxon#1.24.1/build/global/luxon.min.js"></script>
PS Don't forget to always tell the parser the format to parse.

Start of Day from one timezone to GMT

I am using moment-timezone library to build a UI that needs to be relative to a variety of timezones.
I am taking an input of a timezone, i.e "America/Chicago" and need to get the start of day in GMT.
For instance, if today is March 27th at 9am Chicago time (2pm GMT), I need to get the date in epoch seconds for March 27th, 00:00 AM.
I'm using the moment.tz("America/Chicago").startOf('day') but I keep getting Tue Mar 27 2018 01:00:00 GMT-0400 (EDT) . Any idea how to do this?
Thanks
// This part you are already doing correctly.
// You get back a Moment object representing the start of the current day in Chicago:
var m = moment.tz("America/Chicago").startOf('day');
I need to get the date in epoch seconds
// Ok, so simply now get the associated Unix Time
var timestamp = m.unix();
Also note that the correct terminology is "Unix Time", not "epoch seconds".
See my blog post: "Please don't call it Epoch Time".
... but I keep getting Tue Mar 27 2018 01:00:00 GMT-0400 (EDT)
You are probably either looking at _d or a Date object, or rather the string representation of one. Don't. See this Moment.js documentation for details.
Per your comment:
I need to take the current time in a specific timezone. I then need to convert that time to the corresponding day in GMT. Finally I need to get the midnight epoch timestamp of that GMT day.
That's a little different then you originally asked, but it would be like this:
var timestamp = moment.utc().startOf('day').unix();
Note that there's no purpose in involving another time zone for this operation. Logically, when asking for "Now in time zone A converted to time zone B", it's the same as asking for "Now in time zone B". In other words, you would get the same value even when the time zone was present:
var timestamp = moment.tz('America/Chicago').utc().startOf('day').unix();
So you're better off just leaving the time zone out.

Why does Javascript show me the wrong date?

Consider the following date object which is created in JavaScript.
var date = new Date("2017-09-07T16:46:06.000Z");
This date object should be equivalent to Sep 7 2017 4:46:06 PM
However, in the browser console, when I type the following:
console.log(date);
The following is returned:
Fri Sep 08 2017 02:46:06 GMT+1000 (E. Australia Standard Time)
The time is wrong. (It actually is today's date, but the time is completely wrong).
Key points of confusion:
My computer timezone is set to GMT+1000 (Australia/Brisbane)
When I created the date object, I did not specify the timezone, therefore it should conform to my systems timezone
When I log the date object to the console, it is still using GMT+1000 (Australia/Brisbane) but the date is different
When you created the date, you did specify a timezone. That Z at the end means Zulu or Greenwich Mean Time. Your computer is 10 hours off from GMT, so it adjusts to your local timezone for display.
If you want the date to be in your local time zone, remove the Z
var date = new Date("2017-09-07T16:46:06.000Z");
So it looks like the Z at the end of your date string is meant to represent UTC or Zulu time
var date = new Date("2017-09-07T16:46:06.000");
should be the correct solution

Convert milliseconds into UTC date object with UTC Time Zone

I am trying to convert milliseconds into UTC date object as below -
var tempDate = new Date(1465171200000);
// --> tempDate = Mon Jun 06 2016 05:30:00 **GMT+0530 (India Standard Time)** {}
var _utcDate = new Date(tempDate.getUTCFullYear(), tempDate.getUTCMonth(), tempDate.getUTCDate(), tempDate.getUTCHours(), tempDate.getUTCMinutes(), tempDate.getUTCSeconds());
//--> _utcDate = Mon Jun 06 2016 00:00:00 **GMT+0530 (India Standard Time)** {}
Time is resetting to UTC time but Time Zone is still coming as GMT+0530 (India Standard Time).
Is there any sure shot approach to convert milliseconds into UTC date object with UTC Time Zone?
Quoting from this answer (that I suggest you to read completely):
There is no time zone or string format stored in the Date object itself. When various functions of the Date object are used, the computer's local time zone is applied to the internal representation.
As time zone is not stored in the Date object there is no way to set it.
I see two options:
the first is to make use of a library (as suggested in the answer above). Quite popular now is Moment.js
the second (pure JavaScript - if it's a viable solution in your context):
Do the "time math" in your local timezone.
When you're ready to switch to UTC use toUTCString() method.
Of course you'll end up with a string as this let you store the time zone as long as the date time value.
As you won't be able to manipulate the date time as a Date object from now on this must be the last step.
var tempDate = new Date(1465171200000);
// Mon Jun 06 2016 05:30:00 GMT+0530
// Do your date time math here
// using the Date object's methods
var utcDateAsString = tempDate.toUTCString();
// Mon Jun 06 2016 00:00:00 GMT
You say:
Time is resetting to UTC time but Time Zone is still coming as GMT+0530 (India Standard Time). Is there any sure shot approach to convert milliseconds into UTC date object with UTC Time Zone?
But I think you misunderstand what is occurring. When you pass a number to the Date constructor as in:
new Date(1465171200000)
is it assumed to be milliseconds since the ECMAScript epoch (1970-01-01T00:00:00Z), so a Date object is created with that value as its internal time value. So Date objects are inherently UTC.
When you write that to a string, internally a human readable date string is generated based on the host timezone setting, which is why you see a date for GMT+0530 (that is your host system timezone setting). The Date object itself does not have a timezone, it's always UTC.
When you then use UTC values to create a "local" Date using:
new Date(tempDate.getUTCFullYear(), tempDate.getUTCMonth(), ...)
then the host timezone is used to generate a UTC time value equivalent to a "local" date for the associated values. You've effectively subtracted your timezone offset from the original time value so it now represents a different moment in time. You can get exactly the same result doing:
var d = new Date(1465171200000);
d.setMinutes(d.getMintues() + d.getTimezoneOffset());
which just shows a bit more clearly what's going on. Note that ECMAScript timezone offsets are in minutes and have the opposite sense to UTC, that is, they are negative (-) for east and positive (+) for west. So an offset of UTC+05:30 it is represented as -330 and you need to add it to "shift" a Date rather than subtract it.
var tempDate = new Date(1465171200000);
var _utcDate = new Date(tempDate.getUTCFullYear(), tempDate.getUTCMonth(), tempDate.getUTCDate(), tempDate.getUTCHours(), tempDate.getUTCMinutes(), tempDate.getUTCSeconds());
console.log('Direct conversion to Date\ntempDate: ' + tempDate.toString());
console.log('Adjusted using UTC methods\n_utcDate: ' + _utcDate.toString());
tempDate.setMinutes(tempDate.getMinutes() + tempDate.getTimezoneOffset());
console.log('Adjusted using timezoneOffset\ntempDate: ' + tempDate.toString());
However, I can't understand why you want to do the above. 1465171200000 represents a specific moment in time (2016-06-06T00:00:00Z), adjusting it for every client timezone means it represents a different moment in time for each client with a different timezone offset.
If you create a Date from a Number, the local timezone is the one considered. But if you want to see what a timestamp would mean with the hours corrected for UTC, you could use a helper as such:
Number.prototype.toUTCDate = function () {
var value = new Date(this);
value.setHours(value.getHours() - (value.getTimezoneOffset() / 60));
return value;
};
The usage would be:
var date = (1465171200000).toUTCDate();

Categories

Resources