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.DateTimeStandardType
DateTimeStandard([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".

source
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.

Note

This function is experimental and might be removed in the future. It relies on some internal function of Dates for parsing the format.

source
CFTime.DateTimeJulianType
DateTimeJulian([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".

source
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.

Note

This function is experimental and might be removed in the future. It relies on some internal function of Dates for parsing the format.

source
CFTime.DateTimeProlepticGregorianType
DateTimeProlepticGregorian([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".

source
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.

Note

This function is experimental and might be removed in the future. It relies on some internal function of Dates for parsing the format.

source
CFTime.DateTimeAllLeapType
DateTimeAllLeap([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".

source
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.

Note

This function is experimental and might be removed in the future. It relies on some internal function of Dates for parsing the format.

source
CFTime.DateTimeNoLeapType
DateTimeNoLeap([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".

source
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.

Note

This function is experimental and might be removed in the future. It relies on some internal function of Dates for parsing the format.

source
CFTime.DateTime360DayType
DateTime360Day([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".

source
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.

Note

This function is experimental and might be removed in the future. It relies on some internal function of Dates for parsing the format.

source

Time encoding and decoding

CFTime.timedecodeFunction
dt = 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.

CalendarType (prefer_datetime=true)Type (prefer_datetime=false)
standard, gregorianDateTimeDateTimeStandard
proleptic_gregorianDateTimeDateTimeProlepticGregorian
julianDateTimeDateTimeJulian
noleap, 365_dayDateTimeNoLeapDateTimeNoLeap
all_leap, 366_dayDateTimeAllLeapDateTimeAllLeap
360_dayDateTime360DayDateTime360Day

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)
source
CFTime.timeencodeFunction
data = 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".

source

Accessor Functions

Dates.yearMethod
Dates.year(dt::AbstractCFDateTime) -> Int64

Extract the year part of an AbstractCFDateTime as an Int64.

source
Dates.monthMethod
Dates.month(dt::AbstractCFDateTime) -> Int64

Extract the month part of an AbstractCFDateTime as an Int64.

source
Dates.dayMethod
Dates.day(dt::AbstractCFDateTime) -> Int64

Extract the day part of an AbstractCFDateTime as an Int64.

source
Dates.hourMethod
Dates.hour(dt::AbstractCFDateTime) -> Int64

Extract the hour part of an AbstractCFDateTime as an Int64.

source
Dates.minuteMethod
Dates.minute(dt::AbstractCFDateTime) -> Int64

Extract the minute part of an AbstractCFDateTime as an Int64.

source
Dates.secondMethod
Dates.second(dt::AbstractCFDateTime) -> Int64

Extract the second part of an AbstractCFDateTime as an Int64.

source
Dates.millisecondMethod
Dates.millisecond(dt::AbstractCFDateTime) -> Int64

Extract the millisecond part of an AbstractCFDateTime as an Int64.

source
Dates.microsecondMethod
Dates.microsecond(dt::AbstractCFDateTime) -> Int64

Extract the microsecond part of an AbstractCFDateTime as an Int64.

source
Dates.nanosecondMethod
Dates.nanosecond(dt::AbstractCFDateTime) -> Int64

Extract the nanosecond part of an AbstractCFDateTime as an Int64.

source
CFTime.picosecondMethod
CFTime.picosecond(dt::AbstractCFDateTime) -> Int64

Extract the picosecond part of an AbstractCFDateTime as an Int64.

source
CFTime.femtosecondMethod
CFTime.femtosecond(dt::AbstractCFDateTime) -> Int64

Extract the femtosecond part of an AbstractCFDateTime as an Int64.

source
CFTime.attosecondMethod
CFTime.attosecond(dt::AbstractCFDateTime) -> Int64

Extract the attosecond part of an AbstractCFDateTime as an Int64.

source

Query Functions

Dates.daysinmonthFunction
monthlength = 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
source
monthlength = daysinmonth(t)

Returns the number of days in a month containing the date t

Example

julia> daysinmonth(DateTimeAllLeap(2001,2,1))
29
source
Dates.daysinyearFunction
yearlength = 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
source
yearlength = daysinyear(t)

Returns the number of days in a year containing the date t

Example

julia> daysinyear(DateTimeAllLeap(2001,2,1))
366
source
Dates.yearmonthdayFunction
yearmonthday(dt::AbstractCFDateTime) -> (Int64, Int64, Int64)

Simultaneously return the year, month and day parts of dt.

source
Dates.yearmonthFunction
yearmonth(dt::AbstractCFDateTime) -> (Int64, Int64)

Simultaneously return the year and month parts of dt.

source
Dates.monthdayFunction
monthday(dt::AbstractCFDateTime) -> (Int64, Int64)

Simultaneously return the month and day parts of dt.

source
Dates.firstdayofyearFunction
firstdayofyear(dt::AbstractCFDateTime) -> Int

Return the first day of the year including the date dt

source
Dates.dayofyearFunction
dayofyear(dt::AbstractCFDateTime) -> Int

Return the day of the year for dt with January 1st being day 1.

source

Convertion Functions

Base.convertFunction
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.

source
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.

source
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.

source
Base.reinterpretFunction
dt2 = 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.

source

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.