librarylibs/Dates/src/Dates.xtl

Dates: dates -- day numbers from calendar dates and back, weekdays, leap years, month lengths, ISO text, month calendars. Import it with an alias of your choice: "d:" u_se< "Dates". Put libs/Dates/src on XETAL_PATH ("just path"); the reference is libs/Dates/docs. Names with l: are exported; those under h: are private to this file.

A date is three numbers, year month day (2026 10 3), or a 3-row matrix of them, one date per column; a day number counts days from 1970-01-01 (day 0), so dates subtract and add as numbers. The calendar is the proleptic Gregorian one, for any year.

source · imports t: libs/Strings/src/Strings.xtl

Day numbers

ˡd̲ays : Int -> Int

function · line 18

d_ays ymd: the day number of each date (Howard Hinnant's days_from_civil, whole-array).

ˡd̲ays ← { ymd →
  m ← f̲irst 1 d̲rop ymd
  d ← f̲irst 2 d̲rop ymd
  y ← (f̲irst ymd) − m ≤ 2                      ⍝ March-based years
  era ← y d̲iv 400
  yoe ← y − era × 400
  doy ← (d − 1) + (2 + 153 × m + 9 − 12 × m > 2) d̲iv 5
  doe ← (yoe × 365) + (yoe d̲iv 4) − (yoe d̲iv 100) − doy      ⍝ read right to left: + doy
  (era × 146097) + doe − 719468
}

ˡc̲ivil : Int -> Int

function · line 31

c_ivil n: the date (year month day) of each day number: three numbers for one, a 3-row matrix for several (civil_from_days).

ˡc̲ivil ← { n →
  z ← n + 719468
  era ← z d̲iv 146097
  doe ← z − era × 146097
  yoe ← (doe − (doe d̲iv 1460) − (doe d̲iv 36524) − doe d̲iv 146096) d̲iv 365
  doy ← doe − (365 × yoe) + (yoe d̲iv 4) − yoe d̲iv 100
  mp ← (2 + 5 × doy) d̲iv 153
  d ← 1 + doy − (2 + 153 × mp) d̲iv 5
  m ← mp + 3 − 12 × mp ≥ 10
  y ← (yoe + era × 400) + m ≤ 2
  (3 c̲at s̲hape n) r̲eshape y c̲at m c̲at d
}
Used in: ˡi̲so

ˡt̲oday : Unit -> Int

function · line 46

t_oday @: today's day number, from the clock ([]TS: year, month, day, ... of the local time stamp). Read each time it is called.

ˡt̲oday ← { @ → ˡd̲ays 3 t̲ake ⎕TS }

Calendar facts

ˡw̲eekday : Int -> Int

function · line 52

w_eekday n: the day of the week of each day number, 1 Monday to 7 Sunday (ISO 8601; day 0, 1970-01-01, was a Thursday).

ˡw̲eekday ← { n → 1 + (n + 3) m̲od 7 }

ˡl̲eap? : Truthy a => Int -> a

function · line 55

l_eap? y: whether each year is a leap year.

ˡl̲eap? ← { y → (0 = y m̲od 400) ∨ (0 = y m̲od 4) ∧ 0 ≠ y m̲od 100 }
Used in: ˡd̲aysIn

ˡd̲aysIn : (Num a, Truthy a) => Int -> Int -> a

function · line 58

y d_aysIn m: the number of days in month m of year y.

ˡd̲aysIn ← { y m →
  '∨ r̲/ r̲avel (m < 1) ∨ m > 12 ? @ p̲anic< "months run 1 to 12, not {m}"
  (m s̲elect 31 28 31 30 31 30 31 31 30 31 30 31) + (m = 2) ∧ ˡl̲eap? y
}
p̲anic< expands to
(⎕P̲ANIC ("months run 1 to 12, not " c̲at (f̲ormat (m))))

Text

ʰt̲wo : a -> Char

function (private) · line 66

A number of one or two digits as two, 03.

ʰt̲wo ← { x → " " "0" ᵗr̲eplace 2 ᵗp̲adLeft f̲ormat x }
Used in: ˡi̲so

ˡi̲so : Int -> Box Char

function · line 69

i_so n: each day number as ISO text, 2026-10-03 (a list for several).

ˡi̲so ← { n →
  c ← ˡc̲ivil r̲avel n
  '{ i →
    v ← i s̲elect₂ c
    (f̲ormat f̲irst v) c̲at "-" c̲at (ʰt̲wo f̲irst 1 d̲rop v) c̲at "-" c̲at ʰt̲wo f̲irst 2 d̲rop v
  } m̲ap r̲ange t̲ally r̲avel n
}

ˡc̲alendar : Int -> Int -> Int

function · line 79

y c_alendar m: month m of year y as a 6 by 7 matrix of days, Monday first, 0 where a cell has no day.

ˡc̲alendar ← { y m →
  first ← ˡw̲eekday ˡd̲ays y c̲at m c̲at 1
  n ← y ˡd̲aysIn m
  cells ← (o̲ffsets 42) − first − 2
  6 7 r̲eshape cells × (cells ≥ 1) ∧ cells ≤ n
}
Used in: ˡm̲onth

ˡm̲onth : Int -> Int -> Char

function · line 87

y m_onth m: the month as text, a header and a line per week.

ˡm̲onth ← { y m →
  c ← y ˡc̲alendar m
  weeks ← '{ i → " " ᵗj̲oin '{ d → d = 0 ? "  "◆ 2 ᵗp̲adLeft f̲ormat d } m̲ap i s̲elect c } m̲ap r̲ange 6
  ᵗm̲ix (e̲nclose "Mo Tu We Th Fr Sa Su") c̲at weeks
}