Skip to content

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

@tpgillam

Description

@tpgillam

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions