Dates and times#
Three built-in kinds handle the calendar and the clock:
| Kind | Is | Prints as |
|---|---|---|
date |
A calendar day, with no time or zone | 2026-09-24 |
datetime |
A moment, seen in a time zone | 2026-09-24T14:30:00+08:00[Asia/Shanghai] |
duration |
An exact length of time | 2h 30m |
takepkg std.time;
func m{
deadline = date(2026, 12, 31);
left = deadline - time.today();
out("days left:", left.days());
meeting = datetime(2026, 9, 24, 14, 30, 0, "Asia/Shanghai");
out(meeting.in_zone("America/New_York")); // 2026-09-24T02:30:00-04:00[America/New_York]
out(meeting + time.hours(1) + time.minutes(30));
}
They are values, like numbers and strings, not families: two dates of the same
day are equal, < and sorting order them, and they work as set members and map
keys. Annotations use their names: func remind(date day). The calendar,
leap years, time zones, and daylight saving come from the
jiff crate.
date#
| Written | Gives |
|---|---|
date(2026, 9, 24) |
Year, month, and day |
date("2026-09-24") |
ISO 8601 text |
date("24/09/2026", "%d/%m/%Y") |
Text in another layout; see formats |
date(a_datetime) |
The day of a datetime, in its own zone |
time.today() |
Today, where this machine is |
| Method | Result |
|---|---|
year(), month(), day() |
The parts, as ints |
weekday() |
1 for Monday to 7 for Sunday |
day_of_year() |
1 to 366 |
days_in_month() |
28 to 31 |
is_leap_year() |
Whether its year has a February 29 |
add_days(n), add_months(n), add_years(n) |
Another date, n steps away; n may be negative |
at(hour, minute, second, zone) |
A datetime on this day |
format(pattern) |
Text in any layout |
add_months keeps the day where it can and uses the month's last day where it
cannot: January 31 plus a month is February 28, or 29 in a leap year.
datetime#
| Written | Gives |
|---|---|
datetime("2026-09-24T14:30:00+08:00") |
ISO 8601 with an offset, or Z for UTC |
datetime("2026-09-24T14:30:00+08:00[Asia/Shanghai]") |
The same, in a named zone |
datetime(2026, 9, 24, 14, 30, 0, "Asia/Shanghai") |
Its parts and a zone |
datetime("2026-09-24 14:30 +0800", "%Y-%m-%d %H:%M %z") |
Text in another layout, which must include the zone |
time.now_datetime() |
Now, in this machine's zone |
A zone is an IANA name such as "Asia/Shanghai" or "Europe/London", "UTC",
an offset such as "+08:00", or "local" for this machine's zone. A time
without a zone names no moment, so datetime("2026-09-24T14:30:00") raises and
asks for one.
| Method | Result |
|---|---|
year(), month(), day(), hour(), minute(), second() |
The parts, in its zone |
weekday() |
1 for Monday to 7 for Sunday |
date() |
Its calendar day |
zone() |
The zone's name, or its offset when it has no name |
offset() |
Its distance from UTC at that moment, as a duration |
in_zone(zone) |
The same moment, seen in another zone |
timestamp() |
Seconds since 1970-01-01 UTC, as a float |
add_days(n), add_months(n), add_years(n) |
Calendar steps that keep the time of day |
format(pattern) |
Text in any layout |
Two datetimes are equal when they are the same moment, whatever zones they are seen in: 14:30 in Shanghai equals 06:30 UTC.
Daylight saving#
Adding a duration adds exactly that much time. Calendar steps keep the time of day. Across the night the clocks change, they differ:
ny = datetime(2026, 3, 7, 12, 0, 0, "America/New_York");
out(ny + time.days(1)); // 2026-03-08T13:00:00-04:00[America/New_York]: exactly 24 hours later
out(ny.add_days(1)); // 2026-03-08T12:00:00-04:00[America/New_York]: noon the next day
A time the clocks skip moves forward past the gap; a time that happens twice takes the first.
duration#
| Written | Gives |
|---|---|
time.days(n), time.hours(n), time.minutes(n), time.seconds(n), time.milliseconds(n) |
A length in one unit; n may have a fraction |
duration(90) |
A number of seconds |
duration("2h 30m"), duration("2 hours, 30 minutes") |
Text in d, h, m, s, and ms |
duration("PT2H30M") |
ISO 8601 |
later - earlier |
The time between two dates or two datetimes |
| Method | Result |
|---|---|
seconds(), minutes(), hours(), days() |
The whole length in that unit, as a float |
abs() |
The length without its sign |
A day in a duration is always 24 hours. Months and years have no fixed length,
so they are the add_months and add_years methods instead. A zero duration
is false in a condition, as 0 is.
Arithmetic#
| Written | Gives |
|---|---|
date + duration, date - duration |
A date; the duration must be whole days |
date - date |
A duration |
datetime + duration, datetime - duration |
A datetime |
datetime - datetime |
A duration |
duration + duration, duration - duration, -duration |
A duration |
duration * number, duration / number |
A duration |
duration / duration |
How many times one fits in the other, as a float |
Mixing a date and a datetime is an error that says how to convert one, and so
is adding a number to a date, since 3 could mean days, hours, or seconds:
TypeError: cannot add a date and an int; add a duration, such as time.days(3) or time.hours(2)
Formats#
format and the two-argument date and datetime use strftime patterns:
| Pattern | Gives |
|---|---|
%Y, %m, %d |
2026, 09, 24 |
%B, %b |
September, Sep |
%A, %a |
Thursday, Thu |
%H, %M, %S |
14, 30, 00 |
%I, %p |
02, PM |
%z, %Z, %Q |
+0800, CST, Asia/Shanghai |
%j |
267, the day of the year |
%% |
A % |
out(date(2026, 9, 24).format("%A, %d %B %Y")); // Thursday, 24 September 2026
In files#
JSON has no dates, so json.stringify writes them as ISO 8601 strings, which
date(), datetime(), and duration() read back. TOML has dates:
std.file.toml reads them as date and datetime and
writes them back as TOML dates. CSV, .env, and INI write them as they print.
The local zone#
time.today(), time.now_datetime(), and the "local" zone use the TZ
environment variable when it names a zone, and otherwise the zone the system is
set to. Where neither is known, they use UTC.
Zone names such as "Asia/Shanghai" come from the system's time zone database
on Linux and macOS, which the system keeps up to date. Windows has no such
database, and minimal Linux containers often leave it out, so a copy is built
into marslang and used when the system has none.