| home | send comment | send link | add bookmark |

Perpetual Calendar Calculator

by Stephen R. Schmitt


Introduction

Pope Gregory instituted the Gregorian calendar that is in common use today. In 1582 AD, the Julian calendar, in use since 45 BC, introduced an error of one day in every 128 years that had moved the date of the vernal equinox to March 11. The new calendar restored the vernal equinox to March 21. The numerical algorithm of the Gregorian calendar was devised by the Neapolitan astronomer-physician Aloysius Lilius (Luigi Lilio Ghiraldi). It took effect in Europe's Roman Catholic countries in October of 1582. In that month, October 4, 1582 was followed by October 15, 1582. Protestant countries continued to use the Julian calendar until the 1700's or later.

Algorithm

The algorithm will calculate monthly Gregorian calendars. The results are valid whenever and wherever the Gregorian calendar is in use.

It adjusts the number of days in February for a leap year. In the Gregorian calendar, a common year contains 365 days. A year is a leap year of 366 days if it is exactly divisible by 4 except for century years that are not divisible by 400. These are also common years; that is, 1900 and 2100 are not leap years while 2000 is a leap year.

The Julian Day is computed in order to calculate the weekday of the first day of the month. The Julian Day is the total count of days from the date -4712 January 1, 12 hours Greenwich Mean Time or, more conventionally, 4713 BCE January 1, Noon at the Greenwich meridian.

Zeno source code

Zeno 1.2 is an interpreter for the Zeno programming language. It is an easy to learn and is suitable for educational purposes.


var C : array[42] of string

program

    var tm : real := localtime
    var yy : int  := dateyear( tm )
    var mm : int  := datemonth( tm )   
    put_month( mm, yy )

    repeat
        put "\nmonth, year"...
        get mm, yy
        put_month( mm, yy )
    until not another
    
end program
    
% print out table showing monthly calendar
procedure put_month( month, year : int )

    var i, jd, days, beg : int

    % compute julian day for year and month
    days := 0
    if (month <= 2) then 
        days := -1
    end if
        
    jd := 367*year 
        - floor(7*(year + floor((month + 9)/12))/4)
        + floor(275*month/9) 
        - floor(3*(floor((year + days)/100) + 1)/4) 
        + 1721031
    
    % get days in this month
    case month of
    value 4,6,9,11:
        days := 30                      % Apr, Jun, Sep, Nov
    value 2:
        days := 28                      % Feb normal
        if year mod 4 = 0 then
            if not((year mod 100 = 0) and 
                   (year mod 400 ~= 0)) then
                days := 29              % Feb leap year
            end if
        end if
    value:
        days := 31                      % other months
    end case

    % init with blanks
    for i := 1...42 do
        C[i] := "    "
    end for

    % day of week of first day of month
    beg := jd - 7*floor(jd/7)
    for i := 1...days do
        C[i+beg] := intstr(i, 4)
    end for

    % display month and year
    put "            "...
    case month of
    value  1: put "Jan"...
    value  2: put "Feb"...
    value  3: put "Mar"...
    value  4: put "Apr"...
    value  5: put "May"...
    value  6: put "Jun"...
    value  7: put "Jul"...
    value  8: put "Aug"...
    value  9: put "Sep"...
    value 10: put "Oct"...
    value 11: put "Nov"...
    value 12: put "Dec"...
    end case
    put ' ', year
    
    % display days
    put "   S   M   T   W   T   F   S"
    put C[1],  C[2],  C[3],  C[4],  C[5],  C[6],  C[7]
    put C[8],  C[9],  C[10], C[11], C[12], C[13], C[14]
    put C[15], C[16], C[17], C[18], C[19], C[20], C[21]
    put C[22], C[23], C[24], C[25], C[26], C[27], C[28]
    put C[29], C[30], C[31], C[32], C[33], C[34], C[35]
    put C[36], C[37], C[38], C[39], C[40], C[41], C[42]

end procedure

% ask user to continue or not
function another : boolean

    var ans : string
    put "another [Y|N]"...
    get ans
    return (ans[1] = 'Y') or (ans[1] = 'y')

end function

Sample output

            Mar 2004
   S   M   T   W   T   F   S
       1   2   3   4   5   6
   7   8   9  10  11  12  13
  14  15  16  17  18  19  20
  21  22  23  24  25  26  27
  28  29  30  31            
                            

month, year? 4 2005
            Apr 2005
   S   M   T   W   T   F   S
                       1   2
   3   4   5   6   7   8   9
  10  11  12  13  14  15  16
  17  18  19  20  21  22  23
  24  25  26  27  28  29  30
                            
another [Y|N]? n


Copyright © 2005, Stephen R. Schmitt