Skip to content

Commit

Permalink
promotion rules
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander-Barth committed Mar 1, 2024
1 parent 8ba1e67 commit 71cab34
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 32 deletions.
6 changes: 3 additions & 3 deletions src/CFTime.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ The following types are supported `DateTime`,
module CFTime

using Printf
using Dates
import Dates: UTInstant, Millisecond
import Dates
import Dates: UTInstant, Millisecond, DateTime, DateFormat
import Dates:
year,
month,
Expand Down Expand Up @@ -50,7 +50,7 @@ import Dates:
yearmonth,
yearmonthday

import Base: +, -, isless, string, show, convert, reinterpret, ==
import Base: +, -, isless, string, show, convert, reinterpret, ==, promote_rule

include("constants.jl")
include("types.jl")
Expand Down
23 changes: 1 addition & 22 deletions src/datetime.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ This type implements the calendar defined as "$($calendar)".
units = first(TIME_DIVISION[max(length(args),7)-2]),
)
DT = $CFDateTime
factor, exponent = filter(td -> td[1] == units,TIME_DIVISION)[1][2:end]
factor, exponent = filter(td -> td[1] == Symbol(units),TIME_DIVISION)[1][2:end]
T = Period{Ti,Val(factor), Val(exponent)}
return DT{T,Val(origin)}(args...)
end
Expand Down Expand Up @@ -182,27 +182,6 @@ pattern given in the `format` string.
end
end


function +(p1::Period{T,Tfactor,Texponent},p2::Period{T,Tfactor,Texponent}) where {T, Tfactor, Texponent}
Period{T,Tfactor,Texponent}(p1.duration + p2.duration)
end

function +(p1::Period{T1},p2::Period{T2}) where {T1, T2}
T = promote_type(T1,T2)

# which is the smallest unit?
if _factor(p1) / 10^(-_exponent(p1)) <= _factor(p2) / 10^(-_exponent(p2))

duration = T(p1.duration) +
(T(p2.duration) * _factor(p2) * 10^(_exponent(p2)-_exponent(p1))) ÷
_factor(p1)
return Period(duration,_factor(p1),_exponent(p1))
else
return p2 + p1
end
end


+(dt::AbstractCFDateTime,p::Union{Dates.TimePeriod,Dates.Day}) = dt + convert(CFTime.Period,p)

function -(dt1::AbstractCFDateTime,dt2::AbstractCFDateTime)
Expand Down
43 changes: 43 additions & 0 deletions src/period.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@

Period(duration::Number,factor,exponent=-3) = Period{typeof(duration),Val(factor),Val(exponent)}(duration)

function Period(duration::Number,units::Union{Symbol,AbstractString})
factor, exponent = filter(td -> td[1] == Symbol(units),TIME_DIVISION)[1][2:end]
return Period(duration,factor,exponent)
end

_type(p::Period{T,factor,exponent}) where {T,factor,exponent} = T
_factor(p::Period{T,factor,exponent}) where {T,factor,exponent} = unwrap(factor)
_exponent(p::Period{T,factor,exponent}) where {T,factor,exponent} = unwrap(exponent)
Expand Down Expand Up @@ -67,6 +72,44 @@ function Period(T::DataType,tuf::Tuple,factor,exponent=-3)
Period{typeof(duration),Val(factor),Val(exponent)}(duration)
end

function promote_rule(::Type{Period{T1,Tfactor1,Texponent1}},
::Type{Period{T2,Tfactor2,Texponent2}}) where
{T1,Tfactor1,Texponent1,T2,Tfactor2,Texponent2}

factor1 = unwrap(Tfactor1)
factor2 = unwrap(Tfactor2)
exponent1 = unwrap(Texponent1)
exponent2 = unwrap(Texponent2)
T = promote_type(T1,T2)

# which is the smallest unit?
if factor1 / 10^(-exponent1) <= factor2 / 10^(-exponent2)
return Period{T,Tfactor1,Texponent1}
else
return Period{T,Tfactor2,Texponent2}
end
end

function convert(::Type{Period{T1,Tfactor1,Texponent1}},
p::Period{T2,Tfactor2,Texponent2}) where
{T1,Tfactor1,Texponent1,T2,Tfactor2,Texponent2}

factor1 = unwrap(Tfactor1)
factor2 = unwrap(Tfactor2)
exponent1 = unwrap(Texponent1)
exponent2 = unwrap(Texponent2)

duration = (T1(p.duration) * factor2 * 10^(exponent2-exponent1)) ÷
factor1

return Period{T1,Tfactor1,Texponent1}(duration)
end

function +(p1::Period{T,Tfactor,Texponent},p2::Period{T,Tfactor,Texponent}) where {T, Tfactor, Texponent}
Period{T,Tfactor,Texponent}(p1.duration + p2.duration)
end

+(p1::Period,p2::Period) = +(promote(p1,p2)...)
+(p1::Period,p2::Union{Dates.TimePeriod,Dates.Day}) = p1 + convert(CFTime.Period,p2)
+(p1::Union{Dates.TimePeriod,Dates.Day},p2::Period) = p2 + p1

Expand Down
17 changes: 10 additions & 7 deletions test/test_resolution.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ using Pkg; Pkg.activate("CFTime-env",shared=true)
using CFTime
import CFTime: timetuplefrac, datetuple_ymd, timeunits, datetuple, datenum, AbstractCFDateTime, parseDT, datenum_
import Dates
import Dates: value, year, month, day, hour, minute, second, millisecond, microsecond, nanosecond
import Dates: value, year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, DateTime, @dateformat_str
using Test
import Base: +, -, *, zero, one, isless, rem, div, string, convert
using Dates

using CFTime: Period, DateTimeStandard

# TEST
Expand All @@ -30,10 +28,7 @@ end

factor = 1000

#for tuf in (
# (2,3,4,5),
tuf= (2,3,4,5,6,7,8)
# )
factor = 1e-6
exponent = -3

Expand All @@ -47,8 +42,16 @@ exponent = -9
p = Period(tuf,factor,exponent)
@test timetuplefrac(p)[1:length(tuf)] == tuf

# test promotion rules

p1 = CFTime.Period(1,:second)
p2 = CFTime.Period(1000,:millisecond)

@test promote_type(typeof(p1),typeof(p2)) == typeof(p2)

pp1,pp2 = promote(p1,p2)
@test pp1 === pp2

#end

dt = DateTimeStandard(1000,"milliseconds since 2000-01-01");
@test same_tuple((2000, 1, 1, 0, 0, 1),datetuple(dt))
Expand Down

0 comments on commit 71cab34

Please sign in to comment.