Commit | Line | Data |
---|---|---|
b19a0abd KB |
1 | Program Design |
2 | ||
3 | This program exactly duplicates the operation of the original unix "cal" | |
4 | program. It was designed with that intent, so no "improvements" were made | |
5 | to either the command line syntax or to the error reporting. The main | |
6 | goal was to allow replacement of the existing binary with a freely | |
7 | redistibutable version without breaking any existing applications that | |
8 | might be built on top of the original. | |
9 | ||
10 | The date routines were written from scratch, basically from first | |
11 | principles. The algorithm for calculating the day of week from any | |
12 | gregorian date was "reverse engineered". This was necessary as most of | |
13 | the documented algorithms have to do with date calculations for other | |
14 | calendars (e.g. julian) and are only accurate when converted to gregorian | |
15 | within a narrow range of dates. | |
16 | ||
17 | I take 1 jan 1 to be a Saturday because that's what cal says and I couldn't | |
18 | change that even if I was dumb enough to try. From this we can easily | |
19 | calculate the day of week for any date. The algorithm for a zero based | |
20 | day of week: | |
21 | ||
22 | calculate the number of days in all prior years (year-1)*365 | |
23 | add the number of leap years (days?) since year 1 | |
24 | (not including this year as that is covered later) | |
25 | add the day number within the year | |
26 | this compensates for the non-inclusive leap year | |
27 | calculation | |
28 | if the day in question occurs before the gregorian reformation | |
29 | (3 sep 1752 for our purposes), then simply return | |
30 | (value so far - 1 + SATURDAY's value of 6) modulo 7. | |
31 | if the day in question occurs during the reformation (3 sep 1752 | |
32 | to 13 sep 1752 inclusive) return THURSDAY. This is my | |
33 | idea of what happened then. It does not matter much as | |
34 | this program never tries to find day of week for any day | |
35 | that is not the first of a month. | |
36 | otherwise, after the reformation, use the same formula as the | |
37 | days before with the additional step of subtracting the | |
38 | number of days (11) that were adjusted out of the calendar | |
39 | just before taking the modulo. | |
40 | ||
41 | It must be noted that the number of leap years calculation is sensitive | |
42 | to the date for which the leap year is being calculated. A year that occurs | |
43 | before the reformation is determined to be a leap year if its modulo of | |
44 | 4 equals zero. But after the reformation, a year is only a leap year if | |
45 | its modulo of 4 equals zero and its modulo of 100 does not. Of course, | |
46 | there is an exception for these century years. If the modulo of 400 equals | |
47 | zero, then the year is a leap year anyway. This is, in fact, what the | |
48 | gregorian reformation was all about (a bit of error in the old algorithm | |
49 | that caused the calendar to be inaccurate.) | |
50 | ||
51 | Once we have the day in year for the first of the month in question, the | |
52 | rest is trivial. Running diff on any output of this program and the | |
53 | equivalent output from the original cal reports no difference. This was | |
54 | confirmed by a script that ran them for all possible inputs (and took | |
55 | approximately 36 hours to complete on a sun-3.) |