Standard Library
namespace datetime
Calendar arithmetic and date parsing for UTC timestamps.
since 0.1.0-alpha.1linuxwindowswasm
Overview
Timestamps are counted as milliseconds since 1970-01-01T00:00:00Z (the Unix epoch), and a day number counts whole days since the same instant. The functions here convert between those counts and calendar fields using the proleptic Gregorian calendar, and parse the two text formats used on the web: the HTTP date format and ISO 8601. Time zones and leap seconds are not modelled; everything is UTC. The DateTime and Duration types build on these functions and are usually the better entry point.
Description
The datetime namespace holds the free functions that support DateTime and Duration. The language
has no static methods, so the operations that can fail are free functions here rather than
constructors. Two parsers return DateTime?:
datetime::parseHttpDate(text)reads the RFC 7231 formSun, 06 Nov 1994 08:49:37 GMTand nothing else. The obsolete RFC 850 and asctime forms returnNone.datetime::parseIso8601(text)readsYYYY-MM-DDTHH:MM:SS, optionally followed by a fraction of up to three digits (further digits are ignored) and then eitherZor a numeric offset such as+02:00. The offset is subtracted so the result is always a UTC instant. Text with no zone suffix is read as UTC.
Both parsers are strict about layout and return None for any text that does not fit it, including
trailing characters. They do not check that the fields describe a real date: a day or month out of range
rolls over, so Sun, 31 Feb 1994 08:49:37 GMT reads as 3 March 1994.
The calendar functions convert between instants and civil dates:
epochFromCivil(year, month, day, hour, minute, second, milli) returns the epoch milliseconds of a
civil date and time, daysFromCivil(year, month, day) and civilFromDays(days) convert between a date
and a day count since 1970-01-01, and weekday(days) returns 0 for Sunday through 6 for Saturday.
Use epochFromCivil with DateTime::ofEpochMs to build an instant from components.
Parsing and calendar functions
DateTime? p = datetime::parseHttpDate("Sun, 06 Nov 1994 08:49:37 GMT");
DateTime a = p ?? DateTime::ofEpochMs(0);
console.writeln(a.epochMs);
DateTime? q = datetime::parseIso8601("1994-11-06T10:49:37.500+02:00");
DateTime b = q ?? DateTime::ofEpochMs(0);
console.writeln(b.iso8601());
console.writeln(datetime::parseIso8601("1994-11-06 08:49:37Z") == None);
console.writeln(datetime::parseHttpDate("Sunday, 06-Nov-94 08:49:37 GMT") == None);
console.writeln(datetime::epochFromCivil(1970, 1, 2, 0, 0, 1, 5));
console.writeln(datetime::civilFromDays(19000).joinToString("-"));
console.writeln(datetime::weekday(datetime::daysFromCivil(1994, 11, 6)));
784111777000
1994-11-06T08:49:37.500Z
true
true
86401005
2022-1-8
0
Rules
- A parser returns
Nonefor malformed text and never throws. - A numeric offset in an ISO 8601 string must be exactly
+hh:mmor-hh:mm. - Fractions longer than three digits are truncated, not rounded.
Examples
Round trip through both formats
DateTime t = DateTime::ofEpochMs(datetime::epochFromCivil(2026, 7, 5, 12, 0, 0, 0));
string h = t.httpDate();
string i = t.iso8601();
console.writeln(h);
console.writeln(i);
DateTime fromHttp = datetime::parseHttpDate(h) ?? DateTime::ofEpochMs(0);
DateTime fromIso = datetime::parseIso8601(i) ?? DateTime::ofEpochMs(0);
console.writeln(fromHttp.epochMs == t.epochMs);
console.writeln(fromIso.epochMs == t.epochMs);
Sun, 05 Jul 2026 12:00:00 GMT
2026-07-05T12:00:00Z
true
true
Examples
Parsing, shifting, and formatting a timestamp
DateTime? parsed = datetime::parseIso8601("1994-11-06T08:49:37Z");
if (parsed != None) {
DateTime later = parsed.plus(Duration::ofDays(30));
console.writeln(later.iso8601());
console.writeln(later.httpDate());
}
console.writeln(datetime::daysFromCivil(1994, 11, 6));
1994-12-06T08:49:37Z
Tue, 06 Dec 1994 08:49:37 GMT
9075
Functions
civilFromDays
civilFromDays(int z) -> Array<int>Convert a day number to a calendar date.
Parameters
- z
- Whole days since 1970-01-01; negative values are before the epoch.
Returns
A three-element array holding the year, the month (1 to 12) and the day of the month (1 to 31).
Examples
Array<int> epoch = datetime::civilFromDays(0);
console.writeln(epoch.joinToString("-"));
Array<int> later = datetime::civilFromDays(9075);
console.writeln(later.joinToString("-"));
console.writeln(datetime::civilFromDays(0 - 1).joinToString("-"));
1970-1-1
1994-11-6
1969-12-31
See also: daysFromCivil
dayMs
dayMs(int epochMs) -> intGet the time of day of a timestamp, in milliseconds since midnight UTC.
The result is always from 0 to 86399999, including for instants before 1970.
Parameters
- epochMs
- Milliseconds since 1970-01-01T00:00:00Z.
Returns
Milliseconds elapsed since the most recent midnight UTC.
Examples
console.writeln(datetime::dayMs(784111777000));
console.writeln(datetime::dayMs(0 - 1));
31777000
86399999
See also: epochDays
daysFromCivil
daysFromCivil(int y, int m, int d) -> intConvert a calendar date to a day number.
The inverse of civilFromDays. The date is not range-checked, so an out-of-range month or day rolls over into the neighbouring month or year rather than failing.
Parameters
- y
- The year.
- m
- The month, 1 to 12.
- d
- The day of the month, starting at 1.
Returns
Whole days since 1970-01-01; negative before the epoch.
Examples
console.writeln(datetime::daysFromCivil(1970, 1, 1));
console.writeln(datetime::daysFromCivil(1994, 11, 6));
console.writeln(datetime::daysFromCivil(2000, 3, 1) - datetime::daysFromCivil(2000, 2, 28));
0
9075
2
See also: civilFromDays
epochDays
epochDays(int epochMs) -> intConvert a timestamp to the number of whole days since the Unix epoch.
The result rounds toward earlier days, so instants before 1970 still land on the day that contains them: one millisecond before the epoch is on day -1.
Parameters
- epochMs
- Milliseconds since 1970-01-01T00:00:00Z.
Returns
The day number that contains the instant.
Examples
console.writeln(datetime::epochDays(784111777000));
console.writeln(datetime::epochDays(0));
console.writeln(datetime::epochDays(0 - 1));
9075
0
-1
See also: dayMs
epochFromCivil
epochFromCivil(int y, int mo, int d, int h, int mi, int s, int ms) -> intConvert calendar and clock fields, taken as UTC, to a timestamp.
The fields are not range-checked; out-of-range values carry into the next larger unit.
Parameters
- y
- The year.
- mo
- The month, 1 to 12.
- d
- The day of the month, starting at 1.
- h
- The hour, 0 to 23.
- mi
- The minute, 0 to 59.
- s
- The second, 0 to 59.
- ms
- The millisecond, 0 to 999.
Returns
Milliseconds since 1970-01-01T00:00:00Z.
Examples
console.writeln(datetime::epochFromCivil(1994, 11, 6, 8, 49, 37, 0));
console.writeln(datetime::epochFromCivil(1970, 1, 1, 0, 0, 1, 500));
784111777000
1500
See also: daysFromCivil
monthIndex
monthIndex(string mon) -> intLook up a month number from its three-letter English name.
The match is exact and case-sensitive.
Parameters
- mon
- A month name such as
Nov.
Returns
The month number from 1 to 12, or 0 when the name is not recognised.
Examples
console.writeln(datetime::monthIndex("Nov"));
console.writeln(datetime::monthIndex("nov"));
console.writeln(datetime::monthIndex("Foo"));
11
0
0
See also: monthName
monthName
monthName(int m) -> stringGet the three-letter English name of a month.
Parameters
- m
- The month number, 1 for January through 12 for December.
Returns
One of Jan through Dec; 0 gives an empty string.
Examples
console.writeln(datetime::monthName(1));
console.writeln(datetime::monthName(11));
Jan
Nov
See also: monthIndex
parseHttpDate
parseHttpDate(string s) -> DateTime | NoneParse a date in the HTTP date format.
Only the modern fixed-length form is accepted, for example Sun, 06 Nov 1994 08:49:37 GMT: a weekday name followed by a comma, day, month name, four-digit year, HH:MM:SS time and the literal GMT. The older two-digit-year and C asctime forms give None. The weekday name is not checked against the date, and the numeric fields are not range-checked.
Parameters
- s
- The text to parse.
Returns
The instant described, or None when s is not in that format.
Examples
DateTime? ok = datetime::parseHttpDate("Sun, 06 Nov 1994 08:49:37 GMT");
console.writeln(ok != None ? ok.epochMs.toString() : "invalid");
DateTime? obsolete = datetime::parseHttpDate("Sunday, 06-Nov-94 08:49:37 GMT");
console.writeln(obsolete != None ? obsolete.epochMs.toString() : "invalid");
DateTime? wrongZone = datetime::parseHttpDate("Sun, 06 Nov 1994 08:49:37 UTC");
console.writeln(wrongZone != None ? wrongZone.epochMs.toString() : "invalid");
784111777000
invalid
invalid
See also: httpDate
parseIso8601
parseIso8601(string s) -> DateTime | NoneParse an ISO 8601 date and time.
The text must have the shape YYYY-MM-DDTHH:MM:SS, optionally followed by a fraction of a second and a zone. A fraction is a dot and digits; only the first three digits (milliseconds) are kept. The zone is Z for UTC or an offset such as +02:00 or -05:00; an offset is subtracted so the result is always the UTC instant, and text with no zone is read as UTC. Anything left over after the zone gives None, and so does a date-only string. The numeric fields are not range-checked: month 13 parses and rolls over into the next year.
Parameters
- s
- The text to parse.
Returns
The instant described, or None when s does not have that shape.
Examples
DateTime? utc = datetime::parseIso8601("1994-11-06T08:49:37Z");
console.writeln(utc != None ? utc.iso8601() : "invalid");
DateTime? offset = datetime::parseIso8601("1994-11-06T10:49:37.5+02:00");
console.writeln(offset != None ? offset.iso8601() : "invalid");
DateTime? dateOnly = datetime::parseIso8601("1994-11-06");
console.writeln(dateOnly != None ? dateOnly.iso8601() : "invalid");
DateTime? spaced = datetime::parseIso8601("1994-11-06 08:49:37Z");
console.writeln(spaced != None ? spaced.iso8601() : "invalid");
1994-11-06T08:49:37Z
1994-11-06T08:49:37.500Z
invalid
invalid
See also: iso8601
weekday
weekday(int z) -> intGet the day of the week for a day number.
Parameters
- z
- Whole days since 1970-01-01, as returned by
epochDays.
Returns
0 for Sunday through 6 for Saturday.
Examples
console.writeln(datetime::weekday(0));
console.writeln(datetime::weekday(9075));
console.writeln(datetime::weekdayName(datetime::weekday(9075)));
4
0
Sun
See also: weekdayName
weekdayName
weekdayName(int w) -> stringGet the three-letter English name of a weekday.
Parameters
- w
- The weekday number,
0for Sunday through6for Saturday.
Returns
One of Sun, Mon, Tue, Wed, Thu, Fri, Sat.
Examples
console.writeln(datetime::weekdayName(0));
console.writeln(datetime::weekdayName(4));
Sun
Thu
See also: weekday