calendar

tape
import calendar from "calendar";

calendar is the arithmetic of the Gregorian calendar, extended back before 1582 (the proleptic Gregorian calendar, as ISO 8601 uses). It reads no clock and allocates nothing, so it works in every profile, t0 included, and in pure modules. Programs that read the clock use time, which is built on it; use calendar where time is out of reach, such as a parser that must stay pure.

Days since 1970

tape
pub fn days_from_civil(y0: i64, m: i64, d: i64) -> i64

The number of days from 1 January 1970 to the date y0-m-d: negative before 1970, for any year (year 0 is 1 BC). m is 1 to 12; d is taken as it is, so day 0 is the last day of the month before.

tape
let days: i64 = calendar.days_from_civil(2026, 10, 26);      // 20752
let secs: i64 = days * 86400 + 14 * 3600;                    // 2026-10-26T14:00:00Z, Unix time
let before: i64 = calendar.days_from_civil(1969, 12, 31);    // -1

Leap years and months

tape
pub fn is_leap_year(y: i64) -> bool
pub fn days_in_month(y: i64, m: i64) -> i64

is_leap_year follows the Gregorian rule: every fourth year, but centuries only when divisible by 400 (2000 was a leap year, 1900 was not). days_in_month is 28 to 31; a month outside 1 to 12 is a mistake in the program and stops it (a trap).

tape
fn valid_date(y: i64, m: i64, d: i64) -> bool {
    return m >= 1 && m <= 12 && d >= 1 && d <= calendar.days_in_month(y, m);
}

Digits

tape
pub fn put_digits(b: []u8, pos: i64, v: i64, width: i64) -> i64

Writes v (0 or more) as exactly width digits at b[pos..], with leading zeros, and returns the position after them: the way dates and times are written field by field.

tape
var buf: [10]u8;
var pos: i64 = calendar.put_digits(buf[0..10], 0, 2026, 4);
buf[pos] = @byte("-");
pos = calendar.put_digits(buf[0..10], pos + 1, 3, 2);
buf[pos] = @byte("-");
pos = calendar.put_digits(buf[0..10], pos + 1, 7, 2);         // buf[0..10] is "2026-03-07"

Notes

  • time’s is_leap_year and days_in_month are these functions; time.from_fields and DateTime.to_unix_nanos do the checking and the conversion for whole date-times.
  • x509 uses calendar for certificate validity times, and log for the time stamps of its lines.

Last modified: