CHAPTER 7

Days and Weeks

Days

Zeller's congruence is a complicated looking formula that calculates the day of the week (Sunday, Monday, etc.) for any given date. Using this formula you could, for example, find out on which day of the week a person was born. And, if your memory is bad, you could find out on what day of the week a certain anniversary occurred.
   The following is Zeller's formula:

A =INT(2.6*M - 0.01) + D + Y + INT(Y/4) + INT(C/4)
-2*C
X =A MOD 7

The number X is a number between 0 and 6, because all multiples of 7 smaller than A have been subtracted from A by using the MOD function. (Remember that the expression X = A MOD 7 is equivalent to the expression X = A - 7*INT(A/7).) The resulting number X represents the 7 days of the week as follows:

   0 : Sunday
   1 : Monday
   2 : Tuesday
   3 : Wednesday
   4 : Thursday
   5 : Friday
   6 : Saturday

The numbers D, M, Y and C are defined as:
   D :   the day of the month.
   M :   the number of the month - but not the standard number. January and February are numbers 11 and 12 of the preceding year (affecting Y and possibly C described below). March is number 1, April is 2, May is 3, . . ., and December is number 10.
   Y :   the year in the century.
   C :   the number of hundreds in the year, in other words, the first two digits in the year number.

For instance, if the date is 26th August 1983 then the standard way of expressing this is 26/08/1983. For Zeller's formula we use D = 26, M = 6, Y = 83 and C = 19.
   Substituting these values into Zeller's formula gives:

      A    =   INT(2.6*6 - 0.1) + 26 + 83 + INT(83/4) + INT(19/4)
            - 2*19
         =   INT(15.6 - 0.1) + 26 + 83 + INT(20.75) + INT(4.75) - 38
         =   15 + 26 + 83 + 20 + 4 - 38
         =   110

and

      X   =   110 MOD 7
         =   110 - 7*INT(110/7)
         =   110 - 7*15
         =   5

Thus we conclude that the day of the week of 26th August 1983 was Friday.
   Here are some examples showing the standard date format and the value that Zeller's formula uses.

STANDARD NOTATIONZELLER'S FORMULA NOTATION
DMCY
03/03/1947311947
01/01/20001111999
26/02/198326121982
29/11/19842991984

The next program uses Zeller's formula to calculate the day of the week for any specified date. Your computer will automatically calculate the correct values of D, M, C and Y from any date you input. Observe that the program makes a few checks to ensure that the date entered makes sense. Thus, for instance, 30th February 1983 will not be accepted. In addition the year entered must be an integer in the range 1752 to 4902. Zeller's formula applies in the range 1582 to 4902, but the Gregorian calendar has been used in Britain, the British Colonies and the USA only since 1752.
   Leap years are automatically taken care of in the program. Note that a year is a leap year if the year number is exactly divisible by 4, unless it is divisible by 100 but not divisible by 400. Thus 1900 was not a leap year but 2000 will be a leap year.

Listing 7.1
LIST

   10 REM Day of week
   20 MODE 1:COLOUR 3:PRINT ' TAB(14);"D
ay of week"':@%=10
   30 PRINT "This program calculates the
 day of the  week for any date specified
.";
   40 DIM A%(12),A$(12):FOR I=1 TO 12:RE
AD A%(I),A$(I):NEXT
   50 DIM B$(6):FOR I=0 TO 6:READ B$(I):
NEXT
   60 VDU 19,1,5,0,0,0
   70 REPEAT
   80  COLOUR 1:PRINT ''"Type in the dat
e:"
   90  REPEAT
  100   A%(2)=29:TEST=-1
  110   INPUT '"  Enter day, 1 to 31: ";
D
  120   IF D<1 OR D>31 OR D<>INT(D) THEN
 COLOUR 3:PRINT '"An integer between 1 a
nd 31 please.":COLOUR 1:TEST=0
  130   IF TEST THEN PROCMonth
  140   IF TEST:IF D>A%(M) THEN COLOUR 3
:PRINT '"Not enough days in ";A$(M);".":
COLOUR 1:TEST=0
  150   IF TEST THEN PROCYear
  160   IF TEST:IF M=2 AND D>A%(2) THEN 
COLOUR 3:PRINT '"There are 28 days in Fe
bruary.":COLOUR 1:TEST=0
  170  UNTIL TEST
  180  COLOUR 2:PRINT '; D;" ";A$(M);" "
;Y;" is/was a ";
  190  REM Change format of input detail
s
  200  M=M-2:IF M<1 THEN M=M+12:Y=Y-1
  210  C=INT(Y/100):Y=Y-C*100
  220  REM Zeller's congruence
  230  DAY=INT(2.6*M-0.1)+D+Y+INT(C/4)+I
NT(Y/4)-2*C
  240  DAY=DAY MOD 7
  250  PRINT ;B$(DAY);"day."
  260  COLOUR 3:PRINT CHR$(7) ' TAB(10);
"Another go? Y or N ";
  270  REPEAT:G$=GET$:UNTIL G$="Y" OR G$
="N"
  280 UNTIL G$="N"
  290 CLS:PRINT '"Bye for now.":END
  300 DEF PROCMonth
  310 REPEAT
  320  INPUT '"Enter month, 1 to 12: ";M
  330  IF M<1 OR M>12 OR M<>INT(M) THEN 
COLOUR 3:PRINT '"An integer between 1 an
d 12!":COLOUR 1
  340 UNTIL M>0 AND M<13 AND M=INT(M)
  350 ENDPROC
  400 DEF PROCYear
  410 REPEAT
  420  INPUT '" Enter year, in full: ";Y
  430  IF Y<1582 OR Y>4902 THEN COLOUR 3
:PRINT '"Year is not in range.":COLOUR 1
  440  IF Y<>INT(Y) THEN COLOUR 3:PRINT 
'"Not a year - try again.":COLOUR 1
  450 UNTIL Y=INT(Y) AND Y>1582 AND Y<49
03
  460 REM Check for leap year
  470 L=0:IF INT(Y/4)*4=Y THEN L=-1
  480 IF L AND INT(Y/100)*100=Y THEN L=0
:IF INT(Y/400)*400=Y THEN L=-1
  490 A%(2)=28-L:IF L THEN PRINT '"The y
ear is/was a leap year."
  500 ENDPROC
  600 REM Data
  610 DATA 31,January,29,February,31,Mar
ch,30,April
  620 DATA 31,May,30,June,31,July,31,Aug
ust
  630 DATA 30,September,31,October,30,No
vember,31,December
  640 DATA Sun,Mon,Tues,Wednes,Thurs,Fri
,Satur


RUN

              Day of week

This program calculates the day of the  
week for any date specified.

Type in the date:

  Enter day, 1 to 31: ?25

Enter month, 1 to 12: ?12

 Enter year, in full: ?1983

25 December 1983 is/was a Sunday.

          Another go? Y or N 


Note: You may have come across Zeller's formula before and possibly noticed that the formula used here is slightly different. Often the first term INT(2.6*M - 0.1) is written as INT(2.6*M - 0.2) instead. This latter form is not used here because of the way the BBC and Electron calculate the INTegral part of numbers. Try M = 7, then

   INT(2.6*7 - 0.2)   = INT(18.2 - 0.2)
      = INT(18)
      = 18

However, you'll find that your computer returns the value of INT(2.6*7 - 0.2) as 17, even though if you ask it to print 2.6*7 - 0.2 it prints 18 correctly.

Calendar

Once we know the day of the week of any date we can produce a calendar. The next program prints a calendar for any month in any year. (Only one month can be displayed reasonably on the screen.) The program calculates the day on which the first day of that month occurs by using Zeller's formula. The remaining days are then printed out. As in the Day of the Week program, leap years are automatically taken care of.

Listing 7.2
LIST

   10 REM Calendar
   20 MODE 1:COLOUR 3:PRINT ' TAB(16);"C
alendar"':@%=10
   30 PRINT "This program prints a calen
dar for any  month of any year specified
.";
   40 DIM A%(12),A$(12):FOR I=1 TO 12:RE
AD A%(I),A$(I):NEXT
   50 REPEAT
   60  VDU 19,1,5,0,0,0
   70  COLOUR 1:PRINT ''"Type in the mon
th and year:"
   80  PROCMonth
   90  PROCYear
  100  A$=A$(M)+" "+STR$(Y):MM=A%(M)
  110  REM Change format of input detail
s
  120  M=M-2:IF M<1 THEN M=M+12:Y=Y-1
  130  C=INT(Y/100):Y=Y-C*100
  140  REM Zeller's congruence
  150  DAY=INT(2.6*M-0.1)+1+Y+INT(C/4)+I
NT(Y/4)-2*C
  160  DAY=DAY MOD 7
  170  REM Print Calendar
  180  CLS:VDU 19,1,6,0,0,0:PRINT '' TAB
(20-LEN(A$)/2);A$
  190  COLOUR 1:PRINT '"   Sun  Mon  Tue
  Wed  Thu  Fri  Sat"':COLOUR 2
  200  FOR I=1 TO MM
  210   DAY=DAY+1
  220   PRINT TAB(DAY*5-1+(I>9));I;
  230   IF DAY>6 THEN DAY=0:PRINT ''
  240  NEXT
  250  COLOUR 3:PRINT CHR$(7) ''' TAB(10
);"Another go? Y or N ";
  260  REPEAT:G$=GET$:UNTIL G$="Y" OR G$
="N"
  270 UNTIL G$="N"
  280 CLS:PRINT '"Bye for now.":END
  300 DEF PROCMonth
  310 REPEAT
  320   INPUT '"Enter month, 1 to 12: ";
M
  330  IF M<1 OR M>12 OR M<>INT(M) THEN 
COLOUR 3:PRINT '"An integer between 1 an
d 12!":COLOUR 1
  340 UNTIL M>0 AND M<13 AND M=INT(M)
  350 ENDPROC
  400 DEF PROCYear
  410 REPEAT
  420  INPUT '" Enter year, in full: ";Y
  430  IF Y<1752 OR Y>4902 THEN COLOUR 3
:PRINT '"Year is not in range.":COLOUR 1
  440  IF Y<>INT(Y) THEN COLOUR 3:PRINT 
'"Not a year - try again.":COLOUR 1
  450 UNTIL Y=INT(Y) AND Y>1581 AND Y<49
03
  460 REM Check for leap year
  470 L=0:IF INT(Y/4)*4=Y THEN L=-1
  480 IF L AND INT(Y/100)*100=Y THEN L=0
:IF INT(Y/400)*400=Y THEN L=-1
  490 A%(2)=28-L:IF L THEN PRINT '"The y
ear is/was a leap year."
  500 ENDPROC
  600 REM Data
  610 DATA 31,January,29,February,31,Mar
ch,30,April
  620 DATA 31,May,30,June,31,July,31,Aug
ust
  630 DATA 30,September,31,October,30,No
vember,31,December


RUN

                Calendar

This program prints a calendar for any  
month of any year specified.

Type in the month and year:

Enter month, 1 to 12: ?2

 Enter year, in full: ?1984

The year is/was a leap year.

             February 1984

   Sun  Mon  Tue  Wed  Thu  Fri  Sat

                   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

          Another go? Y or N 

Data management

Occasionally there is need to provide a listing of dates that are a specified number of days apart. For instance, treatment days at a hospital, and pay days.
   To produce such a listing we use the 'pseudo-Julian' date. This date is simply the number of days since some fixed date. (In fact the First of January of the year 1 has a pseudo-Julian date of 1.) A relatively simple formula converts the real date to the pseudo-Julian date and vice versa.
   If the date is D/M/Y where D is the day, M the month number and Y the year (including the century) then the pseudo-Julian date is calculated as follows:

   X = INT(30.57*M) + INT(395.25) + D
   IF M > 2 and Y is a leap year then subtract 1 from X.
   If M > 2 and Y is not a leap year then subtract 2 from X.

For example, let's calculate the pseudo-Julian date of 26th August 1983. The values of D, M and Y are given by D = 26, M = 8, Y = 1983. Substituting these values into the formula gives the following:
   X   = INT(30.57*8) + INT(365.25*1983 - 395.25) + 26
      = INT(244.56) + INT(723895.5) + 26
      = 244 + 723895 + 26
      = 724165

However, since the month number M is greater than 2 and 1983 is not a leap year we subtract 2 from X to give a pseudo-Julian date of 724163.
   To calculate the date from the pseudo-Julian date proceed as follows, where X is the pseudo-Julian date.

   The first approximation to the year is given by:
   Y = INT(X/365.26) + 1
   The day within the year is given by:
   D = X - INT(365.25*Y - 395.25)
   A leap year adjustment is made:
   D1 = 2, if it is a leap year then D1 = 1
   If D>91 - D1 then add D1 to D
   Calculate the month and day:
   M = INT(D/30.57)
   D = D - INT(30.57*M)
   Adjust month and year if necessary:
   If M > 12 then set M to 1 and add 1 to Y.

For example, let's calculate the date corresponding to a pseudo-Julian

   Y   = INT(724164/365.26) + 1
      = INT(1982.5987) + 1
      = 1983

   D   = 724164 - INT(365.25*1983 - 395.25)
      = 724164 - INT(724290.75 - 395.25)
      = 724164 - INT(723895.5)
      = 269

The year 1983 is not a leap year so that D1 is 2. The value of D is greater than 91 - D1 and so we add D1 to D. Thus the value of D is now given by

   D   = 271
   M   = INT(271/30.57)
      = INT(8.86490023)
      = 8

   D   = 271 - INT(30.57*8)
      = 271 - INT(244.56)
      = 271 - 244
      = 27

   The value of M is not greater than 12 and so we are finished, with values of D = 27, M = 8 and Y = 1983. Thus the date corresponding to the pseudo-Julian date of 724164 is 27th August 1983.
   The next program performs all the above sorts of calculations quickly and provides a listing of dates that are a specified number of days apart. For convenience the program only works for dates in the 20th century. You should be able to make any changes necessary for another century quite easily.

Warning. Dates are entered in the form DD/MM/YY, for example 12th March 1984 would be entered as 12/03/84 or 12/ 3/84 but not as 12/3/84. Not too many checks have been made for the date entered, and you could, for instance, enter 30/02/83. The program would think of this date as 2nd March 1983 (can you see why?).

Listing 7.3
LIST

    10 REM Date management
   20 MODE 1:COLOUR 3:PRINT ' TAB(12);"D
ate management"':@%=10
   30 PRINT "This program provides the l
isting of    dates that are a specified 
number of    days apart."'
   40 REM Enter start date, not many che
cks are made!
   50 COLOUR 1:PRINT '"Type in date as D
D/MM/YY, eg 15/02/84"
   60 REPEAT
   70  INPUT '"Enter start date: ";S$
   80  TEST=-1
   90  IF LEN(S$)<>8 THEN COLOUR 3:PRINT
 '"In the form DD/MM/YY please.":COLOUR 
1:TEST=0
  100  IF TEST:IF MID$(S$,3,1)+MID$(S$,6
,1)<>"//" THEN COLOUR 3:PRINT '"Use    /
  /   please.":COLOUR 1:TEST=0
  110  IF TEST:D=VAL(MID$(S$,1,2)):M=VAL
(MID$(S$,4,2)):Y=VAL(MID$(S$,7,2))+1900
  120  IF TEST:IF D<1 OR D>31 OR M<0 OR 
M>12 THEN COLOUR 3:PRINT '"Day, Month er
ror.":COLOUR 1:TEST=0
  130 UNTIL TEST
  140 REM Date form is in a reasonably c
orrect form
  150 REM Calculate the pseudo-Julian da
y
  160 X=INT(30.57*M)+INT(365.25*Y-395.25
)+D
  170 REM Adjust for leap year
  180 IF M>2 THEN X=X-2:IF INT(Y/4)*4=Y 
THEN X=X+1
  190 REM Enter interval of days
  200 PRINT '"Enter interval in days bet
ween dates."
  210 REPEAT
  220  INPUT '"Interval: ";P
  230  IF P<1 OR INT(P)<>P THEN COLOUR 3
:PRINT '"A positive integer please.":COL
OUR 1
  240 UNTIL P>0 AND INT(P)=P
  250 PRINT '"Enter the number of times 
interval is   required."
  260 REPEAT
  270  INPUT '"Number: ";N
  280  IF INT(N)<>N THEN COLOUR 3:PRINT 
'"A whole number please.":COLOUR 1
  290  IF N<1 OR N>100 THEN COLOUR 3:PRI
NT '"Be reasonable.":COLOUR 1
  300 UNTIL N>0 AND N<101 AND N=INT(N)
  310 COLOUR 2:PRINT ''
  320 FOR I=1 TO N
  330  Y=INT(X/365.26)+1 : REM Year
  340  D=X-INT(365.25*Y-395.25)
  350  REM Leap year adjustment
  360  D1=2:IF INT(Y/4)*4=Y THEN D1=1
  370  IF D>91-D1 THEN D=D+D1
  380  M=INT(D/30.57) : REM Month
  390  D=D-INT(30.57*M) : REM Day
  400  IF M>12 THEN M=1:Y=Y+1 : REM Year
 adjustment
  410  Y=Y-1900
  420  REM Output to display
  430  PROCForm(D):D$=Z$+"/"
  440  PROCForm(M):D$=D$+Z$+"/"
  450  PROCForm(Y):D$=D$+Z$+"  "
  460  PRINT D$;
  470  X=X+P : REM Interval added
  480 NEXT
  490 COLOUR 3:PRINT CHR$(7) ''' TAB(10)
;"Another go? Y or N ";
  500 REPEAT:G$=GET$:UNTIL G$="Y" OR G$=
"N"
  510 IF G$="Y" THEN RUN
  520 CLS:PRINT '"Bye for now.":END
  530 DEF PROCForm(Z)
  540 Z$=STR$(Z):IF LEN(Z$)<2 THEN Z$="0
"+Z$
  550 ENDPROC

RUN

            Date management

This program provides the listing of    
dates that are a specified number of    
days apart.


Type in date as DD/MM/YY, eg 15/02/84

Enter start date: ?01/01/84

Enter interval in days between dates.

Interval: ?7

Enter the number of times interval is   
required.

Number: ?32



01/01/84  08/01/84  15/01/84  22/01/84  
29/01/84  05/02/84  12/02/84  19/02/84  
26/02/84  04/03/84  11/03/84  18/03/84  
25/03/84  01/04/84  08/04/84  15/04/84  
22/04/84  29/04/84  06/05/84  13/05/84  
20/05/84  27/05/84  03/06/84  10/06/84  
17/06/84  24/06/84  01/07/84  08/07/84  
15/07/84  22/07/84  29/07/84  05/08/84 


          Another go? Y or N