-
Notifications
You must be signed in to change notification settings - Fork 15
Datetime Manual
From the beginning, Julia has had a problem with being greedy. This same greed has driven the development of the Datetime package. With roots in Joda/JS-310, numpy datetime64, lubridate, zoo, and runt, the Datetime package aims to greedily provide a DateTime implementation that is not only top in efficiency and performance, but that also contains a full range of types and methods for working with dates, times, periods, and time series of any flavor. Dates and times can be notoriously tricky to work with, so Datetime strives for accuracy, clarity, and simplicity. We also realize we're far from perfect, so tire-kicking, feature requests, and bug reports are heartily welcomed and appreciated!
- Calendars/Type Parameters
- Period Types
- TimeTypes
- Date
- DateTime
- TimeType Ranges
Following Joda-time's idea of pluggable chronologies, Datetime defines Calendar, an abstract type that can be subtyped for specific calendar implementations and that all Period/TimeTypes take as a parameter. Datetime defines a default Calendar with abstract ISOCalendar <: Calendar which follows ISO 8601 standards. Using a Calendar type as a type and method parameter is a core principle of the Datetime package; it not only leverages Julia's multiple dispatch for Calendar-specific methods, but also allows for extremely efficient Date, DateTime, and Period types that don't need to store certain metadata like a Calendar value/pointer. Indeed, these types simply wrap 32 and 64-bit integers [(yep, 4 and 8 bytes!)][1]. The same style is used to specify an offset for DateTime; thus, PST (Pacific Standard Time) is an Offsets type that DateTime can take as a parameter upon creation and is used in calculating the appropriate offset when showing its value. Let's see some of these parameters in action:
julia> y = year(1)
1 year
julia> typeof(y)
Year{ISOCalendar}
julia> dt = today()
2013-07-26
julia> typeof(dt)
Date{ISOCalendar}
julia> calendar(dt)
ISOCalendar
julia> typeof(calendar(dt))
DataType
julia> super(calendar(dt))
Calendar
julia> dt2 = now(CST)
2013-07-25T23:08:12 CDT
julia> typeof(dt2)
DateTime{ISOCalendar,Zone382}
julia> super(CST)
TimeZone
julia> super(TimeZone)
OffsetsZone382 represents the "America/Chicago" or Central Standard Time timezone (for those interested 382 comes directly from the universally used Olson timezone database zone IDs).
[1]: Compare to other languages: R = 256 bytes, Python date, datetime classes = 32, 48 bytes, Joda-time = 24-40 bytes
Period types (i.e. Year, Month, Week, Day, etc) have always been a bit controversial in Datetime implementations. The core problem is that Periods represent a human view of time that aren't fixed durations of time. Consider 1 month; it could represent, in days, a value of 28, 29, 30, or 31 depending on the year and month context. Or 1 year could represent 365 or 366 days in the case of a leap year. In any case, the real trickiness comes out when Date/DateTime-Period arithmetic is considered (which is discussed for each type in its section below). Thanks to the power and expressiveness of Julia's type and dispatch systems, Datetime provides Period implementations that aim to be simple and predictable. Currently Year, Month, Week, Day, Hour, Minute, and Second are 32-bit Period types that can be used for Date/DateTime arithmetic, as well as some limited inter-Period arithmetic. We say "limited" because inter-Period operations aren't always clear (e.g. 1 month + 1 day = ? days). The current approach, which could possibly change, is to allow Year, Week, Day, Hour, Minute, and Second inter-ops, but for months, only Year-Month operations are allowed (it's the only conversion that's consistent). We also follow a "promote downwards" approach to not lose precision (e.g. 1 week + 7 days == 14 days). The motivation for inter-Period operations was to help Periods feel like real types that have their own behaviors and are not severely limited or awkward to work with. Constructing Period types is done through the lowercase single or plural versions of their names:
julia> y = year(1)
1 year
julia> m = months(1)
1 month
julia> w = weeks(52)
52 weeks
julia> d = days(10)
10 days
julia> h = hour(24)
24 hours
julia> mi = minute(1)
1 minute
julia> s = second(1)
1 secondConversion between types occur with same functions applied to already created Periods:
julia> month(year(1))
12 months
julia> weeks(year(1))
52 weeks
julia> hours(day(1))
24 hoursArithmetic and comparison operations follow the promotion rules discussed earlier.
julia> year(1) + month(1)
13 months
julia> year(1) + week(1)
53 weeks
julia> year(1) + day(1)
366 days
julia> month(1) + week(1)
ERROR: no method convert(Type{Week{ISOCalendar}},Month{ISOCalendar})
in + at no file
julia> month(1) + day(1)
ERROR: no method convert(Type{Day{ISOCalendar}},Month{ISOCalendar})
in + at no file
julia> week(1) == day(7)
true
julia> day(1) == seconds(86400)
true
julia> year(1) > second(1)
truePeriod types also support PeriodRange, which allows a Range type to be constructed similar to the numeric Ranges in Julia.
julia> startyear = year(1)
1 year
julia> endyear = year(101)
101 years
julia> stepyear = year(25)
25 years
julia> r = startyear:stepyear:endyear
1 year:25 years:101 years
julia> first(r)
1 year
julia> last(r)
101 years
julia> length(r)
5
julia> step(r)
25 years
julia> [r]
5-element Period Array:
1 year
26 years
51 years
76 years
101 yearsDatetime currently provides two TimeTypes: Date and DateTime, representing different levels of "precision". The motivation for distinct types is simple, some operations are much simpler, both in terms of code and mental reasoning, when the complexities of greater precision don't have to be dealt with. For example, the Date type has a "day-precision" (i.e. no hours, minutes, or seconds), which means that normal gotchas with time zones, daylight savings/summer time, or leap seconds are nonexistent.