Making a Simple Calendar
Date:   ±Y  M  D   (Neg=BC)
Calendar Mode:    Julian              Gregorian 
DATE ±ISOymd = 20170623 = 2017 06 23 
             = 2017 June 23 (Gregorian Calendar)
             = Friday

JD = 2457928 = Standard Gregorian JD number for the date

DoWDate = 5 = Friday
DoW1    = 4 = Thursday (DoW of 1st day of June)
mDays   = 30 days in June

For June of 2017 (Gregorian), we would construct
a 30-day calendar beginning on a Thursday.

---------------------
G 2017          June

Su Mo Tu We Th Fr Sa
             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
---------------------
 
G 2017   June
SunMonTueWedThuFriSat
        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  

The BASICS OF MAKING A STANDARD CALENDAR FOR ANY DATE


To construct a calendar for any given date, we can break down the process into 4 essential steps.
  1. Compute the standard calendrical JD number for the given date.
  2. Determine the day of the week on which the given date falls.
  3. Determine the day of the week on which the month containing the given date begins.
  4. Determine the number of days in the month containing the given date.
Once we know on what day of the week any given month of any given year begins and the number of days in that month, then we have all the information we need to construct a standard calendar for that month.


Step 1:

Compute The Standard Calendrical JD (Julian Day) Number For the Given Date

NOTE:
Here, the calendrical JD number is being distinguished from the astronomical JD number in that the time of day is ignored.  The calendrical JD number simply serves its original purpose as a unique, linear, integer serial number, one for each date on the standard calendar. There are some rare historical deviations from the standard calendar formula, but those special cases are not being considered here.

The JD number is the single most important number we will use for a variety of general Julian and Gregorian calendar computations.  It contains all the information we need to create a complete standard calendar for any month of any year over a very long time period extending thousands of years into the past, prior to the actual dates either calendar officially existed, as well as thousands of years into the theoretical future.

To construct a calendar, we begin by computing the simple calendrical JD (Julian Day) number for the given calendar date and calendar mode.  This simple calendrical JD number will always equate to a positive integer value, measured forward from origin JD=0 in the distant past.

The prehistoric mathematical origin of the Julian calendar model is:
JD=0  on  4713 BC Jan 01 = Monday

The prehistoric mathematical origin of the Gregorian calendar model is:
JD=0  on  4714 BC Nov 24 = Monday

Since each calendar system begins with JD=0 being on a Monday and every 7th day thereafter is a Monday, this leads to a simple formula to derive the day of the week (DoW) directly from the JD number.  This formula will follow later.  We have to compute the JD number first of all.

In the simplest terms, the JD number for any given date is the serial count of the number of days on the calendar that have passed to date since the mathematical origin of the respective calendar system model.

For example, the current Universal Gregorian Date is:
2017 Jun 23, for which JD=2457928, which means that today is sequential calendar day number 2457928, as reckoned from the mathematical origin (JD=0) of the Gregorian calendar system that began on Monday, November 24th, 4714 BC.

Every date on the calendar has such a unique JD serial number reckoned from the origin.  Since it works like a linear yardstick, the difference between the JD numbers of any two dates equates to the exact number of calendar days between those two dates, which includes accounting for any leap years in between as well.

Compute the simple calendrical JD (Julian Day) number for any given integer-encoded date and calendar mode.  The numerical value of this JD number will always equate to a positive integer value.

ISOymd  = ISO integer-encoded date value (Negative = BC date)
CalMode = Calendar mode (0=Julian  or  1=Gregorian)
 YearSignVal = (ISOymd < 0)? -1 : 1
 u = abs(ISOymd)
 v = floor(u / 10000)

 y = YearSignVal * v
 m = floor((u - 10000*v) / 100)
 d = u - 10000*v - 100*m

 w = (y < 0)? y+1 : y

 a = floor((14-m) / 12)
 b = w - a
 c = floor(b/100)

 JD = floor(30.6001*(12*a + m + 1))
    + floor(365.25*(b + 4716)) - 1524
    + CalMode*(floor(c/4) - c + 2) + d
 JD EXAMPLE: For the interface date entered above.

 ISOymd  = 20170623 = 2017 June 23
 CalMode = 1 (Gregorian)

 -----------------------------------------------------------
 YearSignVal = ((2017 < 0)? -1 : 1) = 1

 u = abs(20170623) = 20170623
 v = floor(20170623 / 10000) = 2017

 y = 1 * 2017 = 2017
 m = floor((20170623 - 10000*2017) / 100) = 6
 d = 20170623 - 10000*2017 - 100*6 = 23

 w = ((2017 < 0)? 2017+1 : 2017) = 2017

 a = floor((14-6) / 12) = 0
 b = 2017 - 0 = 2017
 c = floor(2017/100) = 20

 JD = floor(30.6001*(12*0 + 6 + 1)) = 214
    + floor(365.25*(2017 + 4716)) - 1524 = 2457704
    + 1*(floor(20/4) - 20 + 2) + 23 = 10

    = 214 + 2457704 + 10 = 2457928



Step 2:

Determine the Day of the Week (DoW) On Which the Given Date Falls

From the calendrical JD serial number for the given date, we can determine the corresponding day of the week (DoW) index.  This is simply a number code from 0 to 6, interpreted to represent the days of the week from Sunday to Saturday respectively.  The formula is based on the fact that both calendar system models begin (JD=0) on a Monday (DoW=1), by definition, and reckoned cyclically forward from there, every 7th day is a Monday.

Compute the day-of-the-week (DoW) index from the standard Julian Day (JD) number.  The same formula applies to both the Julian and Gregorian calendars.

JD = Calendrical JD number for given date
DoW = Day of the week index code corresponding to JD
DoW = (JD + 1) mod 7
Where the DoW indices are:  0=Sun,  1=Mon,  2=Tue,  3=Wed,  4=Thu,  5=Fri  and  6=Sat

DoW EXAMPLE: For the interface date entered above.

 ISOymd = 20170623 = 2017 June 23 (Gregorian Calendar)

     JD = 2457928

DoW = (JD + 1) mod 7
    = 2457929 mod 7 = 5 = Friday




Step 3.

Determine the Day of the Week On Which the Month Containing the Given Date Begins

Given the day of the month and its corresponding day of the week index, we can proceed to find the day of the week on which the month containing the given date begins.

The following algorithm applies equally to both the Julian and Gregorian calendar systems.
Given the day of the week index corresponding to any given date, compute the day of the week on which the month containing the given date begins.

d = Day of the month (1  to  31)
DoWDate = DoW of the given date (d)
DoW1 = DoW of 1st day of the month containing the given date
DoW1 = (DoWDate + 7 - ((d-1) mod 7)) mod 7
Where the DoW indices are:  0=Sun,  1=Mon,  2=Tue,  3=Wed,  4=Thu,  5=Fri  and  6=Sat

DoW1 EXAMPLE: For the interface date entered above.

 ISOymd = 20170623 = 2017 June 23 (Gregorian Calendar)
      d = 23
DoWDate = 5 = Friday

DoW1 = (DoWDate + 7 - ((d-1) mod 7)) mod 7
     = (5 + 7 - (22 mod 7)) mod 7 = 4 = Thursday

On the Gregorian calendar:
If June 23, 2017 is Friday, then that month begins on a Thursday.




Step 4.

Determine the Number of Days in the Month Containing the Given Date

In practice, every month has a constant number of days, either 30 or 31 days, with the exception of February, which has 28 days or, in the case of a leap year, 29 days.

One simple way of creating a function to return the number of days in a given month, is to store the number of days in an indexed array (i=0  to  m-1).  Then, given the month number (m), we can fetch the corresponding number of days directly from the array.

By this scheme, the number of days in the month of September (m=9) could be symbolized as
mDays = DaysInMonth[m-1] = DaysInMonth[i] = DaysInMonth[8] = 30

Then there is the leap year adjustment to be made for February, when applicable.

Two different approaches will be considered here.  One uses the number of days stored in an array, as mentioned above, and the other method is a purely logical formulation based on a simple fortuitous pattern found in the source data and translated into an algorithm.

Get the number of days in any given month of any given year.  The number of days in the months are held in an indexed array, from which the values can easily be extracted according to the numerical value of the month.  For leap years, a special adjustment is made for February.

DaysInMonth = Indexed array holding the number of days in each month
          y = Year (Negative = BC)
          m = Month number (1  to  12)
       leap = Leap year flag (1=Leap  or  0=Common)
      mDays = Number of days in given month of given year
DaysInMonth = array (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

mDays = DaysInMonth[m-1]

w = (y < 0)? y+1 : y

if (CalMode == 0)
   {
    leap = (w mod 4 == 0)? 1:0
   }
else
   {
    leap = ((!(w mod 4) && (w mod 100)) || !(w mod 400))? 1:0
   }

if (m == 2 && leap == 1)  {mDays = 29}

This does the same as the above, but using a more direct algorithmic approach, without using any array.
w = (y < 0 )? y+1 : y

if (CalMode == 0)
   {
    leap = (w mod 4 == 0)? 1:0
   }
else
   {
    leap = ((!(w mod 4) && (w mod 100)) || !(w mod 400))? 1:0
   }

mDays = 30 - ((m < 8)? -1:1)*(m mod 2) + floor(m/8) - ((m == 2)? 2:0)
      + ((m == 2 && leap == 1)? 1:0)



SUMMARY

The above algorithms provide the foundation for creating a simple perpetual calendar program.

DATE ±ISOymd = 20170623 = 2017 06 23 
             = 2017 June 23 (Gregorian Calendar)
             = Friday

Putting the above algorithms together, we determine:

JD = 2457928 = Standard Gregorian JD number for the date

DoWDate = (JD + 1) mod 7 = DoW of the given date
        = 2457929 mod 7 = 5 = Friday

DoW1 = (DoWDate + 7 - ((d-1) mod 7)) mod 7 = DoW of 1st day of June
     = (5 + 7 - (22 mod 7)) mod 7 = 4 = Thursday

mDays = 30 days in June

For June of 2017 (Gregorian), we would construct
a 30-day standard calendar beginning on a Thursday.

---------------------
G 2017          June

Su Mo Tu We Th Fr Sa
             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
---------------------
 



© Jay Tanner - PHP Science Labs - 2017