Skip to content

Commit

Permalink
test all calendars with reference algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander-Barth committed Mar 5, 2024
1 parent 42d7772 commit 609eaee
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 39 deletions.
6 changes: 6 additions & 0 deletions src/period.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ end
return sum(divi[1:length(tuf)] .* tuf)
end

"""
days,h,mi,s,ms,... = timetuplefrac(t::Period)
Return a tuple with the number of whole days, hours (`h`), minutes (`mi`),
seconds (`s`) and millisecods (`ms`),... from the time period `t`.
"""
function timetuplefrac(t::Period{T,Tfactor}) where {T,Tfactor}
# for integers
factor = _factor(t)
Expand Down
18 changes: 0 additions & 18 deletions src/query.jl
Original file line number Diff line number Diff line change
@@ -1,23 +1,5 @@
# query functions

@inline isleap(::Type{DateTimeAllLeap},year,has_year_zero) = true
@inline isleap(::Type{DateTimeNoLeap},year,has_year_zero) = false

@inline function isleap(::Type{DateTimeProlepticGregorian},year,has_year_zero)
if (year < 0) && !has_year_zero
year = year + 1
end
return (year % 400 == 0) || ((year % 4 == 0) && (year % 100 !== 0))
end

@inline function isleap(::Type{DateTimeJulian},year,has_year_zero)
if (year < 0) && !has_year_zero
year = year + 1
end
return year % 4 == 0
end


# https://web.archive.org/web/20240304171516/https://unidata.github.io/cftime/api.html
# https://github.com/cf-convention/cf-conventions/issues/298
@inline _hasyear0(::Type{T}) where T <: Union{DateTimeJulian,DateTimeStandard} = false
Expand Down
66 changes: 53 additions & 13 deletions test/reference_algorithm.jl
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
module Reference

import CFTime
import CFTime:
DateTimeJulian,
DateTimeProlepticGregorian,
_hasyear0,
isleap
DateTimeStandard,
DateTimeNoLeap,
DateTimeAllLeap,
DateTime360Day,
_hasyear0

# Adapted
# from https://github.com/Unidata/cftime/blob/dc75368cd02bbcd1352dbecfef10404a58683f94/src/cftime/_cftime.pyx
# Licence MIT
# by Jeff Whitaker (https://github.com/jswhit)
@inline isleap(::Type{DateTimeAllLeap},year,has_year_zero) = true
@inline isleap(::Type{DateTimeNoLeap},year,has_year_zero) = false
@inline isleap(::Type{DateTime360Day},year,has_year_zero) = false

@inline function isleap(::Type{DateTimeProlepticGregorian},year,has_year_zero)
if (year < 0) && !has_year_zero
year = year + 1
end
return (year % 400 == 0) || ((year % 4 == 0) && (year % 100 !== 0))
end

@inline function isleap(::Type{DateTimeJulian},year,has_year_zero)
if (year < 0) && !has_year_zero
year = year + 1
end
return year % 4 == 0
end

@inline function isleap(::Type{DateTimeStandard},year,has_year_zero)
if year < 1582
isleap(DateTimeJulian,year,has_year_zero)
else
isleap(DateTimeProlepticGregorian,year,has_year_zero)
end
end

@inline function month_lengths(::Type{T}, year::Integer, has_year_zero) where T
if isleap(T, year, has_year_zero)
Expand All @@ -19,11 +44,19 @@ import CFTime:
end
end

function month_lengths(::Type{DateTime360Day}, year::Integer, has_year_zero)
ntuple(i -> 30,12)
end

# Adapted
# from https://github.com/Unidata/cftime/blob/dc75368cd02bbcd1352dbecfef10404a58683f94/src/cftime/_cftime.pyx
# Licence MIT
# by Jeff Whitaker (https://github.com/jswhit)


@inline function datetuple_ymd(::Type{T}, delta_days, julian_gregorian_mixed, has_year_zero) where T
year = 1858
month = 11
day = 17
# use the same origin
year,month,day = CFTime.datetuple_ymd(T,0)

month_length = month_lengths(T, year, has_year_zero)

Expand All @@ -34,8 +67,14 @@ end
0
end

# The Julian calendar day Thursday, 4 October 1582 was
# followed by the first day of the Gregorian calendar,
# Friday, 15 October 1582

# counting down
@inbounds while delta_days < 0
if (year == 1582) && (month == 10) && (day > 14) && (day + delta_days < 15)
#@show n_invalid_dates
delta_days -= n_invalid_dates # skip over invalid dates
end

Expand All @@ -61,6 +100,7 @@ end

@inbounds while delta_days > 0
if (year == 1582) && (month == 10) && (day < 5) && (day + delta_days > 4)
#@show n_invalid_dates
delta_days += n_invalid_dates # skip over invalid dates
end

Expand All @@ -86,10 +126,10 @@ end
return year,month,day
end

function datetuple_ymd(::Type{DateTimeProlepticGregorian},Z)
has_year_zero = _hasyear0(DateTimeProlepticGregorian)
julian_gregorian_mixed = false
return datetuple_ymd(DateTimeProlepticGregorian, Z, julian_gregorian_mixed, has_year_zero)
function datetuple_ymd(::Type{T},Z) where T
has_year_zero = _hasyear0(T)
julian_gregorian_mixed = T <: DateTimeStandard
return datetuple_ymd(T, Z, julian_gregorian_mixed, has_year_zero)
end

end
18 changes: 10 additions & 8 deletions test/test_time.jl
Original file line number Diff line number Diff line change
Expand Up @@ -484,15 +484,17 @@ for T in [DateTimeStandard, DateTimeJulian, DateTimeProlepticGregorian,
end


# comparision with reference algorithm
#Δ = 1
Δ = 1000

Z = CFTime.datenum(DateTimeProlepticGregorian,-1000,1,1):CFTime.datenum(DateTimeProlepticGregorian,4000,1,1)

Z = CFTime.datenum(DateTimeProlepticGregorian,-1000,1,1):100:CFTime.datenum(DateTimeProlepticGregorian,4000,1,1)

MYMD = CFTime.datetuple_ymd.(DateTimeProlepticGregorian,Z);
RYMD = Reference.datetuple_ymd.(DateTimeProlepticGregorian,Z);

@test MYMD == RYMD
for T in [DateTimeStandard, DateTimeJulian, DateTimeProlepticGregorian,
DateTimeAllLeap, DateTimeNoLeap, DateTime360Day]
Z = CFTime.datenum(T,-1000,1,1):Δ:CFTime.datenum(T,4000,1,1)
MYMD = CFTime.datetuple_ymd.(T,Z);
RYMD = Reference.datetuple_ymd.(T,Z);
@test MYMD == RYMD
end

#=
for dt = DateTime(-1000,1,1):Day(100):DateTime(2300,3,1)
Expand Down

0 comments on commit 609eaee

Please sign in to comment.