calendarmodule calendar
// Types
type t_date
type t_dateTime
type t_timestamp
type t = t_date | t_dateTime | t_timestamp
type t_withTime = t_dateTime | t_timestamp
type t_time
case failIfBad
case undefIfBad
case normIfBad
type errorMode = failIfBad | undefIfBad | normIfBad
// Constructors
def makeDate : errorMode -> number -> number -> number -> t_date
def importDate : errorMode -> data -> t_date
def makeDateTime : errorMode -> number -> number -> number ->
number -> number -> number -> t_dateTime
def importDateTime : errorMode -> data -> t_dateTime
def makeTimestamp : errorMode -> number -> number -> number ->
number -> number -> number -> number -> string ->
t_timestamp
def importTimestamp : errorMode -> data -> t_timestamp
def reprTimestamp : number -> string -> t_timestamp
def makeTime : number -> number -> number -> t_time
def importTime : data -> t_time
// Projections
def year : t -> number
def month : t -> number
def day : t -> number
def hour : (t_withTime | t_time) -> number
def minute : (t_withTime | t_time) -> number
def second : (t_withTime | t_time) -> number
def tzName : t_timestamp -> string
def tzOffset : t_timestamp -> number
// Conversions
def toDate : t -> t_date
def toDateTime : t_withTime -> t_dateTime
def toTimestamp : string -> t -> t_timestamp // since PR#769
def toString : t -> string
def toDBString : t_timestamp -> string // since PR#1284
def parse : string -> t
def parseResult : string -> result(string, t)
def export : (t | t_time) -> data // since PR#769
def format : string -> (t | t_time) -> string // public since #1856
def reprTime : t_time -> data
def toTime : t_withTime -> t_time
// Updaters
def setDay : number -> t -> t
def setMonth : number -> t -> t
def setYear : number -> t -> t
def setHour : number -> (t_withTime | t_time) -> (t_withTime | t_time)
def setMinute : number -> (t_withTime | t_time) -> (t_withTime | t_time)
def setSecond : number -> (t_withTime | t_time) -> (t_withTime | t_time)
def setTimezone : string -> t_timestamp -> t_timestamp
// Addition
def addDays : number -> t -> t
def addMonths : number -> t -> t
def addYears : number -> t -> t
def addHours : number -> (t_withTime | t_time) -> (t_withTime | t_time)
def addMinutes : number -> (t_withTime | t_time) -> (t_withTime | t_time)
def addSeconds : number -> (t_withTime | t_time) -> (t_withTime | t_time)
def addTimes : t_time -> t_time -> [t_time, bool]
// Subtraction (since PR#1011)
def subDays : number -> t -> t
def subMonths : number -> t -> t
def subYears : number -> t -> t
def subHours : number -> t_withTime -> t_withTime
def subMinutes : number -> t_withTime -> t_withTime
def subSeconds : number -> t_withTime -> t_withTime
def subTimes : t_time -> t_time -> [t_time, bool] // since PR #1856
// Time difference
def diffDays : t -> t -> number
def diffMonths : t -> t -> number
def diffYears : t -> t -> number
def diffHours : (t_withTime | t_time) -> (t_withTime | t_time) -> number
def diffMinutes : (t_withTime | t_time) -> (t_withTime | t_time) -> number
def diffSeconds : (t_withTime | t_time) -> (t_withTime | t_time) -> number
def diffTimes : t_time -> t_time -> [t_time, bool]
// Helper functions and derived properties
def isLeapYear : number -> bool
def numDaysOfYear : number -> number
def numDaysOfMonth : number -> number -> number
def firstDayOfMonth : t -> t
def lastDayOfMonth : t -> t
def firstDayOfYear : t -> t
def lastDayOfYear : t -> t
def dayOfYear : t -> number
def epochDate : t_date
def epochDateTime : t_dateTime
def epoch : t_timestamp
def daysSinceEpoch : t -> number
def secondsSinceEpoch : t_withTime -> number
def now : null -> t_timestamp
def localNow : null -> t_timestamp # since PR#1011
// looping over days
def dayRange : t -> t -> t_date*
// periods
type t_period
type t_periodInfo = data
def makePeriod : number -> number -> t_date -> t_period
def periodDayOfDate : t_period -> t -> number
def periodInfoOfDate : t_period -> t -> t_periodInfo
def dateOfPeriodInfo : t_period -> t_periodInfo -> t_date
def firstDayOfPeriod : t_period -> t_periodInfo -> t_date
def lastDayOfPeriod : t_period -> t_periodInfo -> t_date
def succPeriodInfo : t_period -> t_periodInfo -> t_periodInfo
def periodRange : t_period -> t -> t -> t_periodInfo*
// weeks
case weekUS
case weekISO
type t_weekKind = weekUS | weekISO
type t_weekInfo = data
def weekSunSat : t_period
def weekMonSun : t_period
def weekPeriod : t_weekKind -> t_period
def weekDay : t_weekKind -> t -> number
def weekInfoOfPeriodInfoISO : t_periodInfo -> t_weekInfo
def weekInfoOfDate : t_weekKind -> t -> t_weekInfo
def dateOfWeekInfo : t_weekKind -> t_weekInfo -> t_date
def weeksOfYear : t_weekKind -> number -> number
def diffWeeks : t_weekKind -> t -> t -> number
def weekRangeISO : t -> t -> t_weekInfo*
def weekTable : t_weekKind -> t -> t -> array(array(t_date)). // since PR#769
// quarters
type t_quarter
type t_quarterInfo = data
def makeQuarter : number -> t_quarter
def naturalQuarter : t_quarter
def quarterOfDate : t_quarter -> t -> number
def quarterInfoOfDate : t_quarter -> t -> t_quarterInfo
def firstDayOfQuarter : t_quarter -> t_quarterInfo -> t_date
def lastDayOfQuarter : t_quarter -> t_quarterInfo -> t_date
def dateOfQuarterInfo : t_quarter -> t_quarterInfo -> t_date
def succQuarterInfo : t_quarterInfo -> t_quarterInfo
def numDaysOfQuarter : t_quarter -> t_quarterInfo -> number
def diffQuarters : t_quarter -> t -> t -> number
def quarterRange : t_quarter -> t -> t -> t_quarterInfo*
module end
type t_date
type t_dateTime
type t_timestamp
type t = t_date | t_dateTime | t_timestamp
type t_withTime = t_dateTime | t_timestamp
case failIfBad
case undefIfBad
case normIfBad
type errorMode = failIfBad | undefIfBad | normIfBad
We provide three different date types:
t_date is a whole day in the calendart_dateTime is a date with time down to secondst_timestamp is a date with time in a timezoneThere is also t which can be any of the three, and t_withTime meaning the two types having time fields.
Only real dates can be represented, e.g. there is no day 2019/2/29 and because of this you cannot represent this bad day as t_date.
While we take leap days into account, leap seconds are not supported. Seconds are only allowed in the range 0 to 59 (and not 60, as it would be needed for leap seconds).
The constructors allow it to specify how to deal with bad days:
failIfBad means to trigger a runtime error when a bad day is foundundefIfBad means that the value undefined is returned by the constructor when the day is badnormIfBad means to normalize the date so that it fits into the legal range. For example, 2019/2/29 would be normalized to 2019/3/1, and 2019/2/0 would be normalized to 2019/1/31. Any of month/day/hour/minute/second is normalized this way, and the value can be any amount off (e.g. for any positive n, 2019/1/-n would be the n+1-st day before 2019/1/1).You can compare date values with the normal comparisons ==, <, <= etc. You can compare a t_date with a t_date, a t_dateTime with a t_dateTime and a t_timestamp with a t_timestamp. It is not meaningful to do mixed comparisons, e.g. a date with a timestamp.
Regarding timestamps, the comparison behaves as if the corresponding second since the epoch was compared.
def makeDate : errorMode -> number -> number -> number -> t_date
def importDate : errorMode -> data -> t_date
def makeDateTime : errorMode -> number -> number -> number ->
number -> number -> number -> t_dateTime
def importDateTime : errorMode -> data -> t_dateTime
def makeTimestamp : errorMode -> number -> number -> number ->
number -> number -> number -> number -> string ->
t_timestamp
def importTimestamp : errorMode -> data -> t_timestamp
def reprTimestamp : number -> string -> t_timestamp
def makeTime : number -> number -> number -> t_time
The make functions create date / time values from individual fields:
makeDate(emode, year, month, day)makeDateTime(emode, year, month, day, hour, minute, second)makeTimestamp(emode, year, month, day, hour, minute, second, tzOffset, tzName)makeTime(hour, minute, second)Note that makeTimestamp gives the tzOffsetprecedence over the tzName when interpreting the timestamp relative to a time zone. If you want to give the time zone by name only, do it this way:
let ts =
calendar.makeDateTime(emode, year, month, day, hour, minute, second)
|> calendar.toTimestamp(tzName)
The import functions create date values from objects:
importDate(emode, {year, month, day})importDateTime(emode, {year, month, day, hour, minute, second})importTimestamp(emode, {year, month, day, hour, minute, second, timezone, tzOffset, tzName})Timezones are given by both the timezone offset in minutes and a timezone name. While the timezone name is usually a fixed string like “Europe/Amsterdam” designating a geo-political region, the offset is the actual offset used at the particular day. The offset varies over the year because of daylight savings.
When calculating with timestamps, the timezone name remains the same, and the offset is adapted to the final day, e.g.