04-25-2016, 07:56 PM
Some time ago there were several discussions on calculating the number of years, months and days between two given dates. Indeed these figures are sometimes more handy than the pure number of days as returned by the ΔDAYS command that's found on some calculators (or other calendar software).
However, there are many cases where there are two or even three possible valid solutions for the same input dates, depending on the way the number of days is evaluated. This has been discussed in other threads, so there is no need to repeat it here again. ;-)
The following program uses a quite straightforward method: it counts the number of days until the end of the first month, then determines the number of months and years until the second month, and finally adds the number of days in the latter.
Example:
date1: 25 February 1999
date2: 13 November 2005
That's 4 days until 1 Mar 1999, then 6 years and 8 months until 1 Nov 2005, and finally 12 more days, i.e. 6 years, 8 months and 16 days altogether. And that's what the program returns.
The program employs two formulas that may be of interest for other calendar programs as well. Both are related to the number of days in a given month. The number of days in month m is evaluated using the following formula:
For all months except February:
ndays = 30 + (m + m div 8) mod 2
Here div stands for integer division. If your calculator does not feature a command like INT÷ or IDIV, simply use a regular division followed by INT resp. IP.
For February the program has to determine if the year y is a leap year or not. This is done by checking whether y can be divided by 4 resp. 100 resp. 400 and summing up the number of cases where this is not (!) possible. For instance, 1976 can be divided by 4, but not by 100 or 400, so two out of three conditions do not apply.
Numerically this is done by adding the signs of y mod {4, 100, 400}:
n = sgn(y mod 4) + sgn(y mod 100) + sgn(y mod 400)
Now every possible result for n (0...3) stands for a unique combination of the three conditions that determine whether a year is leap or not:
n = 0: all three conditions apply => leap year
n = 1: one condition is false. This must be the division by 400 => common year
n = 2: two conditions are false. These must be the divisions by 400 and 100 => leap year
n = 3: all three conditions do not apply => common year
So if n is odd, y is a common year, and if n is even, it's a leap year.
For February this means
ndays = 29 – [sgn(y mod 4) + sgn(y mod 100) + sgn(y mod 400)] mod 2
The program implements a variation of this formula: instead of the mod operator it NANDs n with 1, which results in -1 if n is even and -2 if n is odd. Adding 30 yields the number of days in February:
ndays = 30 + [sgn(y mod 4) + sgn(y mod 100) + sgn(y mod 400)] NAND 1
Please note that the latter method may not work on calculators with a different NAND implementation.
Finally, here is the listing:
And here's how to use it:
Enter the earlier date and the later date, separated by [ENTER].
Important: use the dd.mmyyyy format.
Example:
How many years, months and days have elapsed between 25 February 1999 and 13 November 2005?
That's 6 years, 8 months and 16 days. These three values are also returned in Y, Z and T as well as in the variables Y, M and D.
As usual: this program may contain errors, so please do your own tests. I appreciate all comments and corrections.
Dieter
Edit: corrected an error in line Y060 (had wrong jump target).
However, there are many cases where there are two or even three possible valid solutions for the same input dates, depending on the way the number of days is evaluated. This has been discussed in other threads, so there is no need to repeat it here again. ;-)
The following program uses a quite straightforward method: it counts the number of days until the end of the first month, then determines the number of months and years until the second month, and finally adds the number of days in the latter.
Example:
date1: 25 February 1999
date2: 13 November 2005
That's 4 days until 1 Mar 1999, then 6 years and 8 months until 1 Nov 2005, and finally 12 more days, i.e. 6 years, 8 months and 16 days altogether. And that's what the program returns.
The program employs two formulas that may be of interest for other calendar programs as well. Both are related to the number of days in a given month. The number of days in month m is evaluated using the following formula:
For all months except February:
ndays = 30 + (m + m div 8) mod 2
Here div stands for integer division. If your calculator does not feature a command like INT÷ or IDIV, simply use a regular division followed by INT resp. IP.
For February the program has to determine if the year y is a leap year or not. This is done by checking whether y can be divided by 4 resp. 100 resp. 400 and summing up the number of cases where this is not (!) possible. For instance, 1976 can be divided by 4, but not by 100 or 400, so two out of three conditions do not apply.
Numerically this is done by adding the signs of y mod {4, 100, 400}:
n = sgn(y mod 4) + sgn(y mod 100) + sgn(y mod 400)
Now every possible result for n (0...3) stands for a unique combination of the three conditions that determine whether a year is leap or not:
n = 0: all three conditions apply => leap year
n = 1: one condition is false. This must be the division by 400 => common year
n = 2: two conditions are false. These must be the divisions by 400 and 100 => leap year
n = 3: all three conditions do not apply => common year
So if n is odd, y is a common year, and if n is even, it's a leap year.
For February this means
ndays = 29 – [sgn(y mod 4) + sgn(y mod 100) + sgn(y mod 400)] mod 2
The program implements a variation of this formula: instead of the mod operator it NANDs n with 1, which results in -1 if n is even and -2 if n is odd. Adding 30 yields the number of days in February:
ndays = 30 + [sgn(y mod 4) + sgn(y mod 100) + sgn(y mod 400)] NAND 1
Please note that the latter method may not work on calculators with a different NAND implementation.
Finally, here is the listing:
Code:
Y001 LBL Y
Y002 STO B
Y003 IP
Y004 STO- B
Y005 x<>y
Y006 STO A
Y007 IP
Y008 STO- A
Y009 - day2 - day1
Y010 STO D #days, may be negative
Y011 100
Y012 STOx A
Y013 STOx B
Y014 RCL B
Y015 IP
Y016 STO- B
Y017 RCL A
Y018 IP
Y019 STO- A
Y020 STO C save month1
Y021 - month2 - month1
Y022 RCL D
Y023 SGN
Y024 x>0?
Y025 CLx carry = -1 if day2 < day1, or 0 otherwise
Y026 + add -1 or 0
Y027 STO M
Y028 SGN
Y029 12
Y030 x carry = -12 if month2 < month1, or 0 otherwise
Y031 x>0?
Y032 CLx
Y033 STO- M adjust #months by 12 or 0
Y034 SGN new carry = -1 or 0
Y035 1E4
Y036 STOx A
Y037 STOx B
Y038 RCL B
Y039 IP
Y040 STO B
Y041 RCL A
Y042 IP
Y043 STO A
Y044 - year2 - year1
Y045 R↑ recall carry
Y046 + and add
Y047 STO Y #years
Y048 RCL D
Y049 x≥0? day2 ≥ day1?
Y050 GTO Y080 then jump to exit
Y051 2 else adjust #days by no. of days in month1
Y052 RCL C
Y053 x=y? month1 = Feb?
Y054 GTO Y061
Y055 8
Y056 INT÷ compute no. of days in month1
Y057 RCL+ C days in month = 30 + (month + month div 8) mod 2
Y058 x<>y
Y059 RMDR
Y060 GTO Y077 finally add 30 and quit
Y061 RCL A handle February separately
Y062 400
Y063 RMDR
Y064 SGN check if
Y065 RCL A year1
Y066 100 is a
Y067 RMDR leap year
Y068 SGN
Y069 + days in February
Y070 RCL A = 29 - [sgn(y mod 400) + sgn(y mod 100) + sgn(y mod 4)] mod 2
Y071 4 = 30 + [sgn(y mod 400) + sgn(y mod 100) + sgn(y mod 4)] NAND 1
Y072 RMDR
Y073 SGN
Y074 +
Y075 1
Y076 NAND = -1 in leap years, or -2 otherwise
Y077 30
Y078 + = no. of days in month1
Y079 STO+ D adjust #days
Y080 RCL D Exit routine starts here
Y081 1E4
Y082 ÷
Y083 RCL M build y,mmdd
Y084 100
Y085 ÷
Y086 +
Y087 RCL+ Y
Y088 RCL D Fill stack
Y089 RCL M with results
Y090 RCL Y Y, M and D
Y091 R↑ and y,mmdd
Y092 RTN
Variables:
A: date 1
B: date 2
C: month 1
D: => #days
M: => #months
Y: => #years
And here's how to use it:
Enter the earlier date and the later date, separated by [ENTER].
Important: use the dd.mmyyyy format.
Code:
date1 [ENTER] date2
[XEQ] Y [ENTER]
T: #days
Z: #months
=> Y: #years
X: y.mmdd
Example:
How many years, months and days have elapsed between 25 February 1999 and 13 November 2005?
Code:
25.021999 [ENTER] 13.112005
[XEQ] Y [ENTER]
=> 6,0816
That's 6 years, 8 months and 16 days. These three values are also returned in Y, Z and T as well as in the variables Y, M and D.
As usual: this program may contain errors, so please do your own tests. I appreciate all comments and corrections.
Dieter
Edit: corrected an error in line Y060 (had wrong jump target).