JS time zone
I have been confused by converting time zones in Angular for several days, it turns out that UTC ISO date formats need to add a letter “Z” at the end which means zero offset1. So what happens if we left it out?
In Firefox
new Date("2018-09-16T09:23:38.0698603");
// output: Date 2018-09-16T01:23:38.069Z ❌
new Date("2018-09-16T09:23:38.0698603").toLocaleString();
// output: "9/16/2018, 9:23:38 AM" ❌
new Date("2018-09-16T09:23:38.0698603Z");
// output: Date 2018-09-16T09:23:38.069Z ✔️
new Date("2018-09-16T09:23:38.0698603Z").toLocaleString()
// output: "9/16/2018, 5:23:38 PM" ✔️
With “Z”, Firefox will create a Date
object with the same time. Without “Z”, you will get a time with offset, it depends on your local time zone.
In Chrome
new Date("2018-09-16T09:23:38.0698603");
// output: Sun Sep 16 2018 09:23:38 GMT+0800 (China Standard Time) ❌
new Date("2018-09-16T09:23:38.0698603").toLocaleString();
// output: "9/16/2018, 9:23:38 AM" ❌
new Date("2018-09-16T09:23:38.0698603Z");
// output: Sun Sep 16 2018 17:23:38 GMT+0800 (China Standard Time) ✔️
new Date("2018-09-16T09:23:38.0698603Z").toLocaleString();
// output: "9/16/2018, 5:23:38 PM" ✔️
new Date("2018-09-16T09:23:38.0698603Z").toLocaleString([], { hour: 'numeric', minute: 'numeric' });
// output: "5:23 PM" ✔️
With “Z”, Chrome will convert the UTC time to your local time zone. Without “Z”, you get the same time but with your local time zone!
In Safari
new Date("2018-09-16T09:23:38.0698603");
// output: Sun Sep 16 2018 17:23:38 GMT+0800 (CST) ✔️
new Date("2018-09-16T09:23:38.0698603").toLocaleString();
// output: "9/16/2018, 5:23:38 PM" ✔️
new Date("2018-09-16T09:23:38.0698603Z");
// output: Sun Sep 16 2018 17:23:38 GMT+0800 (CST) ✔️
new Date("2018-09-16T09:23:38.0698603Z").toLocaleString();
// output: "9/16/2018, 5:23:38 PM" ✔️
Safari doesn’t care the letter “Z” at all, it will convert to your local time zone anyway.
In some shitty Chinese Android browsers
new Date("2018-09-16T09:23:38.0698603");
// output: Sun Sep 16 2018 09:23:38 GMT+0800 (CST) ❌
new Date("2018-09-16T09:23:38.0698603").toLocaleString();
// output: "Sun Sep 16 2018 09:23:38 GMT+0800 (CST)" ❌
new Date("2018-09-16T09:23:38.0698603Z");
// output: Sun Sep 16 2018 17:23:38 GMT+0800 (CST) ✔️
new Date("2018-09-16T09:23:38.0698603Z").toLocaleString();
// output: "Sun Sep 16 2018 17:23:38 GMT+0800 (CST)" ✔️
new Date("2018-09-16T09:23:38.0698603Z").toLocaleString([], { hour: 'numeric', minute: 'numeric' });
// output: "Sun Sep 16 2018 17:23:38 GMT+0800 (CST)" ❌
These basters don’t support locales
and options
parameters of toLocaleString()
!
Miscellaneous
- Get the current UTC time in ISO format:
new Date().toISOString()
// "2020-03-27T07:06:30.600Z"
-
If you want to create a UTC
Date
object, you should useDate.UTC()
. -
If you want to get the local time zone name, use this:
Intl.DateTimeFormat().resolvedOptions().timeZone;
// output: "Asia/Shanghai"
-
If you want to get the offset times, use
getTimezoneOffset()
:
new Date().getTimezoneOffset();
// output: -480
Keep in mind that this method:
returns the time zone difference, in minutes, from current locale (host system settings) to UTC.
– MDN2
In this case, it means that UTC time is after the local time(UTC+8) 480 minutes. And sometimes, Firefox will return 0!
In Angular, if you use Datepipe, it will convert to your local time by default. But you can also set it manually, by passing the timezone
parameter. For example, "+0800"
means the local time is 8 hours before UTC time3.
Conclusion
Don’t use dateString
to create Date
objects, as MDN noted:
parsing of date strings with the
Date
constructor (andDate.parse
, they are equivalent) is strongly discouraged due to browser differences and inconsistencies. Support for RFC 2822 format strings is by convention only. Support for ISO 8601 formats differs in that date-only strings (e.g. “1970-01-01”) are treated as UTC, not local.– MDN4
If you have to use it, make sure you add the letter “Z”. Then use toLocaleString()
, we can convert UTC to your local time zone with formate(except some gross Android browsers). toLocaleString()
will use your local time zone by default unless you set the timezone
option5.
You see, I’ve learned something today, yesterday and the day before yesterday: ****