Parameterize `ZonedDateTime` by `TimeZone` instance
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.
Requested in: https://github.com/JuliaData/Arrow.jl/pull/50#issue-509313802
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
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
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.
Trying to get some activity on custom type printing: https://github.com/JuliaLang/julia/issues/24195#issuecomment-901385487