LEVIATHAN v962456e · 962456eee1

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 form Sun, 06 Nov 1994 08:49:37 GMT and nothing else. The obsolete RFC 850 and asctime forms return None.
  • datetime::parseIso8601(text) reads YYYY-MM-DDTHH:MM:SS, optionally followed by a fraction of up to three digits (further digits are ignored) and then either Z or 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 None for malformed text and never throws.
  • A numeric offset in an ISO 8601 string must be exactly +hh:mm or -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) -> int

Get 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) -> int

Convert 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) -> int

Convert 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) -> int

Convert 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) -> int

Look 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) -> string

Get 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 | None

Parse 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 | None

Parse 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) -> int

Get 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) -> string

Get the three-letter English name of a weekday.

Parameters

w
The weekday number, 0 for Sunday through 6 for 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

See also

  • DateTime — A point in time, held as milliseconds since 1970-01-01T00:00:00Z.
  • Duration — A length of time, stored as a whole number of milliseconds.