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.
Day numbers
ˡd̲ays : Int -> Int
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
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 }
ˡt̲oday : Unit -> Int
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
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
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 }
ˡd̲aysIn : (Num a, Truthy a) => Int -> Int -> a
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 }
Text
ʰt̲wo : a -> Char
A number of one or two digits as two, 03.
ʰt̲wo ← { x → " " "0" ᵗr̲eplace 2 ᵗp̲adLeft f̲ormat x }
ˡi̲so : Int -> Box Char
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
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 }
ˡm̲onth : Int -> Int -> Char
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 }