Making a Calendar in J
Vector 9:1, page 85
Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 85
The Gregorian calendar was introduced in 1582 by Pope Greogory XIII to bring the date of Easter closer to the vernal equinox since the error in the mean year length in the Julian calendar introduced in 45 BC was causing Easter to gradually move towards the summer. In the Gregorian calendar leap years were still those years whose numbers were divisible by 4 except for centennial years where divisibility by 400 was also required. To compensate for the cumulative error in the Julian calendar, when the Gregorian calendar was adopted Thursday, October 4, 1582 was followed by Friday, October 15 resulting in a loss of ten calendar days.
A program in J is developed for calculating and displaying in any one of several formats the Gregorian calendar for any year after 1600. The sequence of verbs in J is compared with the APL functions in McDonnell (1979) which motivated the present paper.
Preliminaries¶
Since leap year is determined by the divisibility of the year number by the integers 4, 100 and 400, it will be useful to define verbs for finding the integer quotients and integer remainders with these divisors. Since the monad % & 4 100 400 gives the quotients when its argument is divided by 4, 100 and 400, the verb
will give the integer quotients, and, for example, div 1992 is 498 19 4. Similarly, the verb
gives the integer remainders, and mod 1992 is 0 92 392.
We shall also use the verbs
in the calculation of the day of the week since the days are numbered from 0 to 6, inclusive, and
to give the positive integers, so that, for example, pi 4 is the list 1 2 3 4.
Finally we shall define the constants
for the day names,
for the month names, and
for the lengths of the months where the leap year adjustment for February will be made later.
Leap Year and its Consequences¶
To find the calendar for any month of any year we shall define a New Year’s date for any year as the sequence number for January 1 of that year beginning with Monday, January 1, 1601 as 1, and an ordinal date for the first day of any month as the number of days from January 1 of the year. For example, January 1, 1992 has a New Year’s date of 142810 and an ordinal date of 1, and May 1, 1992 has an ordinal date of 121 which is the sum of the lengths of the months previous to May. If we number the days of the week from 0 to 6, inclusive, with Sunday as 0, then the number of the day of the week for any date is the 7-residue of the sum of the New Year’s date for the year and the ordinal date for the month. For example, May 1, 1992 falls on a Friday since
where the verb dayno defined in the previous section gives the 7-residue, is equal to 5.
The calculation of the New Year’s and ordinal dates requires a test for leap year. A simple test follows from the observation that a year is a leap year if its number is evenly divisible by either one or three of the divisors 4, 100 and 400, and is given by the verb
where the verb mod defined in the previous section gives the remainders and the monad 0&(~:/ . =) provides a parity check on the number of zero remainders. For example, ly 1992 is 1 and each of ly 1991 and ly 1900 is 0. Given this leap year test we may define the monadic verb
which gives a list of the month lengths with the length of February adjusted for leap year. We may also define the dyadic verb
which gives the length of the month given as the left argument where 0 represents January, 1 represents February, etc. and the right argument gives the year number.
The New Year’s date for any year is the number of days from January 1, 1600 to January 1 of the given year, and is one more than 365 times the number of years plus the number of leap years in this interval. This latter number may be found as the integer quotient of the year number minus 1600 divided by 4, less the integer quotient of this same difference divided by 100 to adjust for all centennial years, plus the difference divided by 400 to account for leap years on every fourth centennial year. Thus the number of leap years is the alternating sum of the appropriate quotients. Therefore, the New Year’s date is given by the monadic verb
The ordinal date for any month, the sum of the lengths of the months preceding the given month, is given by
where the left argument gives the month number in 0-origin indexing and the right argument gives the year number. Finally, the negative of the day number of the first day of any month of any year is
where the left and right arguments give the month number and year number, respectively.
Now the numerical part of a month calendar consists of the consecutive integers from 1 to an upper limit determined by the month length arranged in a table of six rows since any month except February may extend over six consecutive weeks, and seven columns since there are seven days in the week, and beginning in the first row in a column determined by the first day of the month. This array may be constructed simply by first generating the appropriate list of positive integers as determined by the month length, converting to a one-column table, formatting to a three-column character table, extending this table to forty-two rows, rotating the rows by an amount given by the day number of the first day of the month, and finally reshaping into the appropriate table. These operations are performed by the verb
where the left and right arguments give the month and year numbers.
Assembling the Calendar¶
To obtain the desired year calendar the twelve month calendars must be constructed each with column headings for the names of the days of the week and headed overall with the month name, and finally displayed in one of several possible rectangular arrangements. Thus
where
centres the month name, gives a labelled month calendar. The dyadic verb
will give month calendars as determined by the left argument for the year given by the right argument. For example, 3 4 cal 1992 gives a 1992 calendar arranged in three rows and four columns as the 2-cells of a table of shape 3 4 8 21, and 3 cal 1992 gives the first three months of the 1992 calendar as the 2-cells of a table of shape 3 8 21. Finally,
gives a four-by-three calendar for the year specified by the right argument, and has been used to construct the 1992 calendar given in Figure 1.
Figure 2 gives the script file containing all of the verbs discussed in this paper.
Comparison with APL functions¶
The method used to calculate the Gregorian calendar in this paper is similar to that given in APL by Eugene McDonnell. The test for leap year using a dot product for a parity check and the calculation of the number of leap years using an alternating sum are due to McDonnell. Zero suppression, which McDonnell said might give a "spot of trouble" in APL, has been handled very simply in J. The main difference between the two methods lies in the approach to constructing the calendars for all months of the year. The APL functions required what may be termed a global approach where all month calendars were constructed at the same time and then reshaped into the appropriate array.
With J the approach is local with attention being given to the construction of a typical month calendar and then extending the calculations to all months of the year using the rank conjunction. A similar approach was taken in calendar calculations done by the author in Nial where the transformer EACH was used. Indeed, the defined conjunction each=. &.> was used in an earlier version of the J verbs. We might note in conclusion that Trenchard More has compared the local and global approaches to computation by remarking that "Data are simple when viewed locally."
Acknowledgement¶
I would like to thank Eugene McDonnell for bringing to my attention simplifications in some of the verbs used in an earlier version of this paper. His suggestions included the use of the conjunction rank in place of the defined adverb each, and a nice use of the verb take for zero suppression in place of an inelegant defined verb that was originally used for formatting.
References¶
Iverson, K. E., 1992. An Introduction to J. Iverson Software Inc., Toronto.
McDonnell, E. E., 1979. "Making a calendar." APL Quote Quad, vol. 10, no. 1, pp. 23 - 26.
+---------------------+---------------------+---------------------+
| Jan | Feb | Mar |
| Su Mo Tu We Th Fr Sa| Su Mo Tu We Th Fr Sa| Su Mo Tu We Th Fr Sa|
| 1 2 3 4| 1| 1 2 3 4 5 6 7|
| 5 6 7 8 9 10 11| 2 3 4 5 6 7 8| 8 9 10 11 12 13 14|
| 12 13 14 15 16 17 18| 9 10 11 12 13 14 15| 15 16 17 18 19 20 21|
| 19 20 21 22 23 24 25| 16 17 18 19 20 21 22| 22 23 24 25 26 27 28|
| 26 27 28 29 30 31 | 23 24 25 26 27 28 29| 29 30 31 |
| | | |
+---------------------+---------------------+---------------------+
| Apr | May | Jun |
| Su Mo Tu We Th Fr Sa| Su Mo Tu We Th Fr Sa| Su Mo Tu We Th Fr Sa|
| 1 2 3 4| 1 2| 1 2 3 4 5 6|
| 5 6 7 8 9 10 11| 3 4 5 6 7 8 9| 7 8 9 10 11 12 13|
| 12 13 14 15 16 17 18| 10 11 12 13 14 15 16| 14 15 16 17 18 19 20|
| 19 20 21 22 23 24 25| 17 18 19 20 21 22 23| 21 22 23 24 25 26 27|
| 26 27 28 29 30 | 24 25 26 27 28 29 30| 28 29 30 |
| | 31 | |
+---------------------+---------------------+---------------------+
| Jul | Aug | Sep |
| Su Mo Tu We Th Fr Sa| Su Mo Tu We Th Fr Sa| Su Mo Tu We Th Fr Sa|
| 1 2 3 4| 1| 1 2 3 4 5|
| 5 6 7 8 9 10 11| 2 3 4 5 6 7 8| 6 7 8 9 10 11 12|
| 12 13 14 15 16 17 18| 9 10 11 12 13 14 15| 13 14 15 16 17 18 19|
| 19 20 21 22 23 24 25| 16 17 18 19 20 21 22| 20 21 22 23 24 25 26|
| 26 27 28 29 30 31 | 23 24 25 26 27 28 29| 27 28 29 30 |
| | 30 31 | |
+---------------------+---------------------+---------------------+
| Oct | Nov | Dec |
| Su Mo Tu We Th Fr Sa| Su Mo Tu We Th Fr Sa| Su Mo Tu We Th Fr Sa|
| 1 2 3| 1 2 3 4 5 6 7| 1 2 3 4 5|
| 4 5 6 7 8 9 10| 8 9 10 11 12 13 14| 6 7 8 9 10 11 12|
| 11 12 13 14 15 16 17| 15 16 17 18 19 20 21| 13 14 15 16 17 18 19|
| 18 19 20 21 22 23 24| 22 23 24 25 26 27 28| 20 21 22 23 24 25 26|
| 25 26 27 28 29 30 31| 29 30 | 27 28 29 30 31 |
| | | |
+---------------------+---------------------+---------------------+
Figure 1. Calendar for 1992.
NB. Utilities
pi=. >: @ i.
div=. <. @ % & 4 100 400
mod=. 4 100 400 & |
dayno=. 7&|
NB. Constants
DAYS=. ' Su Mo Tu We Th Fr Sa'
MONTHS=. 'JanFebMarAprMayJunJulAugSepOctNovDec'
LENGTHS=. 31 28 31 30 31 30 31 31 30 31 30 31
NB. Month name centered
mn=. _12&{.@]@{&(_3]\MONTHS)
NB. Leap year test
ly=. 0&(~:/ . =) @ mod
NB. Month lengths adjusted for leap year
LENGTHSadj=. LENGTHS&+@((LENGTHS=28)&(*. ly))@]
NB. Month length
ml=. {LENGTHSadj
NB. New Year's date
nydate=. >:@(365&* + -/@div)@(]@-&1601)
NB. Ordinal date
odate=. +/ @ ({.LENGTHSadj)
NB. First day of month
mb=. -@dayno @ (odate + nydate@])
NB. Month calendar without headings
mctable=. ,"_1@(6 7&$)@(mb |. (42&{.)@(3&":)@,.@pi@ml)
NB. Month calendar
mc=.(mn@[), (DAYS&,@mctable)
NB. Calendar for given number of months
cal=. (i.@[)mc"0]
NB. Calendar with 4 rows & 3 columns
calendar=. <"2@(4 3&cal)
Figure 2. Script file.