D. J. Bernstein

The caldate library interface

Calendar dates

     #include <caldate.h>

     struct caldate cd;
A struct caldate value is a calendar date. It has three components: year (e.g., 1999), month (1 through 12), and day (1 through 31).

ASCII input and output

     #include <caldate.h>

     struct caldate cd;
     char *s;
     unsigned int len;

     len = caldate_fmt(s,&cd);
     len = caldate_scan(s,&cd);
caldate_fmt prints cd in ISO style (YYYY-MM-DD) into the character buffer s, without a terminating \0. It returns the number of characters printed. s may be zero; then caldate_fmt returns the number of characters that would have been printed.

caldate_scan reads a calendar date in ISO style from the beginning of the character buffer s and puts the date into cd. It returns the number of characters read. If s does not start with an ISO-style date, caldate_scan returns 0, and may or may not touch cd.

Note that year numbers may be larger than 9999; len will not always be equal to 10. Please don't contribute to the Y10K problem.

Date arithmetic

     #include <caldate.h>

     struct caldate cd;
     long d;
     int *weekday;
     int *yearday;

     d = caldate_mjd(&cd);
Every calendar date has a modified Julian day number. The day number increases by 1 every day. Day number 0 is 17 November 1858. Day number 51604 is 1 March 2000.

caldate_frommjd puts into cd the date corresponding to the modified Julian day number d. caldate_frommjd also computes the day of the week (0 through 6) and the day of the year (0 through 365). It stores the day of the week in *weekday if weekday is nonzero. It stores the day of the year in *yearday if yearday is nonzero. (The day of the week is equal to (d + 3) % 7 if d is positive.)

caldate_mjd returns the modified Julian day number corresponding to the date in cd. It allows cd.month to be smaller than 1, referring to months in previous years, or larger than 12, referring to months in subsequent years. Similarly, it allows cd.day to be smaller than 1, referring to days in previous months, or larger than the number of days in this month, referring to days in subsequent months.

caldate_normalize calls caldate_frommjd with the result of caldate_mjd. This means that it accepts out-of-range months and out-of-range days in cd, and puts a valid calendar date back into cd.

These routines currently support the Gregorian calendar, which was defined in 1582 and adopted at different times in different countries. Earlier dates are handled according to the standard ``virtual Gregorian'' (often misleadingly called ``proleptic Gregorian'') calendar, defined mathematically by the 400-year Gregorian cycle for years before 1582. The Julian calendar is not supported.

Beware that the Gregorian calendar will be replaced by a new calendar within a few thousand years. The caldate_frommjd and caldate_mjd routines will be upgraded accordingly. The current caldate_frommjd and caldate_mjd routines are not useful for dates far in the future.

Beware also that day numbers will overflow a 32-bit long sometime after the year 5000000. All systems should upgrade to 64-bit longs before then. caldate_mjd does not check for overflow.