Skip to content

Commit 74c0be3

Browse files
committed
Store external storage index in time zones
1 parent 2e0c296 commit 74c0be3

File tree

6 files changed

+93
-27
lines changed

6 files changed

+93
-27
lines changed

src/TimeZones.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ include("indexable_generator.jl")
5555

5656
include("class.jl")
5757
include("utcoffset.jl")
58+
include("external.jl")
5859
include(joinpath("types", "timezone.jl"))
5960
include(joinpath("types", "fixedtimezone.jl"))
6061
include(joinpath("types", "variabletimezone.jl"))

src/external.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
struct ExternalField{T}
2+
table::Dict{T,Int}
3+
data::Vector{T}
4+
end
5+
6+
ExternalField{T}() where T = ExternalField{T}(Dict{T,Int}(), Vector{T}())
7+
8+
function add!(x::ExternalField{T}, val::T) where T
9+
get!(x.table, val) do
10+
push!(x.data, val)
11+
lastindex(x.data)
12+
end
13+
end
14+
15+
Base.getindex(x::ExternalField, i::Int) = x.data[i]

src/types/fixedtimezone.jl

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,20 @@ const FIXED_TIME_ZONE_REGEX = r"""
2929
3030
A `TimeZone` with a constant offset for all of time.
3131
"""
32-
struct FixedTimeZone <: TimeZone
32+
mutable struct FixedTimeZone <: TimeZone
3333
name::String
3434
offset::UTCOffset
35+
index::Int
36+
37+
function FixedTimeZone(name::String, utc_offset::UTCOffset)
38+
tz = new(name, utc_offset)
39+
tz.index = add!(_TIME_ZONES, tz)
40+
return tz
41+
end
42+
end
43+
44+
function FixedTimeZone(name::AbstractString, utc_offset::UTCOffset)
45+
FixedTimeZone(convert(String, name), utc_offset)
3546
end
3647

3748
"""
@@ -48,6 +59,21 @@ function FixedTimeZone(name::AbstractString, utc_offset::Second, dst_offset::Sec
4859
FixedTimeZone(name, UTCOffset(utc_offset, dst_offset))
4960
end
5061

62+
# Overload serialization to ensure that `FixedTimeZone` serialization doesn't transfer
63+
# state information which is specific to the current Julia process.
64+
function Serialization.serialize(s::AbstractSerializer, tz::FixedTimeZone)
65+
Serialization.serialize_type(s, typeof(tz))
66+
serialize(s, tz.name)
67+
serialize(s, tz.offset)
68+
end
69+
70+
function Serialization.deserialize(s::AbstractSerializer, ::Type{FixedTimeZone})
71+
name = deserialize(s)
72+
offset = deserialize(s)
73+
74+
return FixedTimeZone(name, offset)
75+
end
76+
5177
# https://en.wikipedia.org/wiki/ISO_8601#Coordinated_Universal_Time_(UTC)
5278
const UTC_ZERO = FixedTimeZone("Z", 0)
5379

@@ -95,3 +121,17 @@ end
95121

96122
name(tz::FixedTimeZone) = tz.name
97123
rename(tz::FixedTimeZone, name::AbstractString) = FixedTimeZone(name, tz.offset)
124+
125+
function Base.:(==)(a::FixedTimeZone, b::FixedTimeZone)
126+
return a.name == b.name && a.offset == b.offset
127+
end
128+
129+
function Base.hash(tz::FixedTimeZone, h::UInt)
130+
h = hash(:timezone, h)
131+
h = hash(tz.name, h)
132+
return h
133+
end
134+
135+
function Base.isequal(a::FixedTimeZone, b::FixedTimeZone)
136+
return isequal(a.name, b.name) && isequal(a.offset, b.offset)
137+
end

src/types/timezone.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const TIME_ZONE_CACHE = Dict{String,Tuple{TimeZone,Class}}()
2+
const _TIME_ZONES = ExternalField{TimeZone}()
23

34
"""
45
TimeZone(str::AbstractString) -> TimeZone

src/types/variabletimezone.jl

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,49 @@ end
55

66
Base.isless(a::Transition, b::Transition) = isless(a.utc_datetime, b.utc_datetime)
77

8+
function Base.:(==)(a::Transition, b::Transition)
9+
return a.utc_datetime == b.utc_datetime && a.zone == b.zone
10+
end
11+
12+
function Base.isequal(a::Transition, b::Transition)
13+
return isequal(a.utc_datetime, b.utc_datetime) && isequal(a.zone, b.zone)
14+
end
15+
816
"""
917
VariableTimeZone
1018
1119
A `TimeZone` with an offset that changes over time.
1220
"""
13-
struct VariableTimeZone <: TimeZone
21+
mutable struct VariableTimeZone <: TimeZone
1422
name::String
1523
transitions::Vector{Transition}
1624
cutoff::Union{DateTime,Nothing}
25+
index::Int
1726

1827
function VariableTimeZone(name::AbstractString, transitions::Vector{Transition}, cutoff::Union{DateTime,Nothing}=nothing)
19-
new(name, transitions, cutoff)
28+
tz = new(name, transitions, cutoff)
29+
tz.index = add!(_TIME_ZONES, tz)
30+
return tz
2031
end
2132
end
2233

34+
# Overload serialization to ensure that `VariableTimeZone` serialization doesn't transfer
35+
# state information which is specific to the current Julia process.
36+
function Serialization.serialize(s::AbstractSerializer, tz::VariableTimeZone)
37+
Serialization.serialize_type(s, typeof(tz))
38+
serialize(s, tz.name)
39+
serialize(s, tz.transitions)
40+
serialize(s, tz.cutoff)
41+
end
42+
43+
function Serialization.deserialize(s::AbstractSerializer, ::Type{VariableTimeZone})
44+
name = deserialize(s)
45+
transitions = deserialize(s)
46+
cutoff = deserialize(s)
47+
48+
return VariableTimeZone(name, transitions, cutoff)
49+
end
50+
2351
name(tz::VariableTimeZone) = tz.name
2452

2553
function rename(tz::VariableTimeZone, name::AbstractString)

src/types/zoneddatetime.jl

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
using Dates: AbstractDateTime, argerror, validargs
22

3-
# Stores non-bits data outside of the `ZonedDateTime` structure
4-
const _ZDT_FIELDS = Vector{Tuple{TimeZone,FixedTimeZone}}()
5-
6-
# Stored indexes into `_ZDT_FIELDS`
7-
const _TZ_INDEX = Dict{Tuple{TimeZone,FixedTimeZone},Int}()
8-
9-
103
# """
114
# ZonedDateTime
125

@@ -16,38 +9,26 @@ const _TZ_INDEX = Dict{Tuple{TimeZone,FixedTimeZone},Int}()
169
struct ZonedDateTime <: AbstractDateTime
1710
utc_datetime::DateTime
1811
_tz_index::Int
12+
_zone_index::Int
1913

2014
function ZonedDateTime(utc_datetime::DateTime, timezone::TimeZone, zone::FixedTimeZone)
21-
return new(utc_datetime, _tz_index(timezone, zone))
15+
return new(utc_datetime, timezone.index, zone.index)
2216
end
2317

2418
function ZonedDateTime(utc_datetime::DateTime, timezone::VariableTimeZone, zone::FixedTimeZone)
2519
if timezone.cutoff !== nothing && utc_datetime >= timezone.cutoff
2620
throw(UnhandledTimeError(timezone))
2721
end
2822

29-
return new(utc_datetime, _tz_index(timezone, zone))
30-
end
31-
end
32-
33-
function _tz_index(tz::TimeZone, zone::FixedTimeZone)
34-
t = (tz, zone)
35-
36-
i = get!(_TZ_INDEX, t) do
37-
push!(_ZDT_FIELDS, t)
38-
lastindex(_ZDT_FIELDS)
23+
return new(utc_datetime, timezone.index, zone.index)
3924
end
40-
41-
return i
4225
end
4326

4427
function Base.getproperty(zdt::ZonedDateTime, field::Symbol)
4528
if field === :zone
46-
tz, zone = _ZDT_FIELDS[getfield(zdt, :_tz_index)]
47-
return zone
29+
return _TIME_ZONES[getfield(zdt, :_zone_index)]::FixedTimeZone
4830
elseif field === :timezone
49-
tz, zone = _ZDT_FIELDS[getfield(zdt, :_tz_index)]
50-
return tz
31+
return _TIME_ZONES[getfield(zdt, :_tz_index)]::TimeZone
5132
else
5233
return getfield(zdt, field)
5334
end

0 commit comments

Comments
 (0)