ember-power-calendar icon indicating copy to clipboard operation
ember-power-calendar copied to clipboard

The problem with timezones

Open MichalBryxi opened this issue 7 years ago • 7 comments

The problem:

  1. A user selects a date with ember-power-calendar. Let's say it was: Sat Oct 20 2018.
  2. The addon returns as a date field native JS Date object with the user's browser timezone. In my case, it is: Sat Oct 20 2018 00:00:00 GMT+0100 (British Summer Time).
  3. Since Date object is nicely consumable by ember-data the developer might easily pass that value directly to some model property.
  4. Once ember-data tries to save that property (typically through json-api serializer), here's what gets passed to the server: 2018-10-19T23:00:00.000Z.
  5. Then if the server stores only DATE, without the time part it might happen that the wrong date gets saved. That is actually how I bumped into this bug.

See the one hour difference that leads to a different date. That is because there is different timezone.

I kidna do understand that the information is still there and I can recalculate the "correct selected date" using the information about user's timezone. But I feel like the consumer of this addon should not care about this. If the addon always returns date in UTC, then there should be no problem. Something like:

new Date(Date.UTC(2018, 10, 20));
Tue Nov 20 2018 00:00:00 GMT+0000 (Greenwich Mean Time)

I tried to isolate a minimum reproducible code here.

Thanks for consideration.

MichalBryxi avatar Oct 04 '18 19:10 MichalBryxi

I encountered the same problems. I solved it with moment's enfOfDay method.

wuarmin avatar Oct 06 '18 11:10 wuarmin

Can you maybe elaborate @wuarmin? You created getter/setters on the model's property and changed the value accordingly? Or observing the property that was returned by ember-power-calendar and changing the model property? Would be nice to have a complete example of possible workaround/solution before this one gets closed.

MichalBryxi avatar Oct 06 '18 12:10 MichalBryxi

I encapsulated ember-power-calendar in my custom calendar component and handle all this stuff there. My component's public api contains a onChanged action which is fired with the corrected date object.

wuarmin avatar Oct 06 '18 14:10 wuarmin

For me it would be useful is if you could configure the datepicker for moment to be in utc mode (and for dates, it might be sensible to turn this on by default).

It's such a pain that for half the year all my dates are out by 1 day unless I override the getting/ setting of moment.

fran-worley avatar Oct 15 '18 07:10 fran-worley

I'm not sure bout this...

This seems like not an addon issue, and more of a standard problem that occurs with any and every app that has to do with dates and timezones. Whether you're getting the date from a new Date() or this date picker, you'll need to be wise about how you handle the date objects to ensure they mean what you want them to mean when they get serialized or translated from javascript to db values.

alexparker avatar Nov 18 '19 19:11 alexparker

I think this should be considered a bug. PowerCalendar is only concerned with dates - we only end up dealing with times because it's not possible to have a native Date or moment object that does not also encapsulate a time. Given that, the date objects PowerCalendar spits out should be free from any ambiguity that adding a time may introduce - if a user selects 15 September on a calendar, in no use case, regardless of their timezone, should it be possible to interpret this as any other date. However, in the current implementation, this is not the case.

For example, if we pass in a @center a Date object with this value:

Tue Sep 01 2020 01:00:00 GMT+0100 (British Summer Time)

this is healthy - when we strip off the time, which is of course irrelevant, regardless of how we do that conversion (i.e. via UTC or locally), the date is 1 September.

However, when PowerCalendar exposes dates, via calendar.Days.date for example, the date object looks like this:

Tue Sep 01 2020 00:00:00 GMT+0100 (British Summer Time)

Note the time offset is still +1 but the time is now midnight. We know the intention is this should also be 1 September, but the way the time has been added has introduced an ambiguity. If we pass that through a function which interprets it as UTC time, we end up with 31 August.

I think the crux is here (assuming use of ember-power-calendar-moment): https://github.com/cibernox/ember-power-calendar-moment/blob/31f591ff600281448c257a8b065a75b701348107/addon/index.js#L17

Dates we pass into startOf with equivalent time and timezone offset i.e. 01:00:00 GMT+0100 come out with the time reset to midnight but with the same timezone - 00:00:00 GMT+0100 - that feels wrong.

The potential solution is:

return moment.utc(date).startOf(unit).toDate();

which preserves the hour and timezone offset initially passed.

In fact I think any use of toDate() should be called on a UTC moment i.e. call moment.utc(date) rather than just moment() however, I'm nervous about what that might to do backwards compatibility and any historical hacks people have implemented to get around this. Also, I don't know if ember-power-calendar-luxon experiences the same and may need similar treatment.

jonnygreen avatar Sep 17 '20 15:09 jonnygreen

On reflection, my comment above is not a good solution as timezones that are behind UTC would end up with a date object that if interpreted as local time, would be a day early. So big backwards compatibility issues. Whoops 🤦.

It needs something though - I think @fran-worley's approach of being able to configure PowerCalendar in UTC mode is a good one. In the meantime, we're implementing a wrapper that massages the date object to produce the date we expect in UTC.

jonnygreen avatar Sep 21 '20 16:09 jonnygreen