# LispKit Date-Time

Library `(lispkit date-time)` provides functionality for handling time zones, dates, and times. Time zones are represented by string identifiers referring to the region and corresponding city, e.g. `"America/Los_Angeles"`. Dates and times are represented via `date-time` data structures. These encapsulate the following components:

- time zone: the time zone of the date
- date: the date consisting of its year, month, and day
- time: the time on date consisting of the hour (>= 0, < 24), the minute (>= 0, < 60), the second (>= 60, <60), and the nano second.

The library uses a floating-point representation of seconds since 00:00 UTC on January 1, 1970, as a means to refer to specific points in time independent of timezones. This means that, for instance, for comparing date-times with each other, a user would have to convert them to seconds and then compare the seconds instead. Here is an example:

    (define initial-time (date-time "Europe/Zurich"))
    (define later-time (date-time "GMT"))
    (date-time< initial-time later-time)
      ⇒  #t
    ; the following line is equivalent:
    (< (date-time->seconds initial-time) (date-time->seconds later-time))
      ⇒  #t

For now, `(lispkit date-time)` assumes all dates are based on the Gregorian calendar, independent of the settings at the operating system-level.

## Time zones

Time zones are represented by string identifiers referring to the region and corresponding city, e.g. `"America/Los_Angeles"`. Procedure `timezones` returns a list of all supported time zone identifiers. Each time zone has a locale-specific name and an offset in seconds from Greenwhich Mean Time. Some time zones also have an abbreviation which can be used as an alternative way to identify a time zone.

(timezones) [procedure]
(timezones filter)

Returns a list of string identifiers for all supported time zones. If filter is provided, it can either be set to `#f`, in which case a list of abbreviations is returned instead, or it is a string, and only time zone identifiers which contain filter are returned.

    (timezones #f)
    ⇒  ("CEST" "GST" "NZDT" "BRST" "WEST" "AST" "MSD" "CDT" "WIT" "MSK" "COT" "IST" "EST" "BST" "CLST" "NDT" "TRT" "EET" "IRST" "EDT" "BRT" "ICT" "CST" "AKST" "BDT" "PHT" "SGT" "WET" "ART" "CLT" "CAT" "UTC" "EEST" "ADT" "JST" "HST" "PET" "MST" "NST" "NZST" "GMT" "MDT" "PKT" "WAT" "HKT" "AKDT" "KST" "PST" "CET" "PDT" "EAT")

(timezone? obj) [procedure]

Returns `#t` if obj is a valid time zone identifier or time zone abbreviation; returns `#f` otherwise.

(timezone) [procedure]
(timezone ident)

Returns the identifier for the time zone specified by ident. ident can either be an identifier, an abbreviation or a GMT offset as a floating-point number or integer. If ident does not refer to a supported time zone, procedure `timezone` will fail.

(timezone-name tz) [procedure]
(timezone-name tz locale)
(timezone-name tz locale format)

Returns a locale-specific name for time zone tz. If locale is not specified, the current locale defined at the operating-system level is used. format specifies the name format. It can have one of the following symbolic values:

- `standard`
- `standard-short`
- `dst`
- `dst-short`
- `generic`
- `generic-short`

(timezone-abbreviation tz) [procedure]

Returns a string representing a time zone abbreviation for tz; e.g. `"PDT"`. If the time zone tz does not have an abbreviation, this function returns `#f`.

(timezone-gmt-offset tz) [procedure]

Returns the difference in seconds between time zone tz and Greenwich Mean Time. The difference is returned as a floating-point number (since seconds are always represented as such by this library).

## Time stamps

Time stamps, i.e. discreet points in time, are represented as floating-point numbers corresponding to the number of seconds since 00:00 UTC on January 1, 1970.

(current-seconds) [procedure]

Returns a floating-point number representing the number of seconds since 00:00 UTC on January 1, 1970.

(seconds->date-time secs) [procedure]
(seconds->date-time secs tz)

Converts the given number of seconds secs into date-time format for the given time zone tz. secs is a floating-point number. It is interpreted as the number of seconds since 00:00 UTC on January 1, 1970. secs is negative if the date-time is earlier than 00:00 UTC on January 1, 1970. If tz is missing, the current, operating-system defined time zone is used.

(date-time->seconds dtime) [procedure]

Returns a floating-point number representing the number of seconds since 00:00 UTC on January 1, 1970 for the given date-time object dtime.

## Date-times

date-time-type-tag [object]

Symbol representing the `date-time` type. The `type-for` procedure of library `(lispkit type)` returns this symbol for all date/time objects.

(date-time? obj) [procedure]

Returns `#t` if obj is a date-time object; returns `#f` otherwise.

(date-time) [procedure]
(date-time year month day)
(date-time year month day hour)
(date-time year month day hour min)
(date-time year month day hour min sec)
(date-time year month day hour min sec nano)
(date-time tz)
(date-time tz year month day)
(date-time tz year month day hour)
(date-time tz year month day hour min)
(date-time tz year month day hour min sec)
(date-time tz year month day hour min sec nano)

Constructs a date-time representation out of the given date time components. tz is the only string argument; it is referring to a time zone. All other arguments are numeric arguments. This procedure returns a date-time object for the specified time at the given date. If no date components are provided as arguments, procedure `date-time` returns a date-time for the current date and time.

(week->date-time year week) [procedure]
(week->date-time year week wday)
(week->date-time year week wday hour)
(week->date-time year week wday hour min)
(week->date-time year week wday hour min sec)
(week->date-time year week wday hour min sec nano)
(week->date-time tz year week) (week->date-time tz year week wday)
(week->date-time tz year week wday hour)
(week->date-time tz year week wday hour min)
(week->date-time tz year week wday hour min sec)
(week->date-time tz year week wday hour min sec nano)

Constructs a date-time representation out of the given date time components. tz is the only string argument; it is referring to a time zone. All other arguments are numeric arguments. Argument wday specifies the week day in the given week. Week days are given numbers from 1 (= Monday) to 7 (= Sunday). This procedure returns a date-time object for the specified time at the given date.

The difference to `date-time` is that this procedure does not refer to a month and day. It rather refers to the week number as well as the weekday within this specified week number.

(date-time-in-timezone dtime) [procedure]
(date-time-in-timezone dtime tzone)

Constructs a date-time representation of the same point in time like dtime, but in a potentially different time zone tzone. If tzone is not given, the default time zone specified by the user in the operating system will be used.

(string->date-time str) [procedure]
(string->date-time str tz)
(string->date-time str tz locale)
(string->date-time str tz locale format)

Extracts a date and time from the given string str in the time zone tz, or the current time zone if tz is omitted. The format of the string representation is defined in terms of locale and format. If both locale and format are omitted or set to `#f`, `string->date-time` assumes the date and time is in ISO 8601 format with UTC as timezone. format can have three different forms:

1. Combined format identifier for date and time: `date-time` parsing is based on the settings of the operating system. format is one of the following symbols: `none`, `short`, `medium`, `long`, or `full`.
2. Separate format identifiers for date and time: `date-time` parsing is based on the settings of the operating system, but the format for dates and times is specified separately. format is a list of the form `(`dateformat timeformat`)` where both dateformat and timeformat are one of the 5 symbols listed under 1. This makes it possible, for instance, to just parse a date (without time) in string form to a date-time object, e.g. by using `(short none)` as format.
3. Custom format specifier: `date-time` parsing is based on a custom format string. format is a string using the following characters as placeholders. Repetitions of the placeholder characters are used to specify the width and format of the field.
   - `y`: Year
   - `M`: Month
   - `d`: Day
   - `H`: Hour (12 hours)
   - `h`: Hour (24 hours)
   - `m`: Minute
   - `s`: Second
   - `S`: Micro second
   - `Z`: Time zone
   - `a`: AM/PM
   - `E`: Weekday

Here are a few examples:

    EEEE, MMM d, yyyy       ~~>  Thursday, Feb 8, 1973
    dd/MM/yyyy              ~~>  08/02/1973
    dd-MM-yyyy HH:mm        ~~>  08-02-1973 17:01
    MMM d, h:mm a           ~~>  Thu 8, 2:11 AM
    yyyy-MM-dd'T'HH:mm:ssZ  ~~>  1973-08-02T17:01:31+0000
    HH:mm:ss.SSS            ~~>  11:02:19.213

(date-time->string dtime) [procedure]
(date-time->string dtime locale)
(date-time->string dtime locale format)

Returns a string representation of the date-time object dtime. The format of the string is defined in terms of locale and format. format can have three different forms (just like for `string->date-time`):

1. Combined format identifier for date and time: `date-time` formatting is based on the settings of the operating system. format is one of the following symbols: `none`, `short`, `medium`, `long`, or `full`.
2. Separate format identifiers for date and time: `date-time` formatting is based on the settings of the operating system, but the format for dates and times is specified separately. format is a list of the form `(`dateformat timeformat`)` where both dateformat and timeformat are one of the 5 symbols listed under 1. This makes it possible, for instance, to just output a date (without time) in string form, e.g. by using `(short none)` as format.
3. Custom format specifier: `date-time` formatting is based on a custom format string. format is a string using the following characters as placeholders. Repetitions of the placeholder characters are used to specify the width and format of the field.
   - `y`: Year
   - `M`: Month
   - `d`: Day
   - `H`: Hour (12 hours)
   - `h`: Hour (24 hours)
   - `m`: Minute
   - `s`: Second
   - `S`: Micro second
   - `Z`: Time zone
   - `a`: AM/PM
   - `E`: Weekday

Here are a few examples:

    EEEE, MMM d, yyyy       ~~>  Thursday, Feb 8, 1973
    dd/MM/yyyy              ~~>  08/02/1973
    dd-MM-yyyy HH:mm        ~~>  08-02-1973 17:01
    MMM d, h:mm a           ~~>  Thu 8, 2:11 AM
    yyyy-MM-dd'T'HH:mm:ssZ  ~~>  1973-08-02T17:01:31+0000
    HH:mm:ss.SSS            ~~>  11:02:19.213

(date-time->iso8601-string dtime) [procedure]
(date-time->iso8601-string dtime fract)
(date-time->iso8601-string dtime fract? excl-tz)

Returns a string representation of the date-time object dtime in ISO 8601 format. If fract? is set to true, seconds are output as floating-point numbers, i.e. with fractional values (default is `#f`). If excl-tz? is set to true, no timezone designator is included in the output (default is `#f`).

(date-time-timezone dtime) [procedure]

Returns the time zone of dtime.

(date-time-year dtime) [procedure]

Returns the year of dtime.

(date-time-month dtime) [procedure]

Returns the month of dtime.

(date-time-day dtime) [procedure]

Returns the day of dtime.

(date-time-hour dtime) [procedure]

Returns the hour of dtime.

(date-time-minute dtime) [procedure]

Returns the minute of dtime.

(date-time-second dtime) [procedure]

Returns the second of dtime.

(date-time-nano dtime) [procedure]

Returns the nano-second of dtime.

(date-time-weekday dtime) [procedure]

Returns the week day of dtime. Week days are represented as fixnums where 1 is Monday, 2 is Tuesday, …, and 7 is Sunday.

(date-time-week dtime) [procedure]

Returns the week number of dtime according to the ISO-8601 standard. Based on this standard, weeks start on Monday. The first week of the year is the week that contains that year’s first Thursday.

(date-time-dst-offset dtime) [procedure]

Returns the daylight saving time offset of dtime in seconds related to GMT. If daylight savings time is not active, `date-time-dst-offset` returns `0.0`. The result is always a floating-point number.

(date-time-hash dtime) [procedure]

Returns a hash code for the given date-time object. This hash code can be used in combination with both `date-time=?` and `date-time-same?`.

## Date-time predicates

(date-time-same? dtime1 dtime2) [procedure]

Returns `#t` if date-time dtime1 and dtime2 have the same timezone and refer to the same point in time, i.e. `(date-time->seconds dtime1)` and `(date-time->seconds dtime2)` are equals.

    (define d1 (date-time 'CET))
    (define d2 (date-time-in-timezone d1 'PST))
    (date-time-same? d1 d1)  ⇒  #t
    (date-time-same? d1 d2)  ⇒  #f
    (date-time=? d1 d2)      ⇒  #t

(date-time=? dtime1 dtime2) [procedure]

Returns `#t` if date-time dtime1 and dtime2 specify the same point in time, i.e. `(date-time->seconds dtime1)` and `(date-time->seconds dtime2)` are equals.

    (define d1 (date-time 'CET))
    (define d2 (date-time-in-timezone d1 'PST))
    (date-time=? d1 d2)                ⇒  #t
    (date-time=? d1 (date-time 'CET))  ⇒  #f

(date-time<? dtime1 dtime2) [procedure]

Returns `#t` if date-time dtime1 specifies an earlier point in time compared to dtime2, i.e. `(date-time->seconds dtime1)` is less than `(date-time->seconds dtime2)`.

(date-time>? dtime1 dtime2) [procedure]

Returns `#t` if date-time dtime1 specifies a later point in time compared to dtime2, i.e. `(date-time->seconds dtime1)` is greater than `(date-time->seconds dtime2)`.

(date-time<=? dtime1 dtime2) [procedure]

Returns `#t` if date-time dtime1 specifies an earlier or equal point in time compared to dtime2, i.e. `(date-time->seconds dtime1)` is less than or equal to `(date-time->seconds dtime2)`.

(date-time>=? dtime1 dtime2) [procedure]

Returns `#t` if date-time dtime1 specifies a later or equal point in time compared to dtime2, i.e. `(date-time->seconds dtime1)` is greater than or equal to `(date-time->seconds dtime2)`.

(date-time-has-dst? dtime) [procedure]

Returns `#t` if daylight saving time is active for dtime; returns `#f` otherwise.

## Date-time operations

(date-time-add dtime days) [procedure]
(date-time-add dtime days hrs)
(date-time-add dtime days hrs min)
(date-time-add dtime days hrs min sec)
(date-time-add dtime days hrs min sec nano)

Compute a new date-time from adding days, hrs, min, sec, and nano (all fixnums) to the given date-time dtime. The resulting date-time is using the same timezone like dtime.

(date-time-add-seconds dtime sec) [procedure]

Compute a new date-time from adding the number of seconds sec (a flonum) to the given date-time dtime.

(date-time-diff-seconds dtime1 dtime2) [procedure]

Computes the difference between dtime2 and dtime1 as a number of seconds (a flonum).

(next-dst-transition dtime) [procedure]

Returns the date and time when the next daylight savings time transition takes place after dtime. `next-dst-transition` returns `#f` if there is no daylight savings time for the time zone of dtime.