moment / luxon

⏱ A library for working with dates and times in JS
https://moment.github.io/luxon
MIT License
15.26k stars 731 forks source link

Interval.hasSame ignores timezones unless the interval is empty #1424

Open brentobi opened 1 year ago

brentobi commented 1 year ago

Interval.hasSame ignores timezones unless the interval is empty.

Baseline Interval.hasSame (expectedly) returns

because the local hours are matching.

That is because Interval.hasSame internally uses DateTime.hasSame which ignores timezones when comparing unit values. https://github.com/moment/luxon/blob/d30908f973359e8c4127535858e48599d7e0b7c0/src/datetime.js#L1950

Expected behaviour I would expect Interval.hasSame to return

because that should be the same case as the first example above.

Actual behaviour Instead Interval.hasSame always returns true if the interval isEmpty (-> same unix timestamps) even if different timezones would result in different local unit values.

Analysis This bug (?) seems to have been introduced in https://github.com/moment/luxon/issues/709 by returning true early in case the interval isEmpty. https://github.com/moment/luxon/blob/33f79577a16f56629ddf9c1f1034259da7222d9c/src/interval.js#L251-L253

Example code

(() => {
let s,e,i;

const log = (expect) => {
console.log(s.hour, s.toLocaleString(luxon.DateTime.DATETIME_FULL_WITH_SECONDS), s.toUTC().toISO());
console.log(e.hour, e.toLocaleString(luxon.DateTime.DATETIME_FULL_WITH_SECONDS), e.toUTC().toISO());
console.log('i.hasSame("hour")', i.hasSame("hour"), "expect", expect);
};

s = luxon.DateTime.fromISO("2023-01-01T10:15:00.000+00:00", {zone: 'UTC+2'});
e = luxon.DateTime.fromISO("2023-01-01T10:30:00.000+00:00", {zone: 'UTC+1'});
i = luxon.Interval.fromDateTimes(s, e);
log(false);

// 12 '1 January 2023 at 12:15:00 GMT+2' '2023-01-01T10:15:00.000Z'
// 11 '1 January 2023 at 11:30:00 GMT+1' '2023-01-01T10:30:00.000Z'
// i.hasSame("hour") false expect false

s = luxon.DateTime.fromISO("2023-01-01T10:15:00.000+00:00", {zone: 'UTC+2'});
e = luxon.DateTime.fromISO("2023-01-01T11:30:00.000+00:00", {zone: 'UTC+1'});
i = luxon.Interval.fromDateTimes(s, e);
log(true);

// 12 '1 January 2023 at 12:15:00 GMT+2' '2023-01-01T10:15:00.000Z'
// 12 '1 January 2023 at 12:30:00 GMT+1' '2023-01-01T11:30:00.000Z'
// i.hasSame("hour") true expect true

s = luxon.DateTime.fromISO("2023-01-01T10:15:00.000+00:00", {zone: 'UTC+2'});
e = luxon.DateTime.fromISO("2023-01-01T10:15:00.000+00:00", {zone: 'UTC+1'});
i = luxon.Interval.fromDateTimes(s, e);
log(false);

// 12 '1 January 2023 at 12:15:00 GMT+2' '2023-01-01T10:15:00.000Z'
// 11 '1 January 2023 at 11:15:00 GMT+1' '2023-01-01T10:15:00.000Z'
// i.hasSame("hour") true expect false
})();

P.S.: Thank's for providing this lib!