CFTime.jl
This package implements the calendar types from the CF convention, namely:
- Mixed Gregorian/Julian calendar (
DateTimeStandard
) - Proleptic gregorian calendar (
DateTimeProlepticGregorian
) - Gregorian calendar without leap years (all years are 365 days long) (
DateTimeNoLeap
) - Gregorian calendar with only leap year (all years are 366 days long) (
DateTimeAllLeap
) - A calendar with every year being 360 days long (divided into 30 day months) (
DateTime360Day
) - Julian calendar (
DateTimeJulian
)
Note that time zones are not supported by CFTime.jl
.
Installation
Inside the Julia shell, you can download and install the package by issuing:
using Pkg
Pkg.add("CFTime")
Latest development version
If you want to try the latest development version, you can do this with the following commands:
using Pkg
Pkg.add(PackageSpec(url="https://github.com/JuliaGeo/CFTime.jl", rev="master"))
Types
CFTime.DateTimeStandard
— TypeDateTimeStandard([Ti::DataType], y, [m, d, h, mi, s, ms]) -> DateTimeStandard
Construct a DateTimeStandard
type by year (y
), month (m
, default 1), day (d
, default 1), hour (h
, default 0), minute (mi
, default 0), second (s
, default 0), millisecond (ms
, default 0). All arguments must be convertible to Int64
. DateTimeStandard
is a subtype of AbstractCFDateTime
.
The netCDF CF calendars are defined in the CF Standard. This type implements the calendar defined as "standard".
DateTimeStandard(dt::AbstractString, format::AbstractString; locale="english") -> DateTimeStandard
Construct a DateTimeStandard by parsing the dt
date time string following the pattern given in the format
string.
This function is experimental and might be removed in the future. It relies on some internal function of Dates
for parsing the format
.
CFTime.DateTimeJulian
— TypeDateTimeJulian([Ti::DataType], y, [m, d, h, mi, s, ms]) -> DateTimeJulian
Construct a DateTimeJulian
type by year (y
), month (m
, default 1), day (d
, default 1), hour (h
, default 0), minute (mi
, default 0), second (s
, default 0), millisecond (ms
, default 0). All arguments must be convertible to Int64
. DateTimeJulian
is a subtype of AbstractCFDateTime
.
The netCDF CF calendars are defined in the CF Standard. This type implements the calendar defined as "julian".
DateTimeJulian(dt::AbstractString, format::AbstractString; locale="english") -> DateTimeJulian
Construct a DateTimeJulian by parsing the dt
date time string following the pattern given in the format
string.
This function is experimental and might be removed in the future. It relies on some internal function of Dates
for parsing the format
.
CFTime.DateTimeProlepticGregorian
— TypeDateTimeProlepticGregorian([Ti::DataType], y, [m, d, h, mi, s, ms]) -> DateTimeProlepticGregorian
Construct a DateTimeProlepticGregorian
type by year (y
), month (m
, default 1), day (d
, default 1), hour (h
, default 0), minute (mi
, default 0), second (s
, default 0), millisecond (ms
, default 0). All arguments must be convertible to Int64
. DateTimeProlepticGregorian
is a subtype of AbstractCFDateTime
.
The netCDF CF calendars are defined in the CF Standard. This type implements the calendar defined as "prolepticgregorian".
DateTimeProlepticGregorian(dt::AbstractString, format::AbstractString; locale="english") -> DateTimeProlepticGregorian
Construct a DateTimeProlepticGregorian by parsing the dt
date time string following the pattern given in the format
string.
This function is experimental and might be removed in the future. It relies on some internal function of Dates
for parsing the format
.
CFTime.DateTimeAllLeap
— TypeDateTimeAllLeap([Ti::DataType], y, [m, d, h, mi, s, ms]) -> DateTimeAllLeap
Construct a DateTimeAllLeap
type by year (y
), month (m
, default 1), day (d
, default 1), hour (h
, default 0), minute (mi
, default 0), second (s
, default 0), millisecond (ms
, default 0). All arguments must be convertible to Int64
. DateTimeAllLeap
is a subtype of AbstractCFDateTime
.
The netCDF CF calendars are defined in the CF Standard. This type implements the calendar defined as "allleap".
DateTimeAllLeap(dt::AbstractString, format::AbstractString; locale="english") -> DateTimeAllLeap
Construct a DateTimeAllLeap by parsing the dt
date time string following the pattern given in the format
string.
This function is experimental and might be removed in the future. It relies on some internal function of Dates
for parsing the format
.
CFTime.DateTimeNoLeap
— TypeDateTimeNoLeap([Ti::DataType], y, [m, d, h, mi, s, ms]) -> DateTimeNoLeap
Construct a DateTimeNoLeap
type by year (y
), month (m
, default 1), day (d
, default 1), hour (h
, default 0), minute (mi
, default 0), second (s
, default 0), millisecond (ms
, default 0). All arguments must be convertible to Int64
. DateTimeNoLeap
is a subtype of AbstractCFDateTime
.
The netCDF CF calendars are defined in the CF Standard. This type implements the calendar defined as "noleap".
DateTimeNoLeap(dt::AbstractString, format::AbstractString; locale="english") -> DateTimeNoLeap
Construct a DateTimeNoLeap by parsing the dt
date time string following the pattern given in the format
string.
This function is experimental and might be removed in the future. It relies on some internal function of Dates
for parsing the format
.
CFTime.DateTime360Day
— TypeDateTime360Day([Ti::DataType], y, [m, d, h, mi, s, ms]) -> DateTime360Day
Construct a DateTime360Day
type by year (y
), month (m
, default 1), day (d
, default 1), hour (h
, default 0), minute (mi
, default 0), second (s
, default 0), millisecond (ms
, default 0). All arguments must be convertible to Int64
. DateTime360Day
is a subtype of AbstractCFDateTime
.
The netCDF CF calendars are defined in the CF Standard. This type implements the calendar defined as "360day".
DateTime360Day(dt::AbstractString, format::AbstractString; locale="english") -> DateTime360Day
Construct a DateTime360Day by parsing the dt
date time string following the pattern given in the format
string.
This function is experimental and might be removed in the future. It relies on some internal function of Dates
for parsing the format
.
Time encoding and decoding
CFTime.timedecode
— Functiondt = timedecode(data,units,calendar = "standard"; prefer_datetime = true)
Decode the time information in data as given by the units units
according to the specified calendar. Valid values for calendar
are "standard"
, "gregorian"
, "proleptic_gregorian"
, "julian"
, "noleap"
, "365_day"
, "all_leap"
, "366_day"
and "360_day"
.
If prefer_datetime
is true
(default), dates are converted to the DateTime
type (for the calendars "standard", "gregorian", "proleptic_gregorian" and "julian") unless the time unit is expressed in microseconds or smaller. Such conversion is not possible for the other calendars.
Calendar | Type (prefer_datetime=true) | Type (prefer_datetime=false) |
---|---|---|
standard , gregorian | DateTime | DateTimeStandard |
proleptic_gregorian | DateTime | DateTimeProlepticGregorian |
julian | DateTime | DateTimeJulian |
noleap , 365_day | DateTimeNoLeap | DateTimeNoLeap |
all_leap , 366_day | DateTimeAllLeap | DateTimeAllLeap |
360_day | DateTime360Day | DateTime360Day |
Example:
using CFTime, Dates
# standard calendar
dt = CFTime.timedecode([0,1,2,3],"days since 2000-01-01 00:00:00")
# 4-element Array{Dates.DateTime,1}:
# 2000-01-01T00:00:00
# 2000-01-02T00:00:00
# 2000-01-03T00:00:00
# 2000-01-04T00:00:00
dt = CFTime.timedecode([0,1,2,3],"days since 2000-01-01 00:00:00","360_day")
# 4-element Array{DateTime360Day,1}:
# DateTime360Day(2000-01-01T00:00:00)
# DateTime360Day(2000-01-02T00:00:00)
# DateTime360Day(2000-01-03T00:00:00)
# DateTime360Day(2000-01-04T00:00:00)
CFTime.timeencode
— Functiondata = timeencode(dt,units,calendar = "standard")
Convert a vector or array of DateTime
(or DateTimeStandard
, DateTimeProlepticGregorian
, DateTimeJulian
, DateTimeNoLeap
, DateTimeAllLeap
, DateTime360Day
) according to the specified units (e.g. "days since 2000-01-01 00:00:00"
) using the calendar calendar
. Valid values for calendar are: "standard"
, "gregorian"
, "proleptic_gregorian"
, "julian"
, "noleap"
, "365_day"
, "all_leap"
, "366_day"
, "360_day"
.
Accessor Functions
Dates.year
— MethodDates.year(dt::AbstractCFDateTime) -> Int64
Extract the year part of an AbstractCFDateTime
as an Int64
.
Dates.month
— MethodDates.month(dt::AbstractCFDateTime) -> Int64
Extract the month part of an AbstractCFDateTime
as an Int64
.
Dates.day
— MethodDates.day(dt::AbstractCFDateTime) -> Int64
Extract the day part of an AbstractCFDateTime
as an Int64
.
Dates.hour
— MethodDates.hour(dt::AbstractCFDateTime) -> Int64
Extract the hour part of an AbstractCFDateTime
as an Int64
.
Dates.minute
— MethodDates.minute(dt::AbstractCFDateTime) -> Int64
Extract the minute part of an AbstractCFDateTime
as an Int64
.
Dates.second
— MethodDates.second(dt::AbstractCFDateTime) -> Int64
Extract the second part of an AbstractCFDateTime
as an Int64
.
Dates.millisecond
— MethodDates.millisecond(dt::AbstractCFDateTime) -> Int64
Extract the millisecond part of an AbstractCFDateTime
as an Int64
.
Dates.microsecond
— MethodDates.microsecond(dt::AbstractCFDateTime) -> Int64
Extract the microsecond part of an AbstractCFDateTime
as an Int64
.
Dates.nanosecond
— MethodDates.nanosecond(dt::AbstractCFDateTime) -> Int64
Extract the nanosecond part of an AbstractCFDateTime
as an Int64
.
CFTime.picosecond
— MethodCFTime.picosecond(dt::AbstractCFDateTime) -> Int64
Extract the picosecond part of an AbstractCFDateTime
as an Int64
.
CFTime.femtosecond
— MethodCFTime.femtosecond(dt::AbstractCFDateTime) -> Int64
Extract the femtosecond part of an AbstractCFDateTime
as an Int64
.
CFTime.attosecond
— MethodCFTime.attosecond(dt::AbstractCFDateTime) -> Int64
Extract the attosecond part of an AbstractCFDateTime
as an Int64
.
Query Functions
Dates.daysinmonth
— Functionmonthlength = daysinmonth(::Type{DT},y,m)
Returns the number of days in a month for the year y
and the month m
according to the calendar given by the type DT
.
Example
julia> daysinmonth(DateTimeAllLeap,2001,2)
29
monthlength = daysinmonth(t)
Returns the number of days in a month containing the date t
Example
julia> daysinmonth(DateTimeAllLeap(2001,2,1))
29
Dates.daysinyear
— Functionyearlength = daysinyear(::Type{DT},y)
Returns the number of days in a year for the year y
according to the calendar given by the type DT
.
Example
julia> daysinyear(DateTimeAllLeap,2001,2)
366
yearlength = daysinyear(t)
Returns the number of days in a year containing the date t
Example
julia> daysinyear(DateTimeAllLeap(2001,2,1))
366
Dates.yearmonthday
— Functionyearmonthday(dt::AbstractCFDateTime) -> (Int64, Int64, Int64)
Simultaneously return the year, month and day parts of dt
.
Dates.yearmonth
— Functionyearmonth(dt::AbstractCFDateTime) -> (Int64, Int64)
Simultaneously return the year and month parts of dt
.
Dates.monthday
— Functionmonthday(dt::AbstractCFDateTime) -> (Int64, Int64)
Simultaneously return the month and day parts of dt
.
Dates.firstdayofyear
— Functionfirstdayofyear(dt::AbstractCFDateTime) -> Int
Return the first day of the year including the date dt
Dates.dayofyear
— Functiondayofyear(dt::AbstractCFDateTime) -> Int
Return the day of the year for dt with January 1st being day 1.
Convertion Functions
Base.convert
— Functiondt2 = convert(::Type{T}, dt)
Convert a DateTime of type DateTimeStandard
, DateTimeProlepticGregorian
, DateTimeJulian
or DateTime
into the type T
which can also be either DateTimeStandard
, DateTimeProlepticGregorian
, DateTimeJulian
or DateTime
.
Conversion is done such that duration (difference of DateTime types) are preserved. For dates on and after 1582-10-15, the year, month and days are the same for the types DateTimeStandard
, DateTimeProlepticGregorian
and DateTime
.
For dates before 1582-10-15, the year, month and days are the same for the types DateTimeStandard
and DateTimeJulian
.
dt2 = convert(::Type{T}, dt)
Convert a DateTime of type DateTimeStandard
, DateTimeProlepticGregorian
, DateTimeJulian
or DateTime
into the type T
which can also be either DateTimeStandard
, DateTimeProlepticGregorian
, DateTimeJulian
or DateTime
.
Conversion is done such that duration (difference of DateTime types) are preserved. For dates on and after 1582-10-15, the year, month and days are the same for the types DateTimeStandard
, DateTimeProlepticGregorian
and DateTime
.
For dates before 1582-10-15, the year, month and days are the same for the types DateTimeStandard
and DateTimeJulian
.
dt2 = convert(::Type{T}, dt)
Convert a DateTime of type DateTimeStandard
, DateTimeProlepticGregorian
, DateTimeJulian
or DateTime
into the type T
which can also be either DateTimeStandard
, DateTimeProlepticGregorian
, DateTimeJulian
or DateTime
.
Conversion is done such that duration (difference of DateTime types) are preserved. For dates on and after 1582-10-15, the year, month and days are the same for the types DateTimeStandard
, DateTimeProlepticGregorian
and DateTime
.
For dates before 1582-10-15, the year, month and days are the same for the types DateTimeStandard
and DateTimeJulian
.
Base.reinterpret
— Functiondt2 = reinterpret(::Type{T}, dt)
Convert a variable dt
of type DateTime
, DateTimeStandard
, DateTimeJulian
, DateTimeProlepticGregorian
, DateTimeAllLeap
, DateTimeNoLeap
or DateTime360Day
into the date time type T
using the same values for year, month, day, minute, second and millisecond. The conversion might fail if a particular date does not exist in the target calendar.
Arithmetic
Adding and subtracting time periods is supported:
DateTimeStandard(1582,10,4) + Dates.Day(1)
# returns DateTimeStandard(1582-10-15T00:00:00)
1582-10-15 is the adoption of the Gregorian Calendar.
Comparision operator can be used to check if a date is before or after another date.
DateTimeStandard(2000,01,01) < DateTimeStandard(2000,01,02)
# returns true
Time ranges can be constructed using a start date, end date and a time increment, for example: DateTimeStandard(2000,1,1):Dates.Day(1):DateTimeStandard(2000,12,31)
Rounding
using CFTime: DateTimeStandard
dt = DateTimeStandard(24*60*60,"second since 2000-01-01")
floor(dt+Second(9),Second(10)) == dt
# output
true
ceil(dt+Second(9),Second(10)) == dt + Second(10)
# output
true
round(dt+Second(9),Second(10)) == dt + Second(10)
# output
true
Julia's DateTime
records the time relative to a time orgin (January 1st, 1 BC or 0000-01-01 in ISO_8601) with a millisecond accuracy. Converting CFTime date time structures to Julia's DateTime
(using convert(DateTime,dt)
) can trigger an inexact exception if the convertion cannot be done without loss of precision. One can use the round
function in order to round to the nearest time represenatable by DateTime
:
using CFTime: DateTimeStandard
using Dates: DateTime
dt = DateTimeStandard(24*60*60*1000*1000 + 123,"microsecond since 2000-01-01")
round(DateTime,dt)
# output
2000-01-02T00:00:00
Type-stable constructors
To create a type-stable date time structure, use the DateTimeStandard
(and similar) either with the default units
and time origin
, a constant unit/origin or a value type of the unit and origin. For example:
using CFTime
foo(year,month,day,hour,minute,second) = CFTime.DateTimeStandard(year,month,day,hour,minute,second; units=:second, origin=(1970,1,1))
# Type-stable thanks to constant propagation
@code_warntype foo(2000,1,1,0,0,0)
foo2(year,month,day,hour,minute,second,units,origin) = CFTime.DateTimeStandard(year,month,day,hour,minute,second; units, origin)
# This not type-stable as the type depends on the value of units and origin
units = :second
origin = (1970,1,1)
@code_warntype foo2(2000,1,1,0,0,0,units,origin)
# But this is again type-stable
units = Val(:second)
origin = Val((1970,1,1))
@code_warntype foo2(2000,1,1,0,0,0,units,origin)
Internal API
For CFTime 0.1.3 and before all date-times are encoded using internally milliseconds since a fixed time origin and stored as an Int64
similar to julia's Dates.DateTime
. However, this approach does not allow to encode time with a sub-millisecond precision allowed by the CF convention and supported by e.g. numpy. While numpy
allows attosecond precision, it can only encode a time span of ±9.2 around the date 00:00:00 UTC on 1 January 1970. In CFTime the time origin and the number containing the duration and the time precision are now encoded as two additional type parameters.
When wrapping a CFTime date-time type, it is recommended for performance reasons to make the containg structure also parametric, for example
struct MyStuct{T1,T2}
dt::DateTimeStandard{T1,T2}
end
Future version of CFTime might add other type parameters. Internally, T1
corresponds to a CFTime.Period{T,Tfactor,Texponent}
structure wrapping a number type T representing the duration expressed in seconds as:
duration * factor * 10^exponent
where Tfactor
and Texponent
are value types of factor
and exponent
respectively. T2
is a value type of the date origin tuple represented as (year, month, day,...)
.
For example, duration 3600000 milliseconds is represented as duration = 3600000
, Tfactor = Val(1)
, Texponent = Val(-3)
, as
3600000 milliseconds = 3600000 * 1 * 10⁻³ seconds
or the durtion 1 hours is duration = 1
, Tfactor = Val(3600)
and Texponent = Val(0)
since:
1 hour = 3600 * 1 * 10⁰ seconds
There is no normalization of the time duration per default as it could lead to under-/overflow.
The type parameter T2
of DateTimeStandard
encodes the time origin as a tuple of integers starting with the year (year,month,day,hour,minute,seconds,milliseconds,microseconds,...). Only the year, month and day need specified; all other default to zero. For example T2
would be Val((1970,1,1))
if the time origin is the 1st January 1970).
By using value types as type parametes, the time origin, time resolution... are known to the compiler. For example computing the difference between between two date time expressed in as the same time origin and units as a si
using BenchmarkTools
using Dates
dt0 = DateTimeStandard(1,"days since 2000-01-01")
dt1 = DateTimeStandard(1000,"days since 2000-01-01")
difference_datetime(dt0,dt1) = Dates.Millisecond(dt1 - dt0).value
@btime difference_datetime($dt0,$dt1)
# output (minimum of 5 @btime trails)
# 1.689 ns (0 allocations: 0 bytes)
v0 = 1
v1 = 1000
difference_numbers(v0,v1) = (v1-v0)*(86_400_000)
@btime difference_numbers($v0,$v1)
# output (minimum of 5 @btime trails)
# 1.683 ns (0 allocations: 0 bytes)
The information in this section and any other information marked as internal or experimental is not part of the public API and not covered by the semantic versioning. Future version of CFTime might add or changing the meaning of type parameters as patch-level changes. However removing a type parameter would be considered as a breaking change.