Algol 68 date and time
last modified November 14, 2026
Algol 68 Genie does not turn a date into text or parse one back. It provides the current date and time as eight integers, and it measures processor time as a real. Calendar work such as finding the difference between two dates or adding a hundred days is written with ordinary integer arithmetic, which is the subject of this article.
The programs read the clock, read the local time, format a date, convert a calendar date to a day number, and turn a day number back into a date. The transcripts that show the current date were made on the day the article was written, so a later run prints a different date.
Processor time
clock returns the processor time used so far as a
REAL number of seconds, and seconds returns the same
kind of reading. Neither is a wall clock: a program that sleeps for a second
uses almost no processor time. Two readings taken around a loop therefore
measure the work of the loop and not the time a person waited.
BEGIN
REAL start = clock;
INT total := 0;
FOR i TO 1000000 DO total +:= i MOD 7 OD;
REAL finish = clock;
REAL t0 = clock;
sleep(1);
REAL t1 = clock;
print(("total ", whole(total, 0), newline));
print(("the loop used more processor time than sleep: ",
(finish - start) > (t1 - t0), newline))
END
The four declarations hold snapshots of the clock, and the difference between
the first pair is compared with the difference around sleep. The
exact numbers depend on the machine, so the program prints only the result of
the comparison, which is stable. The sum itself is deterministic and shows
that the loop really ran.
$ a68g cputime.a68 total 2999998 the loop used more processor time than sleep: T
The current date and time
localtime returns a row of eight integers: the year, the month
from 1 to 12, the day of the month, the hour, the minute, the second, the day
of the week with 1 for Sunday and 7 for Saturday, and a flag that is 1 while
daylight saving time is in effect. The row is a value, so it can be subscripted
like any other row.
BEGIN
[]INT t = localtime;
print(("year ", whole(t[1], 0), newline));
print(("month ", whole(t[2], 0), newline));
print(("day ", whole(t[3], 0), newline));
print(("hour ", whole(t[4], 0), newline));
print(("minute ", whole(t[5], 0), newline));
print(("second ", whole(t[6], 0), newline));
print(("weekday ", whole(t[7], 0), newline));
print(("dst ", whole(t[8], 0), newline))
END
The bounds of the row are 1 and 8, so a loop over it would visit every field
in the order above. The weekday 7 belongs to Saturday, and the last field is 0
outside the summer time period. Reading localtime once into the
row keeps all eight fields from the same instant; calling it again for each
print could cross a second boundary and mix two readings.
$ a68g now.a68 year 2026 month 11 day 14 hour 8 minute 56 second 18 weekday 7 dst 0
Formatting a date
A date is formatted by padding the month and the day to two digits and by
choosing the month name from a row. The procedure two returns a
string of exactly two characters, which keeps the fields of the ISO form and
the fields of a time of day aligned.
PROC two = (INT n) STRING:
IF n < 10 THEN "0" + whole(n, 0) ELSE whole(n, 0) FI;
[]STRING months = ("January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November",
"December");
BEGIN
[]INT t = localtime;
print((whole(t[1], 0), "-", two(t[2]), "-", two(t[3]), newline));
print((months[t[2]], " ", whole(t[3], 0), ", ", whole(t[1], 0), newline));
print((two(t[4]), ":", two(t[5]), ":", two(t[6]), newline))
END
The row months is indexed directly by the month field, because
January is at subscript 1 in both. The year is printed without padding, the
day of the month in the long form has no leading zero, and the time uses the
same two-digit rule as the ISO date. The names of different lengths are all
widened to STRING when the row is built.
$ a68g format.a68 2026-11-14 November 14, 2026 08:56:18
Converting a duration
A number of seconds becomes hours, minutes, and seconds with two remainders: the whole hours are the quotient by 3600, and the minutes are the quotient of what is left by 60. The last remainder is the number of seconds, because a minute has 60 of them.
PROC two = (INT n) STRING: IF n < 10 THEN "0" + whole(n, 0) ELSE whole(n, 0) FI; PROC show duration = (INT total) VOID: ( INT h = total OVER 3600; INT m = (total MOD 3600) OVER 60; INT s = total MOD 60; print((two(h), ":", two(m), ":", two(s), newline)) ); BEGIN show duration(0); show duration(59); show duration(3661); show duration(86399) END
The parentheses around total MOD 3600 make the grouping
explicit; OVER and MOD have the same priority, so
the expression is read left to right. The procedure prints
the fields with two digits, so a duration of zero is 00:00:00
and the last second of a day is 23:59:59. Durations longer than a
day keep counting hours past 23.
$ a68g duration.a68 00:00:00 00:00:59 01:01:01 23:59:59
Day numbers and differences
Calendar arithmetic becomes simple when a date is converted to the number of days since 1 January 1970. The conversion counts whole 400-year eras, the years inside the era, and the days inside the year, with the leap day placed at the end of the shifted year. The result for 1970-01-01 is 0.
PROC days from civil = (INT y, m, d) INT:
(
INT yy := y;
IF m <= 2 THEN yy -:= 1 FI;
INT era = yy OVER 400;
INT yoe = yy - era * 400;
INT mp := m - 3;
IF m <= 2 THEN mp := m + 9 FI;
INT doy = (153 * mp + 2) OVER 5 + d - 1;
INT doe = yoe * 365 + yoe OVER 4 - yoe OVER 100 + doy;
era * 146097 + doe - 719468
);
[]STRING weekdays = ("Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday");
BEGIN
INT a = days from civil(2000, 1, 1);
INT b = days from civil(2024, 2, 29);
print((whole(b - a, 0), " days between the two dates", newline));
print(("2000-01-01 was a ", weekdays[(a + 4) MOD 7 + 1], newline));
print(("2024-02-29 was a ", weekdays[(b + 4) MOD 7 + 1], newline))
END
The two IF statements shift January and February into the
previous year, so the leap day is the last day of the shifted year and the
month arithmetic is uniform. The constant 719468 moves the epoch from
1 March 0000 to 1 January 1970. The difference of two day numbers is the
number of days between the dates, and the weekday follows from the fact that
day 0, 1 January 1970, was a Thursday: adding 4 and taking the remainder
modulo 7 gives an index into a row that starts with Sunday.
$ a68g days.a68 8825 days between the two dates 2000-01-01 was a Saturday 2024-02-29 was a Thursday
Adding and subtracting days
The reverse conversion splits the shifted day number into eras, years, and
days again. It is the usual companion of days from civil, and the
two together let a program add a number of days to a date and print the
result.
MODE DATE = STRUCT(INT year, month, day);
PROC civil from days = (INT days) DATE:
(
INT z := days + 719468;
INT era = z OVER 146097;
INT doe = z - era * 146097;
INT yoe = (doe - doe OVER 1460 + doe OVER 36524 - doe OVER 146096) OVER 365;
INT y := yoe + era * 400;
INT doy = doe - (365 * yoe + yoe OVER 4 - yoe OVER 100);
INT mp = (5 * doy + 2) OVER 153;
INT d = doy - (153 * mp + 2) OVER 5 + 1;
INT m := mp + 3;
IF mp >= 10 THEN m := mp - 9 FI;
IF m <= 2 THEN y +:= 1 FI;
DATE(y, m, d)
);
PROC days from civil = (INT y, m, d) INT:
(
INT yy := y;
IF m <= 2 THEN yy -:= 1 FI;
INT era = yy OVER 400;
INT yoe = yy - era * 400;
INT mp := m - 3;
IF m <= 2 THEN mp := m + 9 FI;
INT doy = (153 * mp + 2) OVER 5 + d - 1;
INT doe = yoe * 365 + yoe OVER 4 - yoe OVER 100 + doy;
era * 146097 + doe - 719468
);
PROC two = (INT n) STRING:
IF n < 10 THEN "0" + whole(n, 0) ELSE whole(n, 0) FI;
PROC show = (DATE dt) VOID:
print((whole(year OF dt, 0), "-", two(month OF dt), "-",
two(day OF dt), newline));
BEGIN
INT today = days from civil(2026, 11, 14);
show(civil from days(today + 100));
show(civil from days(today - 1000));
print((whole(days from civil(2024, 2, 29) - days from civil(2000, 1, 1), 0),
" days between 2000-01-01 and 2024-02-29", newline))
END
The reverse conversion undoes each step of the forward one: the era is the
quotient by 146097, the year of the era comes from a division that corrects
for the leap years, and the month is found with the same 153-day pattern. The
result is a DATE structure, which show prints with
the same two-digit padding as before. Adding 100 days to 14 November 2026
gives 22 February 2027, and subtracting 1000 days gives 18 February 2024,
which crosses the leap day of 2024.
$ a68g adddays.a68 2027-02-22 2024-02-18 8825 days between 2000-01-01 and 2024-02-29
Next steps
The environment and processes
article uses clock to time a command, and the
number formatting article explains
the widths used by whole and fixed. The
random numbers article uses the same
kind of integer arithmetic in its simulations.
Source
Revised Report on the Algorithmic Language Algol 68
In this article we have measured processor time, read the local date and time, formatted a date, converted dates to day numbers, computed differences and weekdays, and added and subtracted days.
Author
List all Algol 68 tutorials.