TimeZones.jl icon indicating copy to clipboard operation
TimeZones.jl copied to clipboard

Parameterize `ZonedDateTime` by `TimeZone` instance

Open omus opened this issue 5 years ago • 5 comments

Allows for enforcing that a Vector contains ZonedDateTimes all using the same TimeZone. This idea has been floated around before so I made this issue to centralize the conversation.

omus avatar Dec 21 '20 19:12 omus

Requested in: https://github.com/JuliaData/Arrow.jl/pull/50#issue-509313802

omus avatar Dec 21 '20 19:12 omus

For it to be parametric on the value of the the timezone (ratehr than the type of the timezone) would require that the TimeZone type isbits. Which is #271

oxinabox avatar Apr 09 '21 11:04 oxinabox

For it to be parametric on the value of the the timezone (ratehr than the type of the timezone) would require that the TimeZone type isbits. Which is #271

So this issue is referring to having something like ZonedDateTime{tz"America/Winnipeg"}. Effectively this would mean having a separate type for each time zone making each time zone a singleton. The advantage here is you can use type constraints to enforce all elements of an array to be the same time zone and excise storing that information in the struct. The downside however additional overhead on Julia's type system with introducing 300+ types; complications with custom time zones and possibly serialization

omus avatar Apr 30 '21 03:04 omus

An idea I'm experimenting with is using an intermediate type for the time zone. The advantage of such an approach is that it allows us to use a time zone as a type parameter without requiring the type storing the time zone information to have to be isbits which can be quite challenging.

Essentially this could work like:

using Dates: DateTime
using TimeZones: TimeZones, TimeZone, @tz_str

struct TZ{name} end
TZ{name}() where {name} = TimeZone(String(name))

macro TZ_str(name)
    :(TZ{$(Expr(:quote, Symbol(name)))})
end

struct ZonedDateTime{TZ}
    utc_instant::DateTime
    # zone::FixedTimeZone
end

function ZonedDateTime(dt::DateTime, tz::TimeZone)
    tz_type = TZ{Symbol(tz.name)}
    ZonedDateTime{tz_type}(dt)
end
TimeZones.timezone(::ZonedDateTime{TZ}) where TZ = TZ()
julia> ZonedDateTime{TZ"America/Winnipeg"}(DateTime(2021))
ZonedDateTime{TZ{Symbol("America/Winnipeg")}}(DateTime("2021-01-01T00:00:00"))

julia> ZonedDateTime(DateTime(2021), tz"America/Winnipeg")
ZonedDateTime{TZ{Symbol("America/Winnipeg")}}(DateTime("2021-01-01T00:00:00"))

There's even some room for optimization with this approach as TZ{name}() where {name} can be optimized with specialized methods such as TZ{Symbol("...")} = tz"...":

using TimeZones

struct TZ1{name} end
struct TZ2{name} end

macro TZ1_str(name)
    :(TZ1{$(Expr(:quote, Symbol(name)))})
end
macro TZ2_str(name)
    :(TZ2{$(Expr(:quote, Symbol(name)))})
end

TZ1{name}() where {name} = TimeZone(String(name))
TZ2"America/Winnipeg"() = tz"America/Winnipeg"
julia> @btime TZ1"America/Winnipeg"()
  84.699 ns (3 allocations: 112 bytes)
America/Winnipeg (UTC-6/UTC-5)

julia> @btime TZ2"America/Winnipeg"()
  1.563 ns (0 allocations: 0 bytes)
America/Winnipeg (UTC-6/UTC-5)

One thing I'm not loving about this approach is how the type is displayed but overall that's pretty minor. I need to do some additional experimentation yet.

omus avatar May 18 '21 04:05 omus

Trying to get some activity on custom type printing: https://github.com/JuliaLang/julia/issues/24195#issuecomment-901385487

omus avatar Aug 18 '21 19:08 omus