justinmimbs / timezone-data

An Elm package containing time zone data from the IANA Time Zone Database
https://package.elm-lang.org/packages/justinmimbs/timezone-data/latest/
BSD 3-Clause "New" or "Revised" License
30 stars 5 forks source link

Wrong daylight savings time "switch" for Oslo timezone #1

Closed robinheghan closed 6 years ago

robinheghan commented 6 years ago

First off, great library!

We currently have a bug where time zone information seems a bit wrong. It seems that times goes away from time light savings on Sunday at 01:00 am. However, in Norway we do this switch at 03:00 am on sunday.

We use this library in a travel planer for trains, so currently people are seeing travel times like "00:04 -> 00:18" when it should be "00:04 -> 01:18"

justinmimbs commented 6 years ago

Thanks, Robin!

That sounds like a cool app! Glad to hear this library is being used for that.

Do you have concrete examples of UTC times and time zones that don't show as expected?

Watch out: there is an error in elm/time that gives the wrong hour on the minute of a transition time, but your example times were not on the transition time, so that error wouldn't affect them.

Walking through it, I couldn't find a discrepancy:

EU switches back to standard time on Sunday at 01:00 UTC. Since Norway is currently UTC+02 (i.e. UTC+01 + 1 hour savings), that would be 03:00 local time, as you said.

Watch out: since you'll have two different hours on Sunday morning with clock times of 02:xx, there can, for example, be 74 minutes between local times of 02:04 and 02:18.

The zone generated by TimeZone.europe__oslo () looks as expected; it says (reading from right to left) the current offset is +120 minutes, and at 25678140 minutes past the Unix epoch, the offset will be +60 minutes.

... { offset = 60, start = 25678140 }, { offset = 120, ...

We can verify that "25678140 minutes" is Sunday at 01:00 UTC in a JS console:

new Date(25678140 * 60000).toISOString()
"2018-10-28T01:00:00.000Z"

Please let me know if you have a specific example, or if it was one of the things to watch out for above.

Thanks,

Justin

robinheghan commented 6 years ago

Hmm...

This could just be due to us having a stupid hack due to how our backend works. So this might not turn out to be a big in this library, but with the way we handle times. Feel free to close this issue, but if you have an idea on how we can fix things, I would love to hear from you either way.

So, our problem is that our backend returns ISO8601 strings without time zone information. Like: "29-10-2018T00:04:00". The strings will always be in Norwegian time. This isn't something backend is that excited about changing (like making sure they're always UTC time, or adding the time zone offset) because of backwards compatibility, and because it's a huge change across many backend services.

So what we do, is parse the string as if it was UTC using rtfeldman/iso8601-date-strings, then use this timezone library to figure out the UTC offset i minutes, then subtracting that offset from our parsed string to get "proper" UTC time.

Now that we have UTC time, we use this timezone-data library to display Norwegian time in our views.

I guess our UTC conversion hack breaks down when transitioning from/to daylight savings. It works great in other scenarios though.

justinmimbs commented 6 years ago

Oh, that is interesting. It sounds like the strings are always in Norway local time? That is, a mix of standard and DST offsets? If so, then you'll always have ambiguous times during the "fall back" transitions. If you get the string "2018-10-28T02:00" then you can't know if it should be the first "02:00" (i.e. UTC+02) or the second (UTC+01). There's no way around that ambiguity. :\

robinheghan commented 6 years ago

I see. Well, thanks for your help :)

justinmimbs commented 6 years ago

Sure thing. :) As an aside, while you're stuck with local strings from the server, you could have Time.Extra.partsToPosix handle the conversion from local to universal time.

localStringToPosix : Zone -> String -> Result (List DeadEnd) Posix
localStringToPosix zone string =
    (string ++ "Z")
        |> Iso8601.toTime
        |> Result.map
            (Time.Extra.posixToParts Time.utc
                >> Time.Extra.partsToPosix zone
            )

When given ambiguous time parts, like this Sunday at 2:04 in Norway, partsToPosix returns the time closer to UTC. So it would return the concrete time at 2:04 UTC+01 instead of the alternative, at 2:04 UTC+02.