JuliaTime / TimeZones.jl

IANA time zone database access for the Julia programming language
Other
86 stars 51 forks source link

Multiple distinct UTCs: `Dates.UTC()`, `TimeZone("UTC")`, `TimeZone("Z")` #452

Open tpgillam opened 7 months ago

tpgillam commented 7 months ago

The Dates stdlib defines struct UTC <: TimeZone end, and it doesn't play nicely with ZonedDateTime. I was surprised to find this, partly since TimeZones.jl re-exports the UTC symbol.

For example:

using TimeZones

UTC() == tz"UTC"  # false

ZonedDateTime(2020, 1, 1, tz"UTC")  # 2020-01-01T00:00:00+00:00

ZonedDateTime(2020, 1, 1, UTC())  # ERROR
Stack trace... ``` ERROR: MethodError: no method matching ZonedDateTime(::DateTime, ::UTC) Closest candidates are: ZonedDateTime(::DateTime, ::TimeZone, ::FixedTimeZone) @ TimeZones ~/.julia/dev/TimeZones/src/types/zoneddatetime.jl:14 ZonedDateTime(::Union{Period, TimeZone}...) @ TimeZones ~/.julia/dev/TimeZones/src/types/zoneddatetime.jl:136 ZonedDateTime(::Integer, ::TimeZone) @ TimeZones none:0 ... Stacktrace: [1] ZonedDateTime(y::Int64, m::Int64, d::Int64, h::Int64, mi::Int64, s::Int64, ms::Int64, tz::UTC) @ TimeZones ~/.julia/dev/TimeZones/src/types/zoneddatetime.jl:121 [2] ZonedDateTime(y::Int64, m::Int64, d::Int64, tz::UTC) @ TimeZones ./none:0 [3] top-level scope @ REPL[33]:1```

Maybe it would be nice if tz"UTC" === UTC()? Primarily because, semantically, I think they are intended to be the same thing.

aside: from some poking in src/types/fixedtimezone.jl it seems that tz"Z" is given special treatment. It is also distinct from tz"UTC". But then the following is a little surprising to me:

julia> parse(ZonedDateTime, "2020-01-01T00:00:00.000+00:00").timezone
UTC

julia> parse(ZonedDateTime, "2020-01-01T00:00:00.000Z").timezone
Z (UTC+0)

((the latter is also nearly twice as fast due to optimisations for Z... but this is even more off-topic)) Not that we should necessarily follow the behaviour of other languages, but Python would parse both the strings above to tz-aware datetimes with the identical 'UTC' timezone. Perhaps more importantly, "Z" is not in the IANA database, and is just a notation in ISO8601 to mean UTC as far as I can tell?

Apart from being a bit tidier, rationalising the standard ways of defining "UTC" to give a zero-size struct could be good for performance -- especially if we went down the route of parameterising ZonedDateTime, we could then end up with e.g. sizeof(ZonedDateTime{UTC}) == sizeof(DateTime), which would be great!

omus commented 1 month ago

I think we should support UTC in TimeZones.jl but I'm doubtful we can make UTC === tz"UTC" but we should at least make them ==.