time::date+x86_64 +linux

The time::date module implements the common international Gregorian chronology, based on the astronomically numbered proleptic Gregorian calendar and the ISO week-numbering calendar, as per the ISO 8601 standard, and the common 24 hour clock. It provides date, a representation of civil date/time and a optimized extension of the time::chrono::moment type.

The time::chrono:: module has many useful functions which interoperate with dates. Any time::chrono:: function which accepts *moment also accepts *date.

Dates are created using new, now, localnow, or a "from_" function. Alternatively, the virtual+realize interface can handle indeterminate date/time information, and construct new dates incrementally and safely.

The observer functions (year, hour, etc.) evaluate a date's observed chronological values, adjusted for its associated locality. Use in to localize a date to another locality. Consult your system's timezone database using tzdb.

For working with date/time strings, see parse and format.

Date arithmetic is categorized into two:

Chronologies are irregular due to field overflows and timezone discontinuities. These effects are mitigated with zflag and rflag, which deserve careful consideration.

Index

Types

type date = struct {
	chrono::moment,
	// The [[locality]] with which to interpret this date.
	loc: locality,
	// The observed [[zonephase]]. Observe with [[zone]].
	zonephase: nullable *zonephase,
	// The observed [[daydate]] (scalar day number)
	// since an abitrary epoch (e.g. the Unix epoch 1970-01-01).
	daydate: (void | i64),
	// The observed [[daytime]] (amount of daytime progressed in a day),
	// assessed as a [[time::duration]].
	daytime: (void | i64),
	// The observed [[era]].
	era: (void | int),
	// The observed [[year]].
	year: (void | int),
	// The observed [[month]].
	month: (void | int),
	// The observed [[day]].
	day: (void | int),
	// The observed [[yearday]].
	yearday: (void | int),
	// The observed [[isoweekyear]].
	isoweekyear: (void | int),
	// The observed [[isoweek]].
	isoweek: (void | int),
	// The observed [[week]].
	week: (void | int),
	// The observed [[sundayweek]].
	sundayweek: (void | int),
	// The observed [[weekday]].
	weekday: (void | int),
	// The observed [[hour]].
	hour: (void | int),
	// The observed [[minute]].
	minute: (void | int),
	// The observed [[second]].
	second: (void | int),
	// The observed [[nanosecond]].
	nanosecond: (void | int),
};
type locality = *timezone;
type petz = struct {
	std_abbr: str,
	std_offset: time::duration,
	// empty string means no DST
	dst_abbr: str,
	dst_offset: time::duration,
	dst_startdate: petz_ruledate,
	dst_starttime: time::duration,
	dst_enddate: petz_ruledate,
	dst_endtime: time::duration,
};
type rflag = enum uint {
	DEFAULT = 0, // The default behaviour. Equivalent to CEIL.
	REVSIG = 1 << 0, // Apply units in reverse order, from least to most significant.
	// When a sub-significant overflow occurs, the unresolved field is set
	// to its minimum valid value.
	//
	//     Feb 31 -> Feb 01
	//     Aug 64 -> Aug 01
	FLOOR = 1 << 1,
	// When a sub-significant overflow occurs, the unresolved field is set
	// to its maximum valid value.
	//
	//     Feb 31 -> Feb 28 / Feb 29   (leap year dependent)
	//     Aug 64 -> Aug 31
	CEIL = 1 << 2,
	// When a sub-significant overflow occurs, the unresolved field is set
	// to its new minimum valid value after the next super-significant field
	// increments by one.
	//
	//     Feb 31 -> Mar 01
	//     Aug 64 -> Sep 01
	HOP = 1 << 3,
	// When a sub-significant overflow occurs, the unresolved field's
	// maximum valid value is subtracted from its current value, and the
	// next super-significant field increments by one. This process repeats
	// until the unresolved field's value becomes valid (falls in range).
	//
	//     Feb 31 -> Mar 03 / Mar 02   (leap year dependent)
	//     Aug 64 -> Sep 33 -> Oct 03
	FOLD = 1 << 4,
};
type span = struct {
	years: i64,
	months: i64,
	weeks: i64,
	days: i64,
	hours: i64,
	minutes: i64,
	seconds: i64,
	nanoseconds: i64,
};
type step = enum {
	NANOSECOND = 1,
	SECOND = 2,
	MINUTE = 4,
	HOUR = 8,
	DAY = 16,
	WEEK = 32,
	MONTH = 64,
	YEAR = 128,
	ERA = 256,
};
type timezone = struct {
	// The base timescale (e.g. time::chrono::utc).
	tsc: *chrono::timescale,
	// The textual identifier (e.g. "Europe/Amsterdam").
	name: str,
	// The duration of a day in this timezone (e.g. 24 * time::HOUR).
	daylength: time::duration,
	// The possible zonephases a locality with this timezone can observe
	// (e.g. CET, CEST, ...).
	phases: []zonephase,
	// The transitions between this timezone's zonephases.
	transitions: []zonetransition,
	// The function to calculate the correct [[zonephase]] to observe.
	// If null, defaults to an internal function.
	lookupzone: nullable *zonelookuper,
	// Used for extending calculations beyond the last known transition.
	// See [[petz]].
	petz: petz,
};
type virtual = struct {
	date,
	// The virtual date's timescalar second.
	vsec: (void | i64),
	// The virtual date's nanosecond of the timescalar second.
	vnsec: (void | i64),
	// The virtual date's [[locality]].
	vloc: (void | locality),
	// The [[locality]]'s name.
	locname: (void | str),
	// The zone-offset. See [[zflag]] for its effects in [[realize]].
	zoff: (void | time::duration | zflag),
	// The zone-abbreviation.
	zabbr: (void | str),
	// The century; all but the last two digits of the year.
	century: (void | int),
	// The last two digits of the year; the year modulo 100.
	year100: (void | int),
	// The hour of a 12 hour clock; the hour modulo 12.
	hour12: (void | int),
	// The meridiem indicator (false=AM, true=PM).
	ampm: (void | bool),
};
type zflag = enum u8 {
	// Assume a contiguous chronology with no observed gaps or overlaps.
	// Upon encountering an observed gap or overlap, fail with [[invalid]].
	// In other words, accept one and only one zone-offset.
	CONTIG = 0,
	// Upon encountering an observed overlap, select the earliest possible
	// date (Fig A "f") using the most positive (eastmost) zone-offset.
	LAP_EARLY = 1,
	// Upon encountering an observed overlap, select the latest possible
	// date (Fig A "g") using the most negative (westmost) zone-offset.
	LAP_LATE = 2,
	// Upon encountering an observed gap, disregard the intermediate date
	// and select the date at the observed gap's start-boundary
	// (Fig B "gp"), corresponding to the contiguous time just before the
	// transition (Fig B "tx").
	GAP_START = 4,
	// Upon encountering an observed gap, disregard the intermediate date
	// and select the date at the observed gap's end-boundary (Fig B "gq"),
	// corresponding to the contiguous time at the transition (Fig B "tx").
	GAP_END = 8,
};
type zonelookuper = fn(locality, *date) *zonephase;
type zonephase = struct {
	// The offset from the normal timezone (e.g. 2 * time::HOUR).
	zoff: time::duration,
	// The full descriptive name (e.g. "Central European Summer Time").
	name: str,
	// The abbreviated name (e.g. "CEST").
	abbr: str,
	// Indicator of Daylight Saving Time.
	dst: bool,
};
type zonetransition = struct {
	when: time::instant,
	zoneindex: size,
};

// Undocumented types:
type petz_ruledate = (petz_ruledate_julian | petz_ruledate_ordinal | petz_ruledate_weekdate);
type petz_ruledate_julian = i16;
type petz_ruledate_ordinal = i16;
type petz_ruledate_weekdate = (u8, u8, u8);
type zferror = enum {
	GAP,
	LAP,
};

Errors

type error = !(invalid | insufficient | zfunresolved | parsefail | invalidtzif | tzdberror | chrono::tscmismatch);
type insufficient = !void;
type invalid = !void;
type invalidpetzstr = !void;
type invalidtzif = !void;
type parsefail = !(size, rune);
type tzdberror = !(invalidtzif | fs::error | io::error);
type zfunresolved = !zferror;

Constants

def APRIL: int = 4;
def AUGUST: int = 8;
def DECEMBER: int = 12;
def EARTH_DAY: time::duration = 86400 * time::SECOND;
def EMAIL: str = "%a, %d %b %Y %H:%M:%S %z";
def EMAILZONE: str = "%a, %d %b %Y %H:%M:%S %z %Z";
def EPOCHDAY_GREGORIAN: i64 = -719164;
def EPOCHDAY_JULIAN: i64 = -2440588;
def FEBRUARY: int = 2;
def FRIDAY: int = 4;
def ISOWKSTAMP: str = "%G-W%V-%u %H:%M:%S";
def JANUARY: int = 1;
def JOURNAL: str = "%Y %b %d, %a %H:%M:%S %z %Z %L";
def JULY: int = 7;
def JUNE: int = 6;
def LOCALTIME_PATH: str = "/etc/localtime";
def MARCH: int = 3;
def MARS_SOL_MARTIAN: time::duration = 86400 * time::SECOND;
def MARS_SOL_TERRESTRIAL: time::duration = 88775244147000 * time::NANOSECOND;
def MAY: int = 5;
def MONDAY: int = 0;
def NOVEMBER: int = 11;
def OCTOBER: int = 10;
def POSIX: str = "%a %b %e %H:%M:%S %Y";
def QUARTZ: str = "%s.%N";
def QUARTZLOC: str = "%s.%N:%L";
def QUARTZZOFF: str = "%s.%N%z";
def RFC3339: str = "%Y-%m-%dT%H:%M:%S%z";
def SATURDAY: int = 5;
def SEPTEMBER: int = 9;
def STAMP: str = "%Y-%m-%d %H:%M:%S";
def STAMPLOC: str = "%Y-%m-%d %H:%M:%S.%N %z %Z %L";
def STAMPNANO: str = "%Y-%m-%d %H:%M:%S.%N";
def STAMPZOFF: str = "%Y-%m-%d %H:%M:%S.%N %z";
def STAMPZONE: str = "%Y-%m-%d %H:%M:%S.%N %z %Z";
def SUNDAY: int = 6;
def THURSDAY: int = 3;
def TUESDAY: int = 1;
def TZDB_PATH: str = "/usr/share/zoneinfo";
def WEDNESDAY: int = 2;
def WRIST: str = "%b-%d %a %H:%M %Z";

Globals

const GPS: locality;
const LOCAL: locality;
const MTC: locality;
const TAI: locality;
const TT: locality;
const UTC: locality;

Functions

fn abs(x: span) span;
fn add(d: date, x: time::duration) date;
fn asformat(layout: str, d: *date) (str | io::error);
fn bsformat(buf: []u8, layout: str, d: *date) (str | io::error);
fn coincident(a: *date, b: *date) bool;
fn day(d: *date) int;
fn daydate(d: *date) i64;
fn daytime(d: *date) i64;
fn equalspan(x: span, y: span) bool;
fn era(d: *date) int;
fn fixedzone(tsc: *chrono::timescale, name: str, daylen: time::duration, z: zonephase) *timezone;
fn format(h: io::handle, layout: str, d: *date) (size | io::error);
fn formatspan(s: span, sep: rune = ' ') str;
fn from_datetime(loc: locality, zo: time::duration, dd: i64, dt: i64) date;
fn from_instant(loc: locality, t: time::instant) date;
fn from_moment(loc: locality, m: chrono::moment) (date | chrono::tscmismatch);
fn from_str(layout: str, s: str, locs: locality...) (date | parsefail | insufficient | invalid);
fn hop(a: date, b: date, u: step) i64;
fn hour(d: *date) int;
fn in(loc: locality, d: date) (date | chrono::tscmismatch);
fn isleapyear(y: int) bool;
fn isoweek(d: *date) int;
fn isoweekyear(d: *date) int;
fn load_tzif(h: io::handle, tz: *timezone) (void | invalidtzif | io::error);
fn localnow() date;
fn minute(d: *date) int;
fn month(d: *date) int;
fn nanosecond(d: *date) int;
fn neg(x: span) span;
fn new(loc: locality, zoff: (time::duration | zflag), fields: int...) (date | invalid | zfunresolved);
fn newvirtual() virtual;
fn now() date;
fn parse(v: *virtual, layout: str, info: str) (void | parsefail);
fn realize(v: virtual, locs: locality...) (date | insufficient | invalid | zfunresolved);
fn reckon(d: date, zoff: (time::duration | zflag), rf: rflag, spans: span...) (date | invalid | zfunresolved);
fn second(d: *date) int;
fn strerror(err: error) const str;
fn sum(spans: span...) span;
fn sundayweek(d: *date) int;
fn timezone_free(tz: *timezone) void;
fn to_instant(d: date) time::instant;
fn to_moment(d: date) chrono::moment;
fn traverse(a: date, b: date) span;
fn truncate(d: date, zf: zflag, u: step) (date | invalid | zfunresolved);
fn tzdb(tzid: str) (locality | tzdberror);
fn week(d: *date) int;
fn weekday(d: *date) int;
fn year(d: *date) int;
fn yearday(d: *date) int;
fn zone(d: *date) zonephase;
fn zone_finish(z: *zonephase) void;

Types

type date[link]

type date = struct {
	chrono::moment,
	// The [[locality]] with which to interpret this date.
	loc: locality,
	// The observed [[zonephase]]. Observe with [[zone]].
	zonephase: nullable *zonephase,
	// The observed [[daydate]] (scalar day number)
	// since an abitrary epoch (e.g. the Unix epoch 1970-01-01).
	daydate: (void | i64),
	// The observed [[daytime]] (amount of daytime progressed in a day),
	// assessed as a [[time::duration]].
	daytime: (void | i64),
	// The observed [[era]].
	era: (void | int),
	// The observed [[year]].
	year: (void | int),
	// The observed [[month]].
	month: (void | int),
	// The observed [[day]].
	day: (void | int),
	// The observed [[yearday]].
	yearday: (void | int),
	// The observed [[isoweekyear]].
	isoweekyear: (void | int),
	// The observed [[isoweek]].
	isoweek: (void | int),
	// The observed [[week]].
	week: (void | int),
	// The observed [[sundayweek]].
	sundayweek: (void | int),
	// The observed [[weekday]].
	weekday: (void | int),
	// The observed [[hour]].
	hour: (void | int),
	// The observed [[minute]].
	minute: (void | int),
	// The observed [[second]].
	second: (void | int),
	// The observed [[nanosecond]].
	nanosecond: (void | int),
};

A "datetime" object, optimized for the Gregorian chronology. All instantiated dates are valid, pertain to a locality, and directly convertible to a time::chrono::moment or time::instant.

A date observes various chronological values, which are cached in its "observer" fields. To evaluate and obtain these values, use the various observer functions, documented inline.

Unless interfaced via a virtual, dates should be treated as immutable. Mutating or interrogating fields directly results in undefined behaviour.

type locality[link]

type locality = *timezone;

The locality of a date. Contains information about how to calculate a moment's observed chronological values.

type petz[link]

type petz = struct {
	std_abbr: str,
	std_offset: time::duration,
	// empty string means no DST
	dst_abbr: str,
	dst_offset: time::duration,
	dst_startdate: petz_ruledate,
	dst_starttime: time::duration,
	dst_enddate: petz_ruledate,
	dst_endtime: time::duration,
};

A POSIX "extending timezone" of the "TZ" environment variable format. Used for extending calculations beyond the last known transition.

Example PETZ in string form: "CET-1CEST,M3.5.0,M10.5.0/3".

type rflag[link]

type rflag = enum uint {
	DEFAULT = 0, // The default behaviour. Equivalent to CEIL.
	REVSIG = 1 << 0, // Apply units in reverse order, from least to most significant.
	// When a sub-significant overflow occurs, the unresolved field is set
	// to its minimum valid value.
	//
	//     Feb 31 -> Feb 01
	//     Aug 64 -> Aug 01
	FLOOR = 1 << 1,
	// When a sub-significant overflow occurs, the unresolved field is set
	// to its maximum valid value.
	//
	//     Feb 31 -> Feb 28 / Feb 29   (leap year dependent)
	//     Aug 64 -> Aug 31
	CEIL = 1 << 2,
	// When a sub-significant overflow occurs, the unresolved field is set
	// to its new minimum valid value after the next super-significant field
	// increments by one.
	//
	//     Feb 31 -> Mar 01
	//     Aug 64 -> Sep 01
	HOP = 1 << 3,
	// When a sub-significant overflow occurs, the unresolved field's
	// maximum valid value is subtracted from its current value, and the
	// next super-significant field increments by one. This process repeats
	// until the unresolved field's value becomes valid (falls in range).
	//
	//     Feb 31 -> Mar 03 / Mar 02   (leap year dependent)
	//     Aug 64 -> Sep 33 -> Oct 03
	FOLD = 1 << 4,
};

Specifies the behaviour of reckon when doing chronological arithmetic.

The FLOOR, CEIL, HOP, and FOLD specifies how to resolve sub-significant overflows -- when a field's change in value causes any sub-significant field's range to shrink below its current value and become invalid. For example, adding 1 month to January 31st results in February 31st, a date with an unresolved day field, since February permits only 28 or 29 days.

type span[link]

type span = struct {
	years: i64,
	months: i64,
	weeks: i64,
	days: i64,
	hours: i64,
	minutes: i64,
	seconds: i64,
	nanoseconds: i64,
};

Represents a span of time in the Gregorian chronology; a set of nominal periods of time. Used for chronological arithmetic.

type step[link]

type step = enum {
	NANOSECOND = 1,
	SECOND = 2,
	MINUTE = 4,
	HOUR = 8,
	DAY = 16,
	WEEK = 32,
	MONTH = 64,
	YEAR = 128,
	ERA = 256,
};

Nominal unitary periods of the Gregorian chronology. Used for chronological arithmetic.

type timezone[link]

type timezone = struct {
	// The base timescale (e.g. time::chrono::utc).
	tsc: *chrono::timescale,
	// The textual identifier (e.g. "Europe/Amsterdam").
	name: str,
	// The duration of a day in this timezone (e.g. 24 * time::HOUR).
	daylength: time::duration,
	// The possible zonephases a locality with this timezone can observe
	// (e.g. CET, CEST, ...).
	phases: []zonephase,
	// The transitions between this timezone's zonephases.
	transitions: []zonetransition,
	// The function to calculate the correct [[zonephase]] to observe.
	// If null, defaults to an internal function.
	lookupzone: nullable *zonelookuper,
	// Used for extending calculations beyond the last known transition.
	// See [[petz]].
	petz: petz,
};

A timezone; a political or otherwise theoretical region with a ruleset regarding offsets for calculating localized date/time.

type virtual[link]

type virtual = struct {
	date,
	// The virtual date's timescalar second.
	vsec: (void | i64),
	// The virtual date's nanosecond of the timescalar second.
	vnsec: (void | i64),
	// The virtual date's [[locality]].
	vloc: (void | locality),
	// The [[locality]]'s name.
	locname: (void | str),
	// The zone-offset. See [[zflag]] for its effects in [[realize]].
	zoff: (void | time::duration | zflag),
	// The zone-abbreviation.
	zabbr: (void | str),
	// The century; all but the last two digits of the year.
	century: (void | int),
	// The last two digits of the year; the year modulo 100.
	year100: (void | int),
	// The hour of a 12 hour clock; the hour modulo 12.
	hour12: (void | int),
	// The meridiem indicator (false=AM, true=PM).
	ampm: (void | bool),
};

A virtual date of undetermined validity; a date wrapper interface. It is meant as an intermediary container for date information to be resolved with the realize function.

A virtual date's "observer" fields (including that of the embedded date) should be treated as writable. The realize function takes into account all these fields, except for the embedded time::chrono::moment and locality fields (.sec .nsec .tsc .loc).

This can be used to safely construct a new date piece-by-piece. Start with newvirtual, then collect enough date/time information incrementally by direct field assignments and/or with parse. Finish with realize.

let v = date::newvirtual();
v.vloc = chrono::tz("Europe/Amsterdam")!;
v.zoff = date::zflag::LAP_EARLY | date::zflag::GAP_END;
date::parse(&v, "Date: %Y-%m-%d", "Date: 2000-01-02")!;
v.hour = 15;
v.minute = 4;
v.second = 5;
v.nanosecond = 600000000;
let d = date::realize(v)!;

Virtual date behaviour with the observer functions is undefined.

type zflag[link]

type zflag = enum u8 {
	// Assume a contiguous chronology with no observed gaps or overlaps.
	// Upon encountering an observed gap or overlap, fail with [[invalid]].
	// In other words, accept one and only one zone-offset.
	CONTIG = 0,
	// Upon encountering an observed overlap, select the earliest possible
	// date (Fig A "f") using the most positive (eastmost) zone-offset.
	LAP_EARLY = 1,
	// Upon encountering an observed overlap, select the latest possible
	// date (Fig A "g") using the most negative (westmost) zone-offset.
	LAP_LATE = 2,
	// Upon encountering an observed gap, disregard the intermediate date
	// and select the date at the observed gap's start-boundary
	// (Fig B "gp"), corresponding to the contiguous time just before the
	// transition (Fig B "tx").
	GAP_START = 4,
	// Upon encountering an observed gap, disregard the intermediate date
	// and select the date at the observed gap's end-boundary (Fig B "gq"),
	// corresponding to the contiguous time at the transition (Fig B "tx").
	GAP_END = 8,
};

Flags for resolving undetermined zone-offsets. Handles timezone transitions.

The realize function, as well as other date creation functions (e.g. new, truncate, reckon) accept zflags in place of a numerical zone-offset. If zflags are provided, these functions first calculate an intermediate date with a reasonable numerical zone-offset, usually some preexisting one or a best guess using some locality.

This intermediate date can be invalid if it falls within the observed gap or overlap of a timezone transition, where such dates are ambiguous or nonexistent. In this case, the provided zflags are consulted, and a final adjustment takes place before the final resultant date with a new zone-offset (or zfunresolved) is returned.

Timezone transitions create gaps and overlaps, the two causes of invalid intermediate dates. Passing one "GAP_" and one "LAP_" flag covers both cases.

let zf = date::zflag::LAP_EARLY | date::zflag::GAP_END;
date::new(loc, zf, fields...)!; // will never return [[zfunresolved]]

Note, "GAP_" flags will cause the resultant date to be different to the intermediate date if it falls within a gap.

Flags with greater value take precedent.

The following figures exist to help understand the effect of these flags.

Fig A                    2000 October 29th
                              -1 hour

                                 f=02:30+0200
                                 g=02:30+0100
                             lp  | lq
                 +0200        |  |  |       +0100
  Observed time: 00    01    02  | 03    04    05
      Amsterdam:  |-----|-----|==*==|-----|-----|
                  .     .     .\ :: |.     .
                  .     .     . \: :| .     .
                  .     .     .  :  :  .     .
                  .     .     .  :\ |:  .     .
                  .     .     .  : \| :  .     .
            UTC:  |-----|-----|--*--|--*--|-----|
Contiguous time: 22    23    00  | 01  | 02    03
                                 |  |  |
                                 a tx  b

Fig A -- A backjump timezone transition in the Europe/Amsterdam locality. The transition is marked by "tx". There is an overlap in the chronology, marked by "lp" and "lq". The specified local time 02:30 falls within the observed overlap, and so has two valid zone-offsets and can be observed twice, as dates "f" and "g". When localized to UTC, these two observations correspond to UTC dates "a" and "b" respectively.

Fig B                     2000 March 26th
                              +1 hour

                                 f~02:30+!!!!
                             gp  | gq
                 +0100        |  |  |       +0200
  Observed time: 00    01    02  | 03    04    05
      Amsterdam:  |-----|-----|  *  |-----|-----|
                  .     .     |    /     .     .
                  .     .     |   /     .     .
                  .     .     |  /     .     .
                  .     .     | /     .     .
                  .     .     |/     .     .
            UTC:  |-----|-----|-----|-----|-----|
Contiguous time: 23    00    01    02    03    04
                              |
                             tx

Fig B -- A forejump timezone transition in the Europe/Amsterdam locality. The transition is marked by "tx". There is a gap in the chronology, marked by "gp" and "gq". The specified local time 02:30 falls within the observed gap, and so cannot be observed and is invalid.

type zonelookuper[link]

type zonelookuper = fn(locality, *date) *zonephase;

Determines the correct zonephase to observe for a given date.

type zonephase[link]

type zonephase = struct {
	// The offset from the normal timezone (e.g. 2 * time::HOUR).
	zoff: time::duration,
	// The full descriptive name (e.g. "Central European Summer Time").
	name: str,
	// The abbreviated name (e.g. "CEST").
	abbr: str,
	// Indicator of Daylight Saving Time.
	dst: bool,
};

A timezone state, with an offset for calculating localized date/time.

type zonetransition[link]

type zonetransition = struct {
	when: time::instant,
	zoneindex: size,
};

A timezone transition between two zonephases.

type petz_ruledate[link]

Show undocumented member
type petz_ruledate = (petz_ruledate_julian | petz_ruledate_ordinal | petz_ruledate_weekdate);

type petz_ruledate_julian[link]

Show undocumented member
type petz_ruledate_julian = i16;

type petz_ruledate_ordinal[link]

Show undocumented member
type petz_ruledate_ordinal = i16;

type petz_ruledate_weekdate[link]

Show undocumented member
type petz_ruledate_weekdate = (u8, u8, u8);

type zferror[link]

Show undocumented member
type zferror = enum {
	GAP,
	LAP,
};

Errors

type error[link]

type error = !(invalid | insufficient | zfunresolved | parsefail | invalidtzif | tzdberror | chrono::tscmismatch);

All possible errors returned from this module.

type insufficient[link]

type insufficient = !void;

A virtual date does not have enough information from which to create a valid date.

type invalid[link]

type invalid = !void;

Invalid date.

type invalidpetzstr[link]

type invalidpetzstr = !void;

Invalid POSIX extending TZ string.

type invalidtzif[link]

type invalidtzif = !void;

Invalid TZif data.

type parsefail[link]

type parsefail = !(size, rune);

A parsing error occurred. This shall contain a byteindex of and rune from the layout at the position where the parsing error occured.

type tzdberror[link]

type tzdberror = !(invalidtzif | fs::error | io::error);

Error concerning the Timezone database.

type zfunresolved[link]

type zfunresolved = !zferror;

Failed to resolve an absent zone-offset. The provided zflags failed to account for some timezone effect and could not produce a valid zone-offset.

Constants

def APRIL[link]

def APRIL: int = 4;

Ordinal for the month of April.

def AUGUST[link]

def AUGUST: int = 8;

Ordinal for the month of August.

def DECEMBER[link]

def DECEMBER: int = 12;

Ordinal for the month of December.

def EARTH_DAY[link]

def EARTH_DAY: time::duration = 86400 * time::SECOND;

The duration of a day on Earth, in terrestrial (SI) seconds.

def EMAIL[link]

def EMAIL: str = "%a, %d %b %Y %H:%M:%S %z";

format layout for the email date format.

def EMAILZONE[link]

def EMAILZONE: str = "%a, %d %b %Y %H:%M:%S %z %Z";

format layout for the email date format, with zone offset and zone abbreviation.

def EPOCHDAY_GREGORIAN[link]

def EPOCHDAY_GREGORIAN: i64 = -719164;

The Hare epochal day of the Gregorian Common Era.

def EPOCHDAY_JULIAN[link]

def EPOCHDAY_JULIAN: i64 = -2440588;

The Hare epochal day of the Julian Day Number.

def FEBRUARY[link]

def FEBRUARY: int = 2;

Ordinal for the month of February.

def FRIDAY[link]

def FRIDAY: int = 4;

Ordinal for the weekday Friday.

def ISOWKSTAMP[link]

def ISOWKSTAMP: str = "%G-W%V-%u %H:%M:%S";

format layout for an ISO week-numbering timestamp.

def JANUARY[link]

def JANUARY: int = 1;

Ordinal for the month of January.

def JOURNAL[link]

def JOURNAL: str = "%Y %b %d, %a %H:%M:%S %z %Z %L";

format layout for a friendly, comprehensive datetime.

def JULY[link]

def JULY: int = 7;

Ordinal for the month of July.

def JUNE[link]

def JUNE: int = 6;

Ordinal for the month of June.

def LOCALTIME_PATH[link]

def LOCALTIME_PATH: str = "/etc/localtime";

The filepath of the system's "localtime" file, typically a symlink to a TZif file under TZDB_PATH.

def MARCH[link]

def MARCH: int = 3;

Ordinal for the month of March.

def MARS_SOL_MARTIAN[link]

def MARS_SOL_MARTIAN: time::duration = 86400 * time::SECOND;

The duration of a solar day on Mars, in Martian seconds.

def MARS_SOL_TERRESTRIAL[link]

def MARS_SOL_TERRESTRIAL: time::duration = 88775244147000 * time::NANOSECOND;

The duration of a solar day on Mars, in terrestrial (SI) seconds.

def MAY[link]

def MAY: int = 5;

Ordinal for the month of May.

def MONDAY[link]

def MONDAY: int = 0;

Ordinal for the weekday Monday.

def NOVEMBER[link]

def NOVEMBER: int = 11;

Ordinal for the month of November.

def OCTOBER[link]

def OCTOBER: int = 10;

Ordinal for the month of October.

def POSIX[link]

def POSIX: str = "%a %b %e %H:%M:%S %Y";

format layout for the POSIX locale's default date & time representation.

def QUARTZ[link]

def QUARTZ: str = "%s.%N";

format layout for a precise timescalar second and nanosecond.

def QUARTZLOC[link]

def QUARTZLOC: str = "%s.%N:%L";

format layout for a precise timescalar second, nanosecond, and locality.

def QUARTZZOFF[link]

def QUARTZZOFF: str = "%s.%N%z";

format layout for a precise timescalar second, nanosecond, and zone offset.

def RFC3339[link]

def RFC3339: str = "%Y-%m-%dT%H:%M:%S%z";

format layout compatible with RFC 3339.

def SATURDAY[link]

def SATURDAY: int = 5;

Ordinal for the weekday Saturday.

def SEPTEMBER[link]

def SEPTEMBER: int = 9;

Ordinal for the month of September.

def STAMP[link]

def STAMP: str = "%Y-%m-%d %H:%M:%S";

format layout for a standard, collatable timestamp.

def STAMPLOC[link]

def STAMPLOC: str = "%Y-%m-%d %H:%M:%S.%N %z %Z %L";

format layout for a standard, collatable timestamp with nanoseconds, zone offset, zone abbreviation, and locality.

def STAMPNANO[link]

def STAMPNANO: str = "%Y-%m-%d %H:%M:%S.%N";

format layout for a standard, collatable timestamp with nanoseconds.

def STAMPZOFF[link]

def STAMPZOFF: str = "%Y-%m-%d %H:%M:%S.%N %z";

format layout for a standard, collatable timestamp with nanoseconds and zone offset.

def STAMPZONE[link]

def STAMPZONE: str = "%Y-%m-%d %H:%M:%S.%N %z %Z";

format layout for a standard, collatable timestamp with nanoseconds, zone offset, and zone abbreviation.

def SUNDAY[link]

def SUNDAY: int = 6;

Ordinal for the weekday Sunday.

def THURSDAY[link]

def THURSDAY: int = 3;

Ordinal for the weekday Thursday.

def TUESDAY[link]

def TUESDAY: int = 1;

Ordinal for the weekday Tuesday.

def TZDB_PATH[link]

def TZDB_PATH: str = "/usr/share/zoneinfo";

The filepath of the system's TZDB (Timezone Database) directory, a filetree of TZif (Time Zone Information Format) files and other related files.

def WEDNESDAY[link]

def WEDNESDAY: int = 2;

Ordinal for the weekday Wednesday.

def WRIST[link]

def WRIST: str = "%b-%d %a %H:%M %Z";

format layout for a friendly, terse datetime.

Globals

let GPS[link]

const GPS: locality;

The GPS (Global Positioning System) "Zulu" timezone as a locality. Uses the time::chrono::gps timescale.

let LOCAL[link]

const LOCAL: locality;

The local locality; the system or environment configured timezone.

This is set during the program's initialization. In order of preference, the TZ environment variable is used, if set; the file at LOCALTIME_PATH, if present; or, as a last resort, UTC is used as a default.

let MTC[link]

const MTC: locality;

The MTC (Coordinated Mars Time) "Zulu" timezone as a locality. Uses the time::chrono::mtc timescale.

let TAI[link]

const TAI: locality;

The TAI (International Atomic Time) "Zulu" timezone as a locality. Uses the time::chrono::tai timescale.

let TT[link]

const TT: locality;

The TT (Terrestrial Time) "Zulu" timezone as a locality. Uses the time::chrono::tt timescale.

let UTC[link]

const UTC: locality;

The UTC (Coordinated Universal Time) "Zulu" timezone as a locality. Uses the time::chrono::utc timescale.

Functions

fn abs[link]

fn abs(x: span) span;

Returns a span with its fields made absolute and positive.

fn add[link]

fn add(d: date, x: time::duration) date;

Adds a time::duration to a date with time::add. This is a timescalar aritmetic operation.

See reckon.

fn asformat[link]

fn asformat(layout: str, d: *date) (str | io::error);

Formats a date and writes it into a heap-allocated string. The caller must free the return value.

fn bsformat[link]

fn bsformat(buf: []u8, layout: str, d: *date) (str | io::error);

Formats a date and writes it into a caller supplied buffer. The returned string is borrowed from this buffer.

fn coincident[link]

fn coincident(a: *date, b: *date) bool;

Returns true if two dates represent the same time in the same locality, which is to say that their locality and time::instant are both equal. Their observed chronological values should be the same in all cases.

See time::chrono::compare.

fn day[link]

fn day(d: *date) int;

Observes a date's day of the month. Range 1 to 31.

fn daydate[link]

fn daydate(d: *date) i64;

Observes a date's observed daydate (day number since epoch).

For dates with a locality based on the UTC, TAI, GPS, and similar time::chrono::timescales, their epoch date should be interpreted as the Unix epoch (1970 Janurary 1st). Other timescales may suggest their own interpretations applicable to other chronologies.

fn daytime[link]

fn daytime(d: *date) i64;

Observes a date's observed time-of-day (amount of daytime progressed in a day) as nanoseconds.

fn equalspan[link]

fn equalspan(x: span, y: span) bool;

Returns true if two spans are numerically equal, false otherwise.

fn era[link]

fn era(d: *date) int;

Observes a date's era.

fn fixedzone[link]

fn fixedzone(tsc: *chrono::timescale, name: str, daylen: time::duration, z: zonephase) *timezone;

Creates a timezone with a single zonephase. Useful for fixed offsets. The caller must free the return value with timezone_free. An example, replicate the civil time Hawaii timezone on Earth:

let hawaii = chrono::fixedzone(
	&chrono::utc,
	"Custom/Hawaiian_Reef",
	chrono::EARTH_DAY,
	chrono::zonephase {
		zoff = -10 * time::HOUR,
		abbr = "HARE",
		dst = false,
		...
	},
);

fn format[link]

fn format(h: io::handle, layout: str, d: *date) (size | io::error);

Formats a date according to a layout and writes to an io::handle.

The layout may contain any of the following format specifiers listed below. These specifiers emit 2 digit zero-padded decimals unless stated otherwise. Use of unimplemented specifiers or an invalid layout will cause an abort.

fn formatspan[link]

fn formatspan(s: span, sep: rune = ' ') str;

Formats a span and writes it into an internal static buffer. The returned string is borrowed from this buffer. The following layout is used:

"?Y ?M ?W ?D ?h ?m ?s ?n"

where each '?' is replaced with the appopriate span field values in order of decreasing significance, and the inbetween spaces are replaced with the given sep argument.

fn from_datetime[link]

fn from_datetime(loc: locality, zo: time::duration, dd: i64, dt: i64) date;

Creates a date from a given locality, zone-offset, daydate, and time-of-day.

fn from_instant[link]

fn from_instant(loc: locality, t: time::instant) date;

Creates a date from a time::instant in a locality.

fn from_moment[link]

fn from_moment(loc: locality, m: chrono::moment) (date | chrono::tscmismatch);

Creates a date from a time::chrono::moment.

time::chrono::tscmismatch is returned if the time::chrono::timescales of the moment and the target locality are different.

fn from_str[link]

fn from_str(layout: str, s: str, locs: locality...) (date | parsefail | insufficient | invalid);

Creates a date from a string, parsed according to a layout format. See parse and format. Example:

let new = date::from_str(
	date::STAMPLOC,
	"2000-01-02 15:04:05.600000000 +0100 CET Europe/Amsterdam",
	chrono::tz("Europe/Amsterdam")!
)!;

At least a complete calendar date has to be provided. If the hour, minute, second, or nanosecond values are not provided, they default to 0. If the zone-offset or zone-abbreviation are not provided, the zflags LAP_EARLY and GAP_END are used.

The date's locality will be selected from the provided locality arguments. The 'name' field of these localities will be matched against the parsed result of the %L specifier. If %L is not specified, or if no locality is provided, UTC is used.

fn hop[link]

fn hop(a: date, b: date, u: step) i64;

Calculates the nominal step difference between two dates.

Be aware, using date of different localitys may return unexpected results.

fn hour[link]

fn hour(d: *date) int;

Observes a date's hour of the day.

fn in[link]

fn in(loc: locality, d: date) (date | chrono::tscmismatch);

Creates a simultaneous date with a different locality.

time::chrono::tscmismatch is returned if the time::chrono::timescales of the given moment and the target locality are different.

fn isleapyear[link]

fn isleapyear(y: int) bool;

Calculates whether a year is a leap year.

fn isoweek[link]

fn isoweek(d: *date) int;

Observes a date's ISO week-numbering week. Range 0 to 53.

fn isoweekyear[link]

fn isoweekyear(d: *date) int;

Observes a date's ISO week-numbering year.

fn load_tzif[link]

fn load_tzif(h: io::handle, tz: *timezone) (void | invalidtzif | io::error);

Loads TZif (Time Zone Information Format) data onto a given timezone, initializing the fields ".phases", ".transitions", and ".petz".

Refer to "RFC 8536" for the TZif format.

fn localnow[link]

fn localnow() date;

Returns a date of the current system time using time::clock::REALTIME, in the LOCAL locality.

fn minute[link]

fn minute(d: *date) int;

Observes a date's minute of the hour.

fn month[link]

fn month(d: *date) int;

Observes a date's month of the year. Range January=1 to December=12.

fn nanosecond[link]

fn nanosecond(d: *date) int;

Observes a date's nanosecond of the second.

fn neg[link]

fn neg(x: span) span;

Returns a span with its fields negated.

fn new[link]

fn new(loc: locality, zoff: (time::duration | zflag), fields: int...) (date | invalid | zfunresolved);

Creates a new date. Accepts a locality, a zone-offset, and up to seven chronological fields applied in the following order:

8 or more fields causes an abort. If omitted, the month and day default to 1, and the rest default to 0.

If the desired zone-offset is known, it can be given as a time::duration. Otherwise, use a zflag. See zflag on its effects to the result.

An invalid combination of provided date/time/zoff values returns invalid.

Examples:

// 0000-01-01 00:00:00.000000000 +0000 UTC UTC
date::new(date::UTC, date::zflag::CONTIG);

// 2000-01-02 15:04:05.600000000 +0000 UTC UTC
date::new(date::UTC, 0,
	2000,  1,  2,  15,  4,  5, 600000000);

// 2000-01-02 15:00:00.000000000 +0100 CET Europe/Amsterdam
date::new(date::tzdb("Europe/Amsterdam")!,
	1 * time::HOUR, // standard time in January
	2000,  1,  2,  15);

// Could return [[zfunresolved]] by encountering a timezone transition.
date::new(date::tzdb("Europe/Amsterdam")!,
	date::zflag::CONTIG,
	fields...);

// Will never return [[zfunresolved]].
date::new(date::tzdb("Europe/Amsterdam")!,
	date::zflag::LAP_EARLY | date::zflag::GAP_END,
	fields...);

// On this day in Amsterdam, the clock jumped +1 hour at 02:00.
// 02:30 is never observed. Note the difference in zone-offset.
//
// 2000-03-26 01:59:59.999999999 +0100 CET Europe/Amsterdam
date::new(date::tzdb("Europe/Amsterdam")!,
	date::zflag::GAP_START,
	2000,  3, 26,   2, 30);
//
// 2000-03-26 03:00:00.000000000 +0200 CET Europe/Amsterdam
date::new(date::tzdb("Europe/Amsterdam")!,
	date::zflag::GAP_END,
	2000,  3, 26,   2, 30);

// On this day in Amsterdam, the clock jumped -1 hour at 03:00.
// 02:30 is observed twice. Note the difference in zone-offset.
//
// 2000-10-29 02:30:00.000000000 +0200 CET Europe/Amsterdam
date::new(date::tzdb("Europe/Amsterdam")!,
	date::zflag::LAP_EARLY,
	2000, 10, 29,   2, 30);
//
// 2000-10-29 02:30:00.000000000 +0100 CET Europe/Amsterdam
date::new(date::tzdb("Europe/Amsterdam")!,
	date::zflag::LAP_LATE,
	2000, 10, 29,   2, 30);

fn newvirtual[link]

fn newvirtual() virtual;

Creates a new virtual date. All its fields are voided or nulled.

fn now[link]

fn now() date;

Returns a date of the current system time using time::clock::REALTIME, in the UTC locality.

fn parse[link]

fn parse(v: *virtual, layout: str, info: str) (void | parsefail);

Parses date information from a string into a virtual date, according to a layout with specifiers as documented under format. Partial, sequential, aggregative parsing is possible.

date::parse(&v, "%Y-%m-%d",    "2019-12-27");
date::parse(&v, "%H:%M:%S.%N", "22:07:08.000000000");
date::parse(&v, "%z %Z %L",    "+0100 CET Europe/Amsterdam");

Parse will return parsefail if an invalid layout format specifier is encountered or if given info string does not match the layout.

fn realize[link]

fn realize(v: virtual, locs: locality...) (date | insufficient | invalid | zfunresolved);

Realizes a valid date from a virtual date, or fails appropriately.

The virtual date must hold enough valid date information to calculate a resulting date. A valid combination of "inputs" (filled in, non-void fields) must be provided. For example:

let v = date::newvirtual();
v.locname = "Europe/Amsterdam";
v.zoff = date::zflag::LAP_EARLY | date::zflag::GAP_END;
date::parse(&v, // fills-in .year .month .day
	"Date: %Y-%m-%d", "Date: 2038-01-19")!;
v.hour = 4;
v.minute = 14;
v.second = 7;
v.nanosecond = 0;
let d = date::realize(v, date::tzdb("Europe/Amsterdam")!)!;

A fixed algorithm is used to ascertain the given input combination. Combinations are attempted in a particular order listed below. Inputs marked with '*' can be substituted with further combinations. The algorithm is as follows:

The resultant date is made from a locality and time::instant.

The locality is derived from one of:

The instant is derived from one of:

A void .daydate may be substituted with one of:

A void .daytime may be substituted with:

A void .year may be substituted with:

A void .hour may be substituted with:

If an insufficient combination was provided, insufficient is returned. If invalid values were provided, invalid is returned. Any zflags assigned to the .zoff field affect the final result.

fn reckon[link]

fn reckon(d: date, zoff: (time::duration | zflag), rf: rflag, spans: span...) (date | invalid | zfunresolved);

Reckons from a given date to a new one, via a given set of spans. This is a chronological arithmetic operation. Each span is reckoned independently in succession, applying (adding) their units from most to least significant.

The rflag parameter handles field overflows and other behaviours. The zflag parameter affects the final result. Example:

// 2000-02-29 00:00:00.000000000 -1100 -11 Pacific/Apia
let a = date::new(chrono::tz("Pacific/Apia")!, -11 * time::HOUR,
	2000,  2, 29)!;

let b = date::reckon(a,    // starts as: 2000-Feb-29 00:00 -1100
	date::zflag::GAP_END,
	date::rflag::DEFAULT,
	date::span {
		years  = 11, // becomes: 2011-Feb-28 00:00 -1100
		months = 10, // becomes: 2011-Dec-28 00:00 -1100
		days   =  1, // becomes: 2011-Dec-29 00:00 -1100
		hours  = 36, // becomes: 2011-Dec-30 12:00 -1100
	},
	// In Samoa, Apia, the day 2011-Dec-30 was skipped entirely.
	// Thus, after applying date::zflag::GAP_END for adjustment,
	// we arrive at the final date, time, and zone-offset:
	// 2011-12-31 00:00:00.000000000 +1400 +14 Pacific/Apia
);

See add.

fn second[link]

fn second(d: *date) int;

Observes a date's second of the minute.

fn strerror[link]

fn strerror(err: error) const str;

Converts an error into a human-friendly string. The result may be statically allocated.

fn sum[link]

fn sum(spans: span...) span;

Returns the sum span of a set of spans.

fn sundayweek[link]

fn sundayweek(d: *date) int;

Observes a date's Gregorian week starting Sunday. Range 0 to 53. All days in a year before the year's first Sunday belong to week 0.

fn timezone_free[link]

fn timezone_free(tz: *timezone) void;

Frees a timezone. A locality argument can be passed.

fn to_instant[link]

fn to_instant(d: date) time::instant;

Extracts the time::instant of the given date.

fn to_moment[link]

fn to_moment(d: date) chrono::moment;

Extracts the time::chrono::moment of the given date.

fn traverse[link]

fn traverse(a: date, b: date) span;

Calculates the span between two dates, from A to B.

The returned span, provided to reckon with rflag::DEFAULT and date A, will produce B. The span's fields will all be the same sign.

Be aware, using date of different localitys may return unexpected results.

fn truncate[link]

fn truncate(d: date, zf: zflag, u: step) (date | invalid | zfunresolved);

Truncates the given date at the provided nominal step. The zflag parameter affects the final result. Example:

// On this day in Sao Paulo, a +1 hour jump occurs at 00:00.
// The time range 00:00..00:59 is never observed.
//
// 2000-10-08 12:00:00.000000000 -0200 -02 America/Sao_Paulo
let a = date::new(chrono::tz("America/Sao_Paulo")!, -2 * time::HOUR,
	2000, 10,  8, 12)!
//
// 2000-10-08 01:00:00.000000000 -0200 -02 America/Sao_Paulo
let b = date::truncate(a, date::zflag::GAP_END, date::step::DAY)!;

fn tzdb[link]

fn tzdb(tzid: str) (locality | tzdberror);

Loads a timezone from the system's TZDB (Timezone Database) as a locality. Each call returns a new instance. The caller must free the return value. See timezone_free.

The given "TZID" shall be a TZDB identifier and acts as the relative filepath to a TZif (Time Zone Information Format) file under TZDB_PATH. For example, "Europe/Amsterdam" for "/usr/share/zoneinfo/Europe/Amsterdam".

The loaded timezones are assigned the TZID as its name, the time::chrono::utc timescale, and the EARTH_DAY day-length

fn week[link]

fn week(d: *date) int;

Observes a date's Gregorian week starting Monday. Range 0 to 53. All days in a year before the year's first Monday belong to week 0.

fn weekday[link]

fn weekday(d: *date) int;

Observes a date's day of the week. Range Monday=0 to Sunday=6.

fn year[link]

fn year(d: *date) int;

Observes a date's year.

fn yearday[link]

fn yearday(d: *date) int;

Observes a date's ordinal day of the year. Range 1 to 366.

fn zone[link]

fn zone(d: *date) zonephase;

Observes a date's zonephase.

fn zone_finish[link]

fn zone_finish(z: *zonephase) void;

Frees resources associated with a zonephase.