Natixar / natixar-frontend

The static front end of the Natixar SaaS platform
0 stars 5 forks source link

All the timestampToX Functions Fail to Take the Timezone into Account #88

Closed lepeuvedic-natixar closed 1 month ago

lepeuvedic-natixar commented 1 month ago

https://github.com/Natixar/natixar-frontend/blob/ead8cd58e471085638f3ef84d520788ce85e8a27/src/data/domain/transformers/TimeTransformers.ts#L44

Problem

Converting a timestamp, which is an absolute time index based on UTC time, into a year, requires taking a timezone into account. On Jan 1st, the new year comes first on the anti-Greenwich line in the middle of the Pacific Ocean, then sweeps across the surface of the Earth one time zone at a time. A given instant can be in one year or the next, depending on the time zone. For example, timestamp 0, which is widely know to mean Jan 1st 1970 at 00h00 UTC, falls in 1969 in the early evening of Dec 31st in New-York, USA.

The backend communicates using unambiguous ISO8601 date time strings including the time zone specification. Currently the time zone specification does not match the locale, because we are in May and daylight savings time is applicable, putting us in western Europe, in a +02:00 time zone. The data takes into account a month that is one hour shorter and a month that is one hour longer to accomodate for the transitions into and out of daylight savings time.

Steps to Reproduce

  1. Authenticate if needed and enter the Dashboard
  2. Look at the first date in the bar chart: it is in December 2021 when the data starts on Jan 1st 2022 at 00:00 GMT+1 (2022-01-01T00:00:00+0100) . In addition the month of March is missing in 2022 and in 2023, a fact which could be linked to an offset of one month in the periods (starting in Dec rather than Jan).

Expected Behavior

Data is returned by the back-end in the original time zone. That is, if the user lives in Europe/Paris time zone (which applies daylight savings time) the time zone offset is +02:00 in the summer when DST is in effect or +01:00 in the winter. Therefore Jan 1st, a year-aligned date, will always be represented with +01:00 .

The format() function in date-fns always uses the user's current time zone offset. When the user converts back a timestamp representing 2022-01-01T00:00:00+01:00 while DST is in effect, it is the same as converting the timestamp on Jan 1st but when living in Europe/London. Given there is a 1-hour difference between London and Paris, the same timestamp represents 2021-12-31T23:00:00+02:00 . The date-fns library fails to properly take into account the time zone offset that was in effect at the date being converted in the current geographic time zone.

Solution: convert all these functions to use Luxon and pass a suitable third parameter representing the time zone of the user. The back-end requires that the same time zone offset is used for the start and end of a time range, and will always return data with the same alignment. DST affects the alignment of all the time scales longer than an hour. Practically it means that days, weeks, months and quarters don't have the same duration in UTC and in a time zone which applies DST. One a year, one of these is 1 hr shorter (in spring) and one is 1 hr longer (in autumn), and this can only be reflected in the step field of the /data/ranges endpoint response, if the back-end knows the actual time zone.

The v1 API will include an optional tz parameter which will trigger proper DST application if supplied and will replace the time zone offset in the start and end ISO8601 datetime strings. The front-end will transparently pass the user's time zone like "Europe/Paris". When tz is not present, DST will be ignored and pure time zone offset will be treated as applicable year-long. When tz is present, the time zone offsets must be omitted and the date times will be interpreted according to the time zone, including DST influence if applicable.

The endpoint response format does not need to be modified, and will still indicate time zone offsets only, but they may vary if the DST came in effect or went out during a period (start and end of a quarter, for instance). The step value or array will also be affected to include a day of 23 or 25 hours.

https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

lepeuvedic commented 1 month ago

First step is to run everything in UTC. This means that a date entered by the used on the date range picker means 00:00 UTC for the start and 24:00 UTC for the end.