Interoperability with the Dates
standard library
Julia's Dates
standard library provides data types for representing specific points in time Date
/DateTime
and differences between them, i.e., periods. Unitful provides methods for using period types from the Dates
standard library together with Quantity
s.
Support for Dates.FixedPeriod
s
The Dates.FixedPeriod
union type includes all Dates.Period
s that represent a fixed period of time, i.e., Dates.Week
, Dates.Day
, Dates.Hour
, Dates.Minute
, Dates.Second
, Dates.Millisecond
, Dates.Microsecond
, and Dates.Nanosecond
. These types can be converted to Quantity
s or used in place of them.
Dates.Year
does not represent a fixed period and cannot be converted to a Quantity
. While Unitful's yr
unit is exactly equal to 365.25 days, a Dates.Year
may contain 365 or 366 days.
Each FixedPeriod
is considered equivalent to a Quantity
. For example, Dates.Millisecond(5)
corresponds to the quantity Int64(5)*u"ms"
. A FixedPeriod
can be converted to the equivalent Quantity
with a constructor:
Unitful.Quantity
— MethodQuantity(period::Dates.FixedPeriod)
Create a Quantity
that corresponds to the given period
. The numerical value of the resulting Quantity
is of type Int64
.
Example
julia> using Dates: Second
julia> Quantity(Second(5))
5 s
In most respects, FixedPeriod
s behave like their equivalent quantities. They can be converted to other units using uconvert
, used in arithmetic operations with other quantities, and they have a unit
and dimension
:
julia> using Dates: Hour
julia> p = Hour(3)
3 hours
julia> uconvert(u"s", p)
10800 s
julia> p == 180u"minute"
true
julia> p < 1u"d"
true
julia> 5u"s" + p
10805 s
julia> 210u"km" / p
70.0 km hr^-1
julia> unit(p) === u"hr"
true
julia> dimension(p)
𝐓
Conversely, a FixedPeriod
can be created from a quantity using the appropriate constructor, convert
, or round
methods. This will fail (i.e., throw an InexactError
) if the resulting value cannot be represented as an Int64
:
julia> using Dates: Day, Hour, Millisecond
julia> Millisecond(1.5u"s")
1500 milliseconds
julia> convert(Hour, 1u"yr")
8766 hours
julia> Day(1u"yr")
ERROR: InexactError: Int64(1461//4)
[...]
julia> round(Day, 1u"yr")
365 days
Support for Dates.CompoundPeriod
s
The Dates
standard library provides the Dates.CompoundPeriod
type to represent sums of periods of different types:
julia> using Dates: Day, Second
julia> Day(5) + Second(1)
5 days, 1 second
julia> typeof(ans)
Dates.CompoundPeriod
Unitful provides facilities to work with CompoundPeriod
s as long as they consist only of FixedPeriod
s. Such CompoundPeriod
s can be converted to Quantity
s using convert
, uconvert
, or round
:
julia> using Dates: Day, Second
julia> p = Day(5) + Second(1)
5 days, 1 second
julia> uconvert(u"s", p)
432001//1 s
julia> convert(typeof(1.0u"yr"), p)
0.01368928562374832 yr
julia> round(u"d", p)
5//1 d
julia> q = Month(1) + Day(1) # Month is not a fixed period
1 month, 1 day
julia> uconvert(u"s", q)
ERROR: MethodError: no method matching Quantity{Rational{Int64},𝐓,Unitful.FreeUnits{(s,),𝐓,nothing}}(::Month)
[...]
However, not all operations that are defined for FixedPeriod
s support CompoundPeriod
s as well. The reason for that is that a CompoundPeriod
does not correspond to a specific unit:
julia> p = Day(365) + Hour(6)
365 days, 6 hours
julia> unit(p) # A CompoundPeriod does not have a corresponding unit ...
ERROR: MethodError: no method matching unit(::Dates.CompoundPeriod)
[...]
julia> dimension(p) # ... but it does have a dimension
𝐓
julia> Quantity(p) # As a result, there is no Quantity type associated with it ...
ERROR: MethodError: no method matching Quantity(::Int64)
[...]
julia> T = typeof(1.0u"hr"); T(p) # ... but it can be converted to a concrete time quantity
8766.0 hr
Consequently, any operation whose result would depend on the input unit is not supported by CompoundPeriod
s. For example:
+(::Quantity, ::CompoundPeriod)
and+(::CompoundPeriod, ::Quantity)
error, since the unit of the result depends on the units of both arguments.div(::Quantity, ::CompoundPeriod)
anddiv(::CompoundPeriod, ::Quantity)
work, since the result is a dimensionless number.mod(::CompoundPeriod, ::Quantity)
works, butmod(::Quantity, ::CompoundPeriod)
does not, since the second argument determines the unit of the returned quantity.