diff --git a/Project.toml b/Project.toml index aabb70883..715d978b9 100644 --- a/Project.toml +++ b/Project.toml @@ -11,12 +11,14 @@ Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" +ShortStrings = "63221d1c-8677-4ff0-9126-0ff0817b4975" Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" [compat] EzXML = "0.9.1, 1" Mocking = "0.7" RecipesBase = "0.7, 0.8, 1" +ShortStrings = "0.3.7" julia = "1" [extras] diff --git a/dev/ShortStrings b/dev/ShortStrings new file mode 160000 index 000000000..65ca2364a --- /dev/null +++ b/dev/ShortStrings @@ -0,0 +1 @@ +Subproject commit 65ca2364af105fc2647befe0b73ca3ecdd8c9f7a diff --git a/src/TimeZones.jl b/src/TimeZones.jl index 754cecf58..dba561b68 100644 --- a/src/TimeZones.jl +++ b/src/TimeZones.jl @@ -2,8 +2,10 @@ module TimeZones using Dates using Printf +using ShortStrings using Serialization using RecipesBase: RecipesBase, @recipe +using ShortStrings: ShortString15 using Unicode import Dates: TimeZone, UTC @@ -55,6 +57,7 @@ include("indexable_generator.jl") include("class.jl") include("utcoffset.jl") +include(joinpath("types", "name.jl")) include(joinpath("types", "timezone.jl")) include(joinpath("types", "fixedtimezone.jl")) include(joinpath("types", "variabletimezone.jl")) diff --git a/src/arithmetic.jl b/src/arithmetic.jl index e1991b711..9438ca19d 100644 --- a/src/arithmetic.jl +++ b/src/arithmetic.jl @@ -17,7 +17,7 @@ function Base.:(-)(zdt::ZonedDateTime, p::TimePeriod) return ZonedDateTime(DateTime(zdt, UTC) - p, timezone(zdt); from_utc=true) end -function broadcasted(::typeof(+), r::StepRange{ZonedDateTime}, p::DatePeriod) +function broadcasted(::typeof(+), r::StepRange{<:ZonedDateTime}, p::DatePeriod) start, step, stop = first(r), Base.step(r), last(r) # Since the local time + period can result in an invalid local datetime when working with @@ -41,10 +41,10 @@ function broadcasted(::typeof(+), r::StepRange{ZonedDateTime}, p::DatePeriod) return StepRange(start, step, stop) end -function broadcasted(::typeof(+), r::StepRange{ZonedDateTime}, p::TimePeriod) +function broadcasted(::typeof(+), r::StepRange{<:ZonedDateTime}, p::TimePeriod) return StepRange(r.start + p, r.step, r.stop + p) end -broadcasted(::typeof(+), p::Period, r::StepRange{ZonedDateTime}) = broadcasted(+, r, p) -broadcasted(::typeof(-), r::StepRange{ZonedDateTime}, p::Period) = broadcasted(+, r, -p) -broadcasted(::typeof(-), p::Period, r::StepRange{ZonedDateTime}) = broadcasted(-, r, p) +broadcasted(::typeof(+), p::Period, r::StepRange{<:ZonedDateTime}) = broadcasted(+, r, p) +broadcasted(::typeof(-), r::StepRange{<:ZonedDateTime}, p::Period) = broadcasted(+, r, -p) +broadcasted(::typeof(-), p::Period, r::StepRange{<:ZonedDateTime}) = broadcasted(-, r, p) diff --git a/src/io.jl b/src/io.jl index 7df072d8a..8dbc650aa 100644 --- a/src/io.jl +++ b/src/io.jl @@ -73,17 +73,17 @@ function Base.show(io::IO, tz::VariableTimeZone) # Compact printing of a custom time zone which is non-constructable elseif get(io, :compact, false) - print(io, VariableTimeZone, "(") - show(io, tz.name) - print(io, ", ...)") + print(io, VariableTimeZone, "(\"") + print(io, tz.name) + print(io, "\", ...)") # Verbose printing which should print a fully constructable `VariableTimeZone`. else # Force `:compact => false` to make the force the transition vector printing into # long form. - print(io, VariableTimeZone, "(") - show(io, tz.name) - print(io, ", ") + print(io, VariableTimeZone, "(\"") + print(io, tz.name) + print(io, "\", ") show(IOContext(io, :compact => false), tz.transitions) print(io, ", ") show(io, tz.cutoff) @@ -128,7 +128,7 @@ Base.show(io::IO, ::MIME"text/plain", zdt::ZonedDateTime) = print(io, zdt) # https://github.com/JuliaLang/julia/pull/33290 if VERSION >= v"1.5.0-DEV.224" - Base.typeinfo_implicit(::Type{ZonedDateTime}) = true + Base.typeinfo_implicit(::Type{<:ZonedDateTime}) = true end # Use compact printing on certain element types for Julia versions before: diff --git a/src/types/fixedtimezone.jl b/src/types/fixedtimezone.jl index 1d349ca07..a6bd2a181 100644 --- a/src/types/fixedtimezone.jl +++ b/src/types/fixedtimezone.jl @@ -1,3 +1,7 @@ +# Ideally would always use ShortString15, but it's `hash` is broken on 32-bit systems. +# https://github.com/JuliaString/MurmurHash3.jl/issues/12 +const FixedTimeZoneName = Int === Int64 ? ShortString15 : String + const FIXED_TIME_ZONE_REGEX = r""" ^(?| Z @@ -30,7 +34,7 @@ const FIXED_TIME_ZONE_REGEX = r""" A `TimeZone` with a constant offset for all of time. """ struct FixedTimeZone <: TimeZone - name::String + name::FixedTimeZoneName offset::UTCOffset end @@ -72,7 +76,7 @@ UTC+15:45:21 function FixedTimeZone(s::AbstractString) s == "Z" && return UTC_ZERO - m = match(FIXED_TIME_ZONE_REGEX, s) + m = match(FIXED_TIME_ZONE_REGEX, String(s)) m === nothing && throw(ArgumentError("Unrecognized time zone: $s")) coefficient = m[:sign] == "-" ? -1 : 1 diff --git a/src/types/name.jl b/src/types/name.jl new file mode 100644 index 000000000..58ccfc758 --- /dev/null +++ b/src/types/name.jl @@ -0,0 +1,59 @@ +struct SName + region::ShortString15 + locality1::ShortString15 + locality2::ShortString15 +end + +function Base.print(io::IO, name::SName) + print(io, name.region) + if !isempty(name.locality1) + print(io,"/", name.locality1) + if !isempty(name.locality2) + print(io,"/", name.locality2) + end + end +end + +Base.convert(::Type{String}, name::SName) = string(name) +function Base.convert(::Type{SName}, str::AbstractString) + name = try_convert(SName, str) + if name isa Nothing + throw(DomainError(str, "Timezone must have 3 or fewer parts, all with length < 16")) + end + return name +end + +try_convert(::Type{SName}, name::SName) = name +try_convert(::Type{String}, name::String) = name +function try_convert(::Type{SName}, str::AbstractString) + parts = split(str, "/") + (length(parts) <= 3) || return nothing + all(length(part)<16 for part in parts) || return nothing + return if length(parts) == 3 + SName(parts[1], parts[2], parts[3]) + elseif length(parts) == 2 + SName(parts[1], parts[2], ss15"") + else + SName(parts[1], ss15"", ss15"") + end +end + + +Base.isempty(name::SName) = isempty(name.region) # region being empty implies all empty + +name_parts(str::AbstractString) = split(str, "/") +function name_parts(name::SName) + # TODO this could be faster by returning an iterator but not really performance critial + parts = [name.region] + if !isempty(name.locality1) + push!(parts, name.locality1) + if !isempty(name.locality2) + push!(parts, name.locality2) + end + end + return parts +end + +# Short strings are broken on 32bit: +# TODO: https://github.com/JuliaString/MurmurHash3.jl/issues/12 +const Name = Int === Int32 ? String : SName diff --git a/src/types/timezone.jl b/src/types/timezone.jl index 7e8289b1f..60a0ea2c7 100644 --- a/src/types/timezone.jl +++ b/src/types/timezone.jl @@ -1,4 +1,4 @@ -const TIME_ZONE_CACHE = Dict{String,Tuple{TimeZone,Class}}() +const TIME_ZONE_CACHE = Dict{Name,Tuple{TimeZone,Class}}() """ TimeZone(str::AbstractString) -> TimeZone @@ -41,11 +41,15 @@ US/Pacific (UTC-8/UTC-7) TimeZone(::AbstractString, ::Class) function TimeZone(str::AbstractString, mask::Class=Class(:DEFAULT)) + return TimeZone(convert(Name, str), mask) +end + +function TimeZone(name::Name, mask::Class=Class(:DEFAULT)) + str = string(name) # Note: If the class `mask` does not match the time zone we'll still load the # information into the cache to ensure the result is consistent. - tz, class = get!(TIME_ZONE_CACHE, str) do - tz_path = joinpath(TZData.COMPILED_DIR, split(str, "/")...) - + tz, class = get!(TIME_ZONE_CACHE, name) do + tz_path = joinpath(TZData.COMPILED_DIR, name_parts(name)...) if isfile(tz_path) open(deserialize, tz_path, "r") elseif occursin(FIXED_TIME_ZONE_REGEX, str) @@ -91,19 +95,21 @@ end Check whether a string is a valid for constructing a `TimeZone` with the provided `mask`. """ -function istimezone(str::AbstractString, mask::Class=Class(:DEFAULT)) +function istimezone(str::Union{AbstractString, Name}, mask::Class=Class(:DEFAULT)) # Start by performing quick FIXED class test - if mask & Class(:FIXED) != Class(:NONE) && occursin(FIXED_TIME_ZONE_REGEX, str) + if mask & Class(:FIXED) != Class(:NONE) && occursin(FIXED_TIME_ZONE_REGEX, string(str)) return true end + name = try_convert(Name, str) + name isa Nothing && return false # Perform more expensive checks against pre-compiled time zones tz, class = get(TIME_ZONE_CACHE, str) do - tz_path = joinpath(TZData.COMPILED_DIR, split(str, "/")...) + tz_path = joinpath(TZData.COMPILED_DIR, name_parts(name)...) if isfile(tz_path) # Cache the data since we're already performing the deserialization - TIME_ZONE_CACHE[str] = open(deserialize, tz_path, "r") + TIME_ZONE_CACHE[name] = open(deserialize, tz_path, "r") else nothing, Class(:NONE) end diff --git a/src/types/variabletimezone.jl b/src/types/variabletimezone.jl index 35b2b89b6..842d615b0 100644 --- a/src/types/variabletimezone.jl +++ b/src/types/variabletimezone.jl @@ -11,13 +11,12 @@ Base.isless(a::Transition, b::Transition) = isless(a.utc_datetime, b.utc_datetim A `TimeZone` with an offset that changes over time. """ struct VariableTimeZone <: TimeZone - name::String + name::Name transitions::Vector{Transition} cutoff::Union{DateTime,Nothing} - - function VariableTimeZone(name::AbstractString, transitions::Vector{Transition}, cutoff::Union{DateTime,Nothing}=nothing) - new(name, transitions, cutoff) - end +end +function VariableTimeZone(name::AbstractString, transitions::Vector{Transition}) + VariableTimeZone(name, transitions, nothing) end name(tz::VariableTimeZone) = tz.name diff --git a/src/types/zoneddatetime.jl b/src/types/zoneddatetime.jl index 2c832e8d9..378dd8cd6 100644 --- a/src/types/zoneddatetime.jl +++ b/src/types/zoneddatetime.jl @@ -6,22 +6,20 @@ using Dates: AbstractDateTime, argerror, validargs # A `DateTime` that includes `TimeZone` information. # """ -struct ZonedDateTime <: AbstractDateTime +struct ZonedDateTime{T<:TimeZone} <: AbstractDateTime utc_datetime::DateTime - timezone::TimeZone + timezone::T zone::FixedTimeZone # The current zone for the utc_datetime. +end - function ZonedDateTime(utc_datetime::DateTime, timezone::TimeZone, zone::FixedTimeZone) - return new(utc_datetime, timezone, zone) +function ZonedDateTime( + utc_datetime::DateTime, timezone::VariableTimeZone, zone::FixedTimeZone +) + if timezone.cutoff !== nothing && utc_datetime >= timezone.cutoff + throw(UnhandledTimeError(timezone)) end - function ZonedDateTime(utc_datetime::DateTime, timezone::VariableTimeZone, zone::FixedTimeZone) - if timezone.cutoff !== nothing && utc_datetime >= timezone.cutoff - throw(UnhandledTimeError(timezone)) - end - - return new(utc_datetime, timezone, zone) - end + return ZonedDateTime{VariableTimeZone}(utc_datetime, timezone, zone) end """ @@ -181,11 +179,11 @@ function Base.hash(zdt::ZonedDateTime, h::UInt) return h end -Base.typemin(::Type{ZonedDateTime}) = ZonedDateTime(typemin(DateTime), utc_tz; from_utc=true) -Base.typemax(::Type{ZonedDateTime}) = ZonedDateTime(typemax(DateTime), utc_tz; from_utc=true) +Base.typemin(::Type{<:ZonedDateTime}) = ZonedDateTime(typemin(DateTime), utc_tz; from_utc=true) +Base.typemax(::Type{<:ZonedDateTime}) = ZonedDateTime(typemax(DateTime), utc_tz; from_utc=true) # Note: The `validargs` function is as part of the Dates parsing interface. -function Dates.validargs(::Type{ZonedDateTime}, y::Int64, m::Union{Int64, Int32}, d::Int64, h::Int64, mi::Int64, s::Int64, ms::Int64, tz::AbstractString) +function Dates.validargs(::Type{<:ZonedDateTime}, y::Int64, m::Union{Int64, Int32}, d::Int64, h::Int64, mi::Int64, s::Int64, ms::Int64, tz::AbstractString) err = validargs(DateTime, y, Int64(m), d, h, mi, s, ms) err === nothing || return err istimezone(tz) || return argerror("TimeZone: \"$tz\" is not a recognized time zone") diff --git a/src/tzdata/compile.jl b/src/tzdata/compile.jl index ec4a29f70..03428f605 100644 --- a/src/tzdata/compile.jl +++ b/src/tzdata/compile.jl @@ -4,7 +4,7 @@ using Dates: parse_components using ...TimeZones: TIME_ZONE_CACHE using ...TimeZones: TimeZones, TimeZone, FixedTimeZone, VariableTimeZone, Transition, Class -using ...TimeZones: rename +using ...TimeZones: name_parts, rename, try_convert using ..TZData: TimeOffset, ZERO, MIN_GMT_OFFSET, MAX_GMT_OFFSET, MIN_SAVE, MAX_SAVE, ABS_DIFF_OFFSET @@ -697,7 +697,7 @@ function compile(tz_source::TZSource, dest_dir::AbstractString; kwargs...) empty!(TIME_ZONE_CACHE) for (tz, class) in results - parts = split(TimeZones.name(tz), '/') + parts = name_parts(TimeZones.name(tz)) tz_path = joinpath(dest_dir, parts...) tz_dir = dirname(tz_path) diff --git a/test/arithmetic.jl b/test/arithmetic.jl index 2c8f66aa7..13de497ae 100644 --- a/test/arithmetic.jl +++ b/test/arithmetic.jl @@ -55,7 +55,7 @@ spring_zdt = ZonedDateTime(spring, warsaw) # Arithmetic with a StepRange should always work even when the start/stop lands on # ambiguous or non-existent DateTimes. -@testset "StepRange{ZonedDateTime}" begin +@testset "StepRange{<:ZonedDateTime}" begin @testset "time-period" begin dt = DateTime(2015, 6, 1) @@ -71,7 +71,7 @@ spring_zdt = ZonedDateTime(spring, warsaw) ) @test results == expected @test length(results) == 2 - @test results isa StepRange{ZonedDateTime} + @test results isa StepRange{<:ZonedDateTime} end @testset "date-period" begin @@ -89,7 +89,7 @@ spring_zdt = ZonedDateTime(spring, warsaw) ) @test results == expected @test length(results) == 2 - @test results isa StepRange{ZonedDateTime} + @test results isa StepRange{<:ZonedDateTime} end @testset "ambiguous" begin diff --git a/test/interpret.jl b/test/interpret.jl index c946b18d7..144571390 100644 --- a/test/interpret.jl +++ b/test/interpret.jl @@ -125,7 +125,7 @@ long = VariableTimeZone("Test/LongGap", [ ]) # A time zone with an unnecessary transition that typically is hidden to the user -hidden = VariableTimeZone("Test/HiddenTransition", [ +hidden = VariableTimeZone("Test/Hidden", [ Transition(DateTime(1800,1,1,0), zone["T+1"]) Transition(DateTime(1900,1,1,0), zone["T+0"]) Transition(DateTime(1935,4,1,2), zone["T+1"]) # The hidden transition diff --git a/test/parse.jl b/test/parse.jl index 100aaebd8..7b8294442 100644 --- a/test/parse.jl +++ b/test/parse.jl @@ -327,7 +327,7 @@ end consistent_years = t -> year(t.utc_datetime) >= 2007 tz, i = _parsesub_tz("CST+6CDT+5,M3.2.0/2,M11.1.0/2") - @test tz.name == "CST/CDT" + @test string(tz.name) == "CST/CDT" @test tz.name != wpg.name @test filter(consistent_years, tz.transitions) == filter(consistent_years, wpg.transitions) @test tz.cutoff == wpg.cutoff diff --git a/test/types/fixedtimezone.jl b/test/types/fixedtimezone.jl index 94cae0ab4..774f67283 100644 --- a/test/types/fixedtimezone.jl +++ b/test/types/fixedtimezone.jl @@ -41,4 +41,14 @@ fixed_tz = FixedTimeZone("UTC") @test size(fixed_tz .== fixed_tz) == () end + + @testset "isbits" begin + # We are not using ShortStrings on 32-bit due to hash being broken on 32-bit. + # See https://github.com/JuliaString/MurmurHash3.jl/issues/12 + if Int === Int64 + @test isbits(FixedTimeZone("0123")) + else + @test_broken isbits(FixedTimeZone("0123")) + end + end end diff --git a/test/types/zoneddatetime.jl b/test/types/zoneddatetime.jl index e776e5bb9..748d99e1a 100644 --- a/test/types/zoneddatetime.jl +++ b/test/types/zoneddatetime.jl @@ -77,13 +77,13 @@ using Dates: Hour, Second, UTM, @dateformat_str utc_dt = DateTime(1916, 1, 31, 23) # Disambiguating parameters ignored when there is no ambiguity. - @test ZonedDateTime(local_dt, warsaw).zone.name == "CET" - @test ZonedDateTime(local_dt, warsaw, 0).zone.name == "CET" - @test ZonedDateTime(local_dt, warsaw, 1).zone.name == "CET" - @test ZonedDateTime(local_dt, warsaw, 2).zone.name == "CET" - @test ZonedDateTime(local_dt, warsaw, true).zone.name == "CET" - @test ZonedDateTime(local_dt, warsaw, false).zone.name == "CET" - @test ZonedDateTime(utc_dt, warsaw, from_utc=true).zone.name == "CET" + @test string(ZonedDateTime(local_dt, warsaw).zone.name) == "CET" + @test string(ZonedDateTime(local_dt, warsaw, 0).zone.name) == "CET" + @test string(ZonedDateTime(local_dt, warsaw, 1).zone.name) == "CET" + @test string(ZonedDateTime(local_dt, warsaw, 2).zone.name) == "CET" + @test string(ZonedDateTime(local_dt, warsaw, true).zone.name) == "CET" + @test string(ZonedDateTime(local_dt, warsaw, false).zone.name) == "CET" + @test string(ZonedDateTime(utc_dt, warsaw, from_utc=true).zone.name) == "CET" @test ZonedDateTime(local_dt, warsaw).utc_datetime == utc_dt @test ZonedDateTime(local_dt, warsaw, 0).utc_datetime == utc_dt @@ -99,13 +99,13 @@ using Dates: Hour, Second, UTM, @dateformat_str utc_dt = DateTime(1916, 5, 31, 22) # Disambiguating parameters ignored when there is no ambiguity. - @test ZonedDateTime(local_dt, warsaw).zone.name == "CEST" - @test ZonedDateTime(local_dt, warsaw, 0).zone.name == "CEST" - @test ZonedDateTime(local_dt, warsaw, 1).zone.name == "CEST" - @test ZonedDateTime(local_dt, warsaw, 2).zone.name == "CEST" - @test ZonedDateTime(local_dt, warsaw, true).zone.name == "CEST" - @test ZonedDateTime(local_dt, warsaw, false).zone.name == "CEST" - @test ZonedDateTime(utc_dt, warsaw, from_utc=true).zone.name == "CEST" + @test string(ZonedDateTime(local_dt, warsaw).zone.name) == "CEST" + @test string(ZonedDateTime(local_dt, warsaw, 0).zone.name) == "CEST" + @test string(ZonedDateTime(local_dt, warsaw, 1).zone.name) == "CEST" + @test string(ZonedDateTime(local_dt, warsaw, 2).zone.name) == "CEST" + @test string(ZonedDateTime(local_dt, warsaw, true).zone.name) == "CEST" + @test string(ZonedDateTime(local_dt, warsaw, false).zone.name) == "CEST" + @test string(ZonedDateTime(utc_dt, warsaw, from_utc=true).zone.name) == "CEST" @test ZonedDateTime(local_dt, warsaw).utc_datetime == utc_dt @test ZonedDateTime(local_dt, warsaw, 0).utc_datetime == utc_dt @@ -133,10 +133,10 @@ using Dates: Hour, Second, UTM, @dateformat_str @test_throws NonExistentTimeError ZonedDateTime(local_dts[2], warsaw, true) @test_throws NonExistentTimeError ZonedDateTime(local_dts[2], warsaw, false) - @test ZonedDateTime(local_dts[1], warsaw).zone.name == "CET" - @test ZonedDateTime(local_dts[3], warsaw).zone.name == "CEST" - @test ZonedDateTime(utc_dts[1], warsaw, from_utc=true).zone.name == "CET" - @test ZonedDateTime(utc_dts[2], warsaw, from_utc=true).zone.name == "CEST" + @test string(ZonedDateTime(local_dts[1], warsaw).zone.name) == "CET" + @test string(ZonedDateTime(local_dts[3], warsaw).zone.name) == "CEST" + @test string(ZonedDateTime(utc_dts[1], warsaw, from_utc=true).zone.name) == "CET" + @test string(ZonedDateTime(utc_dts[2], warsaw, from_utc=true).zone.name) == "CEST" @test ZonedDateTime(local_dts[1], warsaw).utc_datetime == utc_dts[1] @test ZonedDateTime(local_dts[3], warsaw).utc_datetime == utc_dts[2] @@ -151,12 +151,12 @@ using Dates: Hour, Second, UTM, @dateformat_str @test_throws AmbiguousTimeError ZonedDateTime(local_dt, warsaw) @test_throws AmbiguousTimeError ZonedDateTime(local_dt, warsaw, 0) - @test ZonedDateTime(local_dt, warsaw, 1).zone.name == "CEST" - @test ZonedDateTime(local_dt, warsaw, 2).zone.name == "CET" - @test ZonedDateTime(local_dt, warsaw, true).zone.name == "CEST" - @test ZonedDateTime(local_dt, warsaw, false).zone.name == "CET" - @test ZonedDateTime(utc_dts[1], warsaw, from_utc=true).zone.name == "CEST" - @test ZonedDateTime(utc_dts[2], warsaw, from_utc=true).zone.name == "CET" + @test string(ZonedDateTime(local_dt, warsaw, 1).zone.name) == "CEST" + @test string(ZonedDateTime(local_dt, warsaw, 2).zone.name) == "CET" + @test string(ZonedDateTime(local_dt, warsaw, true).zone.name) == "CEST" + @test string(ZonedDateTime(local_dt, warsaw, false).zone.name) == "CET" + @test string(ZonedDateTime(utc_dts[1], warsaw, from_utc=true).zone.name) == "CEST" + @test string(ZonedDateTime(utc_dts[2], warsaw, from_utc=true).zone.name) == "CET" @test ZonedDateTime(local_dt, warsaw, 1).utc_datetime == utc_dts[1] @test ZonedDateTime(local_dt, warsaw, 2).utc_datetime == utc_dts[2] @@ -172,12 +172,12 @@ using Dates: Hour, Second, UTM, @dateformat_str utc_dts = (DateTime(1922, 5, 31, 21), DateTime(1922, 5, 31, 22)) @test_throws AmbiguousTimeError ZonedDateTime(local_dt, warsaw) - @test ZonedDateTime(local_dt, warsaw, 1).zone.name == "EET" - @test ZonedDateTime(local_dt, warsaw, 2).zone.name == "CET" + @test string(ZonedDateTime(local_dt, warsaw, 1).zone.name) == "EET" + @test string(ZonedDateTime(local_dt, warsaw, 2).zone.name) == "CET" @test_throws AmbiguousTimeError ZonedDateTime(local_dt, warsaw, true) @test_throws AmbiguousTimeError ZonedDateTime(local_dt, warsaw, false) - @test ZonedDateTime(utc_dts[1], warsaw, from_utc=true).zone.name == "EET" - @test ZonedDateTime(utc_dts[2], warsaw, from_utc=true).zone.name == "CET" + @test string(ZonedDateTime(utc_dts[1], warsaw, from_utc=true).zone.name) == "EET" + @test string(ZonedDateTime(utc_dts[2], warsaw, from_utc=true).zone.name) == "CET" @test ZonedDateTime(local_dt, warsaw, 1).utc_datetime == utc_dts[1] @test ZonedDateTime(local_dt, warsaw, 2).utc_datetime == utc_dts[2] @@ -283,14 +283,14 @@ using Dates: Hour, Second, UTM, @dateformat_str # Make sure that the duplicated hour only doesn't contain an additional entry. @test_throws AmbiguousTimeError ZonedDateTime(DateTime(1935,9,1), dup) - @test ZonedDateTime(DateTime(1935,9,1), dup, 1).zone.name == "DTDT-2" - @test ZonedDateTime(DateTime(1935,9,1), dup, 2).zone.name == "DTST" + @test string(ZonedDateTime(DateTime(1935,9,1), dup, 1).zone.name) == "DTDT-2" + @test string(ZonedDateTime(DateTime(1935,9,1), dup, 2).zone.name) == "DTST" @test_throws BoundsError ZonedDateTime(DateTime(1935,9,1), dup, 3) # Ensure that DTDT-1 is completely ignored. @test_throws NonExistentTimeError ZonedDateTime(DateTime(1935,4,1), dup) - @test ZonedDateTime(DateTime(1935,4,1,1), dup).zone.name == "DTDT-2" - @test ZonedDateTime(DateTime(1935,8,31,23), dup).zone.name == "DTDT-2" + @test string(ZonedDateTime(DateTime(1935,4,1,1), dup).zone.name) == "DTDT-2" + @test string(ZonedDateTime(DateTime(1935,8,31,23), dup).zone.name) == "DTDT-2" end @testset "equality" begin @@ -430,4 +430,20 @@ using Dates: Hour, Second, UTM, @dateformat_str @test typemin(ZonedDateTime) <= ZonedDateTime(typemin(DateTime), utc) @test typemax(ZonedDateTime) >= ZonedDateTime(typemax(DateTime), utc) end + + # TODO: isbits is not working on 32 bit because of not using SName type, because of + # https://github.com/JuliaString/MurmurHash3.jl/issues/12 + Int==Int64 && @testset "isbits" begin + utc_zdt = ZonedDateTime(1, 2, 3, 4, 5, 6, 7, utc) + @test isbits(utc) + + var_zdt = ZonedDateTime(Date(2011, 6, 1), tz"America/Winnipeg") + @test !isbits(var_zdt) # we might like this, but we don't have it. + @test isbits(var_zdt.utc_datetime) + @test isbits(var_zdt.zone) + @test isbits(var_zdt.utc_datetime) + @test isbits(var_zdt.timezone.cutoff) + @test isbits(var_zdt.timezone.name) + @test isbitstype(eltype(var_zdt.timezone.transitions)) + end end diff --git a/test/tzdata/compile.jl b/test/tzdata/compile.jl index b2e80d9fc..c0cae1943 100644 --- a/test/tzdata/compile.jl +++ b/test/tzdata/compile.jl @@ -132,10 +132,10 @@ dates, ordered = order_rules([rule_post, rule_endless, rule_overlap, rule_pre], # Europe/Warsaw time zone has a combination of factors that requires computing # the abbreviation to be done in a specific way. - @test tz.transitions[1].zone.name == "LMT" - @test tz.transitions[2].zone.name == "WMT" - @test tz.transitions[3].zone.name == "CET" # Standard time - @test tz.transitions[4].zone.name == "CEST" # Daylight saving time + @test string(tz.transitions[1].zone.name) == "LMT" + @test string(tz.transitions[2].zone.name) == "WMT" + @test string(tz.transitions[3].zone.name) == "CET" # Standard time + @test string(tz.transitions[4].zone.name) == "CEST" # Daylight saving time @test issorted(tz.transitions) zone = Dict{AbstractString,FixedTimeZone}()