HP Forums

Full Version: (35S) calendar and date functions
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Since date functions and calendar programs seem to be en vogue these days, here is my contribution for the HP35s. It is essentially a small program that converts between common calendar dates and Julian day numbers. This allows for all essential date related functions:
  • Determining the weekday for a given date
  • Calculating the difference between two dates in days
  • Adding/subtracting a number of days to/from a given date
  • Checking dates for validity
The following program works with Julian day numbers (JDNs). As opposed to the familiar notation with day, month and year, JDNs are simple consecutive numbers. Every day has a unique JDN, and 100 days later the JDN has increased by 100 as well - it's as simple as that. The day count starts with day 0 being 1 Jan 4713 B.C., and the last day the program handles is 31 Dec 9999 which is JDN 5373484. The switch from the older Julian to the current Gregorian calender is implemented in that Thu 4 Oct 1582 is directly followed by Fri 15 Oct 1582. You may may change this to a different date, for instance if in your region the switch occured later - see below.

You can now imagine that JDNs make date related calculations very easy - as they are plain integers you can use simple addition and subtraction. Dividing a JDN by 7 yields a remainder that stands for the weekday of that date. Here is a program that does all this. Just to be sure: of course RPN mode is assumed. And be sure not to confuse x<>y (exchange stack registers x and y) and x<> Y (exchange x and variable Y).

J001  LBL J
J002  IP
J003  LASTx
J004  x=y?
J005  GTO J068
J006  FP        // date to JDN
J007  100
J008  x
J009  IP
J010  LASTx
J011  FP
J012  1E4
J013  x
J014  IP
J015  STO Y
J016  R↓
J017  ABS
J018  3
J019  x≤y?
J020  GTO J026
J021  +
J022  9
J023  +
J024  1
J025  STO- Y
J026  SGN
J027  +
J028  30,6
J029  x
J030  IP
J031  x<>y
J032  ABS
J033  +
J034  365,25
J035  RCLx Y
J036  INTG
J037  +
J038  1720995
J039  +
J040  2299160
J041  x<>y
J042  x>y?
J043  FS? 0
J044  GTO J060
J046  x<> Y
J047  100
J048  INT÷
J049  -
J050  LASTx
J051  4
J052  INT÷
J053  +
J054  2
J055  +
J056  x>y?
J057  GTO J060
J058  RCL Y
J059  GTO J999
J062  7
J063  RMDR
J064  1
J065  +
J066  x<>y
J067  RTN
J068  STO X     // JDN to date
J069  7
J070  RMDR
J071  x<> X
J072  2299160
J073  x<>y
J074  x>y?
J075  FS? 0
J076  GTO J090
J077  1
J078  +
J081  1867217,25
J082  -
J083  36524,25
J084  INT÷
J085  +
J086  LASTx
J087  4
J088  INT÷
J089  -
J090  1524
J091  +
J094  122,1
J095  -
J096  365,25
J097  INT÷
J098  STO Y
J099  LASTx
J100  x
J101  IP
J102  -
J105  30,6001
J106  INT÷
J107  LASTx
J108  x<>y
J110  R↓
J111  x
J112  IP
J113  -
J114  x<>y
J115  1
J116  STO+ X
J117  -
J118  12
J119  x≥y?
J120  GTO J124
J121  -
J122  1
J123  STO+ Y
J124  R↓
J125  100
J126  ÷
J127  +
J128  -4716
J129  RCL+ Y
J130  STO Y
J131  ABS
J132  1E6
J133  ÷
J134  +
J135  RCL Y
J136  x=0?
J137  e^x
J138  SGN
J139  x
J140  RCL X
J141  x<>y
J142  RTN

      X  used
      Y  used

      0  set:   force (proleptic) Julian calendar
         clear: automatic Jul./Greg. switch at 4/15 Oct 1582

Entering dates

Any day is entered resp. displayed as follows:
  • All dates are given in dd.mmyyyy format, i.e. 25 December 2014 is 25,122014.
  • The useable date range is 1 Jan 4713 BC = –1,014712 to 31 Dec 9999 = 31,129999, which corresponds to JDN 0 to 5373484.
  • There was no year 0 (1 BC was followed by 1 AD). The program uses astronomical year numbering, so BC dates differ by one in terms of the year number: 753 BC is year –752.
  • The program does not check for validity. But see below for a simple way to do this.
Examples for valid input/output:

25 Dec 2014      <=>  25,122014
 4 Jul 1979      <=>   4,071979
 1 Aug 350 B.C.  <=>  -1,080349

This is what you see in FIX 6 display mode. You may also use ALL, but since trailing zeroes are ommited, dates like 1 Jul 1980 will appear as 1,07198 or 15 Aug 2000 will be displayed as 15.082.

The program uses Flag 0 - please see below at the section on using a proleptic Julian calendar.
The following examples assume that Flag 0 is cleared.

Date calculations

The program converts dates both from and to Julian day numbers (JDNs). Any integer input is considered a JDN, and everything with a fractional part is assumed to be a date in dd.mmyyyy format. The program returns two results: the JDN resp. date in X as well as the corresponding weekday in Y. Here 1 = Monday ... 7 = Sunday.

So the general usage is as follows:

input      keys                output
dd.mmyyyy  [XEQ] J [ENTER]     Y: weekday
                               X: Julian day number

      JDN  [XEQ] J [ENTER]     Y: weekday
                               X: dd.mmyyyy                            


Determine the weekday and Julian day number of 4 July 1979

 4,071979  [XEQ] J [ENTER]     3          // Wednesday
                               2444059    // Julian day number of 4 Jul 1979

Now add 1000 days to this...

 1000      [+]                 2445059    // JDN 1000 days later

...and convert back to day, month and year:

           [XEQ] J [ENTER]     2          // Tuesday
                               30,031982  // 30 Mar 1982

How many days have elapsed between 1 Jan 1900 and 31 Dec 1999?

 1,011900  [XEQ] J [ENTER]     1          // Monday
                               2415021    // JDN
           [STO] A                        // save result
31,121999  [XEQ] J [ENTER]     5          // Friday
                               2451544    // JDN

           [RCL] A [-]                    // subtract first JDN 
                               36523      // result: 36523 days

Some useful application samples
Of course you can also add a few little routines that do these calculations for you. For instance here is a DAYS+ routine that adds a number of days to a given date:

A001  LBL A
A002  IP
A003  STO A
A004  x<>y
A005  XEQ J001
A006  RCL+ A
A007  GTO J001

 4,071979  [ENTER]                        // 4 Jul 1979 plus 1000 days
     1000  [XEQ] A [ENTER]    2           // is Tuesday,
                              30,031982   // 30 Mar 1982

Or use another short routine that calculates the difference between two dates:

D001  LBL D
D002  STO A
D003  x<>y
D004  XEQ J001
D005  x<> A
D006  XEQ J001
D007  RCL- A
D008  RTN

 1,011900  [ENTER]                        // difference between 1 Jan 1900 and 31 Dec 1999
31,121999  [XEQ] D [ENTER]    5           // 31 Dec 1999 was a Friday
                              36523       // and 36523 days after 1 Jan 1900

And finally, the following routine determines the day number within a year (many thanks to Wolfgang for the idea of adding this :-)):

N001  LBL N
N002  STO A
N003  100
N004  x
N005  FP
N006  1
N007  +
N008  100
N009  ÷          // build 00.01yyyy
N010  XEQ J001
N011  x<> A
N012  XEQ J001
N013  RCL- A
N014  RTN

23,081999  [XEQ] N [ENTER]    1           // 23 Aug 1999 was a Monday
                              235         // and the 235th day of the year

Forcing a proleptic Julian calendar

Unless flag 0 is set, the program assumes that the Julian calendar was used until 4 Oct 1582 as stated in Inter gravissimas by Gregory XIII. Using this date for the switch from Julian to Gregorian is common practice. However, many regions in the world changed later, some not before the 20th century.

Setting Flag 0 now enables a proleptic Julian calendar, i.e. it assumes this calendar was valid for any given date. This allows some useful applications.

1. Converting between Julian and Gregorian calendar

The October Revolution started on 7 Nov 1917. What date was this in the Julian calender used those days in Russia?

           [FLAGS] [CF] 0                 // just to be sure (date is Gregorian)
 7,111917  [XEQ] J [ENTER]     3          // Wednesday
                               2421540    // JDN

           [FLAGS] [SF] 0                 // switch to Julian calendar
           [XEQ] J [ENTER]     3          // Wednesday           
                               25,101917  // Julian calendar date was 25 Oct 1917
                                          // that's why it's called the October Revolution

Johann Sebastian Bach was born on 21 March 1685 according to the Julian calendar which was still valid in his region. Later the Gregorian calendar was adopted. On which day may Bach have celebrated his birthday after the switch?

           [FLAGS] [SF] 0                 // assume Julian calendar
21,031685  [XEQ] J [ENTER]     6          // Saturday
                               2336584    // JDN
           [FLAGS] [CF] 0                 // switch back to Gregorian calendar
           [XEQ] J [ENTER]     6          // Saturday
                               31,031685  // According to the Gregorian calendar
                                          // Bach was born on 31 March 1685

2. Adjusting the transition between Julian and Gregorian calendar

The original program assumes the Julian calendar was valid until Thu 4 Oct 1582 which was directly followed by Fri 15 Oct 1582 as the first day of the Gregorian calendar. This is hardcoded by the constant 2299160 in line J040 and J072. It is the JDN of the last day of the Julian calendar, i.e. the JDN of 4 Oct 1582.

If you live in a region where the Gregorian calendar was adopted later, you may want to reflect your local situation by using a different transition point. For instance, Britain and its colonies (including the US) switched after 2 Sep 1752 (followed by 14 Sep 1752). Adjusting the program accordingly is easy:

           [FLAGS] [SF] 0                 // assume Julian calendar
 2,091752  [XEQ] J [ENTER]     3          // Wednesday
                               2361221    // JDN

Now you can replace the constant 2299160 in line J040 and J072 with 2361221 and the transition will occur on 2/14 Sep 1752. After the change you will get the following results:

           [FLAGS] [CF] 0                 // back to automatic calendar switching
 2,091752  [XEQ] J [ENTER]     3          // Wednesday
                               2361221    // JDN
        1  [+]                 2361222    // next day
           [XEQ] J [ENTER]     4          // was Thursday,
                               14,091752  // 14 September 1752

Now try an undefined date between these two:

 9,091752  [XEQ] J [ENTER]     NONEXISTENT // error: date does not exist
           [<-]                            // clear error message
                               2361217     // JDN according to Gregorian Calendar
                               2361228     // JDN according to Julian Calendar

Using the unmodified program, you can try the same with 4 Oct 1582 (adding a day will yield 15 Oct 1582) and an invalid date like 10 Oct 1582 (will return 2299156 and 2299166).

Checking dates

The program does not perform any checks to make sure the user entered a valid date, i.e. you may enter 35 Mar 1975 without an error message although March has only 31 days. In this case the program will return the JDN for 4 Apr 1975. This can be used for a simple validity test: simply convert a date to its JDN and back again. If the result matches the original entry, the date was valid.

31,091975  [XEQ] J [ENTER]     3          // Wednesday
                               2442687    // JDN
           [XEQ] J [ENTER]     3          // Wednesday
                               1,101975   // 31 September does not exist
                                          // date is equivalent to 1 October

As usual, any comments, suggestions and corrections are welcome. ;-)

Thanks (as usual), Dieter for such an extensive resource!
This is a great program!
It's the first program I entered into my new 35s, and it works like a charm. Thank you for sharing!
Reference URL's