diff --git a/base/dates/periods.jl b/base/dates/periods.jl index 1c08edfdaf385..7682164506a73 100644 --- a/base/dates/periods.jl +++ b/base/dates/periods.jl @@ -59,8 +59,10 @@ default(p::Union{T,Type{T}}) where {T<:DatePeriod} = T(1) default(p::Union{T,Type{T}}) where {T<:TimePeriod} = T(0) (-)(x::P) where {P<:Period} = P(-value(x)) +==(x::P, y::P) where {P<:Period} = value(x) == value(y) +==(x::Period, y::Period) = (==)(promote(x, y)...) Base.isless(x::P, y::P) where {P<:Period} = isless(value(x), value(y)) -(==)(x::P, y::P) where {P<:Period} = value(x) == value(y) +Base.isless(x::Period, y::Period) = isless(promote(x, y)...) # Period Arithmetic, grouped by dimensionality: import Base: div, fld, mod, rem, gcd, lcm, +, -, *, /, % @@ -425,9 +427,6 @@ for i = 1:length(fixedperiod_conversions) N *= nc end end -# have to declare thusly so that diagonal dispatch above takes precedence: -(==)(x::T, y::S) where {T<:FixedPeriod,S<:FixedPeriod} = (==)(promote(x, y)...) -Base.isless(x::T, y::S) where {T<:FixedPeriod,S<:FixedPeriod} = isless(promote(x, y)...) # other periods with fixed conversions but which aren't fixed time periods const OtherPeriod = Union{Month, Year} @@ -439,8 +438,13 @@ let vmax = typemax(Int64) ÷ 12, vmin = typemin(Int64) ÷ 12 end Base.convert(::Type{Year}, x::Month) = Year(divexact(value(x), 12)) Base.promote_rule(::Type{Year}, ::Type{Month}) = Month -(==)(x::T, y::S) where {T<:OtherPeriod,S<:OtherPeriod} = (==)(promote(x, y)...) -Base.isless(x::T, y::S) where {T<:OtherPeriod,S<:OtherPeriod} = isless(promote(x, y)...) + +# disallow comparing fixed to other periods +(==)(x::FixedPeriod, y::OtherPeriod) = throw(MethodError(==, (x, y))) +(==)(x::OtherPeriod, y::FixedPeriod) = throw(MethodError(==, (x, y))) + +Base.isless(x::FixedPeriod, y::OtherPeriod) = throw(MethodError(isless, (x, y))) +Base.isless(x::OtherPeriod, y::FixedPeriod) = throw(MethodError(isless, (x, y))) # truncating conversions to milliseconds and days: toms(c::Nanosecond) = div(value(c), 1000000) diff --git a/test/dates/periods.jl b/test/dates/periods.jl index e4bb9d9bb30b2..72ce644003870 100644 --- a/test/dates/periods.jl +++ b/test/dates/periods.jl @@ -234,6 +234,26 @@ test = ((((((((dt + y) - m) + w) - d) + h) - mi) + s) - ms) @test !(Dates.Millisecond(-1) > Dates.Millisecond(1)) @test Dates.Millisecond(1) == Dates.Millisecond(1) @test_throws MethodError Dates.Year(1) < Dates.Millisecond(1) +@test_throws MethodError Dates.Millisecond(1) < Dates.Year(1) +@test_throws MethodError Dates.Year(1) == Dates.Millisecond(1) +@test_throws MethodError Dates.Millisecond(1) == Dates.Year(1) + +# Allow comparisons with new Period subtypes +let + # https://en.wikipedia.org/wiki/Swatch_Internet_Time + struct Beat <: Dates.Period + value::Int64 + end + + Dates.value(b::Beat) = b.value + Dates.toms(b::Beat) = Dates.value(b) * 86400 + Dates._units(b::Beat) = " beat" * (abs(Dates.value(b)) == 1 ? "" : "s") + Base.promote_rule(::Type{Dates.Day}, ::Type{Beat}) = Dates.Millisecond + Base.convert{T<:Dates.Millisecond}(::Type{T}, b::Beat) = T(Dates.toms(b)) + + @test Beat(1000) == Dates.Day(1) + @test Beat(1) < Dates.Day(1) +end @test Dates.Year("1") == y @test Dates.Month("1") == m