JavaScript setMinutes() behaves wrongly around DST ending - javascript

When the US Daylight Saving ends, we switch our clocks back 1 hour and this makes the 1 AM hour happen twice on that day. However, JavaScript behaves strangely for timestamps in the second 1 AM hour (after clock switch) and keeps reverting them to the daylight time of 1 hour before. This can be seen when trying to use setMinutes and setHours methods.
This code sets the minutes of a date to its current minutes value, and behaves as expected (browser has America/Los_Angeles time zone):
let date = new Date("2021-07-07T09:40:00.000Z");
console.log(date.toLocaleString("en-us", {timeZoneName: "short"}));
// "7/7/2021, 2:40:00 AM PDT"
date.setMinutes(date.getMinutes());
console.log(date.toLocaleString("en-us", {timeZoneName: "short"}));
// "7/7/2021, 2:40:00 AM PDT"
But this code doesn't:
let date = new Date("2021-11-07T09:50:00.000Z"); // DST ended on Nov 7 at 2 AM
console.log(date.toLocaleString("en-us", {timeZoneName: "short"}));
// "11/7/2021, 1:50:00 AM PST"
date.setMinutes(date.getMinutes());
console.log(date.toLocaleString("en-us", {timeZoneName: "short"}));
// "11/7/2021, 1:50:00 AM PDT" <-- Wrong time zone
So the Date object can correctly print timestamps in the second (standard time) hour, but it interprets the date as still in daylight time when using setMinutes().
Is this expected behavior? It seems odd that date.setMinutes(date.getMinutes()) should alter the date.

Related

new Date(...).toISOString() in JavaScript gives incorrect result on one day of the year

I'm building a calendar and I noticed that the date is incorrect on one day of the year.
I wanted to standardize dates to ISO 8601. Let's take 2022-03-27 for example:
const foo = new Date(2022, 2, 27).toISOString()
This gives 2022-03-27T00:00:00.000Z as one would expect.
However, the next day, 2022-03-28:
const bar = new Date(2022, 2, 28).toISOString()
This gives 2022-03-27T23:00:00.000Z - 27th March at 23:00.
Why does this happen?
What's happening is that British Summer Time (Daylight Saving Time, aka DST) is kicking in between your two examples (specifically, it starts at 01:00 on 2022-03-27). toISOString always gives you UTC time (GMT) as you can tell from the Z at the end of the string, but your local time is an hour ahead of UTC after 01:00 on 2022-03-27 until DST ends at 02:00 on 30 October 2022.
In your first example, you're creating a Date with the local time of midnight on 2022-03-27, when your local time is (apparently) GMT+00:00 (like mine here in the UK). So toISOString gives you back 00:00 because your local time is GMT/UTC (that date/time is an hour before DST kicks in).
But in your second example, you're creating a Date in local time at midnight on 2022-03-28, when you're on DST. So you're offset from UTC by an hour (UTC is one hour behind you). Midnight 2022-03-28 UK time is 23:00 2022-03-27 UTC.
I don't know what you want to do with this stuff, but if you want to create a Date for midnight UTC on 2022-03-28, use new Date(Date.UTC(2022, 2, 28)).

Find next occurrence of a time in a non-local timezone (in this case, PST)

I want to get how far away is the next occurence of a particular PST time regardless of the client's timezone.
This would be trivial if the time were in UTC but I don't know how to do it in PST keeping in mind the observance of daylight savings time.
Eg. 4 PM PST would be 11 PM UTC since it is right now summer.
I would prefer not to have to manually input the dates of daylight saving time.
I am happy to use a library if this is not possible without one.
// returns the number of milliseconds from the current time until the specified time in PST.
function getTimeUntil (hour, minutes = 0, seconds = 0)
{
// implementation needed
}
The following is an explanation of why this is likely a duplicate of How to initialize a JavaScript Date to a particular time zone.
PST (presumably US Pacific Standard Time) is a timezone with a fixed offset, UTC -8. Places that observe PST and have daylight saving typically call that offset Pacific Daylight Time (PDT), which is UTC -7.
PST might also be Pitcairn Standard Time, which is also UTC -8 and observed all year round on Pitcairn Island. Converting PST to UTC is achieved by adding 8 hours.
However, likely you want to work with times and dates for a place that observes US PST in winter and US PDT in summer, e.g. Los Angeles. In that case you can use a library like Luxon or date.js that allows creating dates based on a timestamp and specified IANA representative location such as "America/Los_Angeles". If that is the case, then see the link above.
My implementation:
// returns the formatted time from the current time until the specified time in PST.
function getTimeUntil (hour, minutes = 0, seconds = 0)
{
let future = luxon.DateTime.now().setZone('America/Vancouver').set({
hours: hour,
minutes: minutes,
seconds: seconds
});
let now = luxon.DateTime.now().setZone('America/Vancouver');
if (future < now)
{
future = future.plus({ days:1 });
}
return future.diff(now, ["hours", "minutes", "seconds"]);
// implementation needed
}
console.log(getTimeUntil(13, 0, 0).toObject());
<script src="https://cdn.jsdelivr.net/npm/luxon#2.0.1/build/global/luxon.min.js"></script>

How to convert current time to CET in Angular

I have seen couple of questions on the same, but which I'm facing the issue is not addressed anywhere so that only asking again.
I am trying to convert current time to CET time so initially i had implemented like this
component.ts
public currentDate;
ngOnInit(){
this.currentDate = new Date();
}
component.html
TIME: {{currentDate | date:'h:mm a':'+0100'}}
With above snippet initially it was matching fine with CET time, but now getting one hour difference. And i found in docs like Central European Time CET alternates between UTC+1 (standard time) and UTC+2 (when daylight saving time (DST) is observed).
All countries in the CET time zone observe DST (UTC+2) from 02:00 am on the last Sunday of March until 03:00 am on the last Sunday of October.
So based on this from last Sunday of march to last Sunday of October supposed to add +2hrs..And tried the same and now matching the same with CET.
But how can we handle this dynamically, or any other approach to convert current time to CET, Instead of changing +1hr some time and +2hr some time period.
Thanks in advance.

Why does 'new Date()' parse a string date incorrectly?

When I try to parse a string date from March, new Date() works incorrectly. But when my string date is from April, everything is fine. I don't understand this. Why does it work like that?
var a = '2018-03-07T00:00+03:00';
console.log(a);
console.log(new Date(a).toString());
var b = '2018-04-07T00:00+03:00';
console.log(b);
console.log(new Date(b).toString());
Here's a screenshot from Google Chrome browser:
As others pointed out, it's due to the daylight saving time in your time-zone. Notice the times in your screenshot: the time for a is 23 and for b is midnight 00, which clearly tells you what happened.
If you want to parse the values without the daylight saving time, you can use the GMT+0 time-zone by replacing your time-zone +3:00 with z. However, then you need to correct time manually by adding/subtracting the hours of your time-zone (-3 in your case). Here is an example:
var a = '2018-03-07T00:00+03:00';
a.replace('+03:00', 'z');
a = new Date(a);
a.setHours(a.getHours() - 3); //3 is your time-zone
console.log(a.toUTCString());
var b = '2018-04-07T00:00+03:00';
b.replace('+03:00', 'z');
b = new Date(b);
b.setHours(b.getHours() - 3); //3 is your time-zone
console.log(b.toUTCString());
Obviously, this code will only work for one known time-zone. If your values can be in different time-zone, then instead of replacing, you need to extract the time-zone from the string (the last 6 characters in this format, except for GMT-0 which is z), and then use it to correct the time on the setHours() line.
Because of summer daylight saving time. According to Date documentation, the date is specific moment in time relative to Jan 1st 1970. That moment in time in March belonged to the part of year with daylight saving offset in your specific locale
Your first date is Standard Time... and the second one is Daylight Time.
var x = new Date('2018-03-07T00:00+03:00');
console.log(x);
var y = new Date('2018-04-07T00:00+03:00');
console.log(y);
In your scenario... EET – Eastern European Time versus EEST – Eastern European Summer Time like shown on console.

In javascript, how to get timezone value in UTC format for new Date(2017,05,31).toISOString()?

How to get timezone value for new Date(2017,05,31).toISOString()? It always comes as 000Z for any Date when the date is passed to the Date constructor. But for new Date().toISOString(), it gives the the timezone value.
new Date(2017,05,31).toISOString() gives "2017-05-30T18:30:00.000Z"
and new Date().toISOString() gives "2017-06-07T15:29:23.692Z". How to get timezone in UTC format for the past dates?
If you want the time to default to midnight in UTC, you can use Date.UTC(year, month, ...) to first create a timestamp based in UTC.
var utcMay31 = Date.UTC(2017, 4, 31); // note: 4 = May (0 = January)
Then, create the Date from that timestamp.
new Date(utcMay31).toUTCString(); // "Wed, 31 May 2017 00:00:00 GMT"
However, if you're wanting to know the timezone stored in the Date object, it doesn't actually have that. Dates represent an "instant" in time as the total number of milliseconds that have passed since Jan 1, 1970 00:00:00.000 UTC.
new Date().getTime(); // 1496851...
A Date can tell you the user's local offset from UTC in minutes at that instant.
new Date().getTimezoneOffset(); // e.g. 0, -480, 300
Otherwise, the timezone is limited to two choices when creating date strings, and the choice is based on the method used – user's local timezone or UTC.
new Date().toString(); // "now" in user's local time
new Date().toUTCString(); // "now" in UTC time
new Date().toISOString(); // "now" also in UTC time, alternate format
// etc.
You're confused ISO date values do not show the "time zone" instead they show the UTC time. Z stand for Zulu (UTC time).
2017-06-07T15:29:23.692Z
The bold part is not the time zone. It is the milli-seconds, the full time is in UTC. The reason it shows a 000Z in the set Date is because you didnt' set the milli-seconds.
If you want to display the time zone use toUTCString(). However it will display GMT which is UTC/Greenwich Time. To display the local time zone in a the date format you can use date.toLocaleString('en-US',{timeZoneName:'short'}) for example will display the date plus the local US time zone. Or you can use toString() which will display the GMT offset + the long local time zone.
In javascript, parsing, rendering and constructing dates will always assume local. It will convert to a timestamp, the number of milliseconds since 1-1-1970 00:00:00. JSON.stringify will convert to a UTC string, but legacy framworks use local dates. Always beware of this.
var myDate = new Date(); // this is now.
you can get your timezoneoffset (in minutes) with myDate.getTimezoneOffset(), but this will return the same offset for every date (aside from daylight saving time)
You shouldn't do this:
var utcDate = new Date(+d+60000*d.getTimezoneOffset());
// +d convert the date to a timespan.
// getTimezoneOffset() is in minutes
// *60000 makes that in milliseconds, the scale timespans operate upon
Date has a few methods to format dates, but always as local or UTC date. You need to do it manually if you want different time zones.
Note: the Date.UTC(...) function returns a timestamp. You sometimes see shifted dates, so they behave like UTC. But this causes problems later on.
var date = new Date(2000,1,1,12,0,0);
// DO NOT USE (breaks at start of daylight saving time)
// these are date/times that have the UTC-value,
// but Javascript treats them like local dates with this value.
utcDate1 = (+date-60000*d.getTimeZoneOffset()); // minus!!
utcDate2 = new Date(Date.UTC(2000,1,1,12,0,0));
// DO NOT USE (breaks at start of daylight saving time)
BTW
Edge, Chrome and Firefox display dates differently in the console: Edge and Firefox always shows local date, Chrome shows UTC. Also, if you change your timezone, Edge will screw up.

Categories

Resources