moment-timezone icon indicating copy to clipboard operation
moment-timezone copied to clipboard

Inconsistent date result between constructor and set methods around DST switch

Open jason-codaio opened this issue 4 years ago • 2 comments

I was debugging a bug recently and realized that depending on how I create a moment I get different results. Apparently the logic used by the setters is different than the constructor arguments. This seems like a bug?

const timezone = 'Asia/Beirut';
const first = moment.tz([2020, 2, 29], timezone).toDate();
const second = moment.tz([1900, 0, 1], timezone).year(2020).month(2).date(29).toDate();
console.log('first', first);   // first 2020-03-28T22:00:00.000Z
console.log('second', second); // second 2020-03-28T21:00:00.000Z
console.log('date of first', moment.tz(first, timezone).date()); // 29
console.log('date of first', moment.tz(second, timezone).date()); // 28

[email protected] moment-timezone@^0.5.28

It is a bit hard to work around generically since the get methods are a much more forgiving when it comes to handling offsets/bubbling/rollover

jason-codaio avatar Mar 17 '20 18:03 jason-codaio

@jason-codaio I believe this is due to DST change on March 29, 2020 at this timezone, and maybe some weirdness behind date set. When you set year, month, date on a moment object, it actually does some math to add the time to create the new date.

Screen Shot 2021-12-17 at 5 32 09 PM

Luxon handles it correctly, and they explains the math for DST very well.

Screen Shot 2021-12-17 at 5 24 53 PM

hdoan-codaio avatar Dec 18 '21 01:12 hdoan-codaio

OK, there is a serious bug in there, this timezone skips midnight on 29th Mar, so 23:59:59 -> 01:00:00, so the first object is correct, and the second one is messed up beyond repair. Will need to investigate:

> moment.tz([1900, 0, 1], timezone).year(2020).month(2).date(29).format()
'2020-03-29T00:00:00+03:00'
> moment.tz([1900, 0, 1], timezone).year(2020).month(2).date(29).add(1, 'min').format()
'2020-03-28T23:00:00+02:00'
> moment.tz([1900, 0, 1], timezone).year(2020).month(2).date(29).add(-1, 'min').format()
'2020-03-28T23:00:00+02:00'
> moment.tz([1900, 0, 1], timezone).year(2020).month(2).date(29).add(-10, 'min').format()
'2020-03-28T23:00:00+02:00'
> moment.tz([1900, 0, 1], timezone).year(2020).month(2).date(29).add(-20, 'min').format()
'2020-03-28T23:00:00+02:00'

ichernev avatar Aug 27 '22 15:08 ichernev