Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Source: DATE-arithmetic

48 views
Skip to first unread message

Robert AH Prins

unread,
Aug 13, 1998, 3:00:00 AM8/13/98
to
Hi all,

As promised in an earlier posting, here are the descriptions of the
date-2-JDN and JDN-2-date routines. The previous posting relating to these
calculations can be found on DejaNews:

The descriptions below are almost verbatim copied from the ones by Roger Hill
in the HP-41 PPC Rom Users Manual.

As for the earlier postings:

- initial post using the formulae:
http://www.dejanews.com/getdoc.xp?AN=285481577

- follow-up, having converted them to integer BASM:
http://www.dejanews.com/getdoc.xp?AN=360163947

- further follow-up, this time using BASM FPU instructions:
http://www.dejanews.com/getdoc.xp?AN=374812294

Have fun with them... (And yes, I know, 0 AD only exists for some astronomers,
for us it's 1 BC)

Formulae used in the CJx routines
=================================

There are may algorithms available for converting a year, month and day
into a day number; the one used here seems to involve a minimum of time-
and byte-consuming digit-entry instructions and has a minor advantage of
correctly interpreting "out-of-range" days and months, should the user have
the occasion to input such dates.

Suppose February always had 30 days; then each year would be 367 days long
-- call this an "extended year" and let an extended year be considered as
beginning with March and ending with February. If Y, M and D are the real
year, month and day-of-month (as input by the user), then the quantity:

y = Y + (M - 3) / 12

has an integer part corresponding to the "extended year" and a fractional
part denoting the month of the extended year. Now consider the quantity
z = 367 * y which we can write as: 367 * INT(y) + 367 * FRC(y). The
367 * INT(y) gives us the expected 367 days per extended year, while the
367 * FRC(y) behaves according to this table:

Month FRC(y) 367 * FRC(y) No. of days*

Mar 0 0 0
Apr 1/12 30 7/12 31
May 2/12 61 2/12 61
Jun 3/12 91 9/12 92
Jul 4/12 122 4/12 122
Aug 5/12 152 11/12 153
Sep 6/12 183 6/12 184
Oct 7/12 214 1/12 214
Nov 8/12 244 8/12 245
Dec 9/12 275 3/12 275
Jan 10/12 305 10/12 306
Feb 11/12 336 5/12 337

* in an extended year prior to the given month, assuming all months have
the same length as in a real year (except for February).

An inspection of the table above will reveal that if any number between
7/12 (inclusive) and 8/12 (exclusive) is added to each of the numbers in
the third column, and the integer part is taken, then the result will be
the same as the fourth column which is based on the real length of months.
(The lower limit of 7/12 is imposed by February, the upper limit of 8/12
by July) Hence the quantity INT(367 * y + p) will give the number of days
prior to the given month (starting with march of 0 AD and assuming all
years are extended years), provided that 7/12 <= p < 8/12.

Real years, however, have 1 or 2 days less than our idealised "extended
years". Subtracting 2 * INT(y) from the expression described above will
remove 2 days from the end of each year (i.e., 2 days from February --
which is why we defined the extended years to end with that month) and
adding INT(y / 4) will bring back one day at the end of every
4-extended-year period putting leap-year days in their proper places. For
the Gregorian century corrections, subtracting INT(y / 100) will remove
the leap-year day from century years, and adding INT(y / 400) will return
it to years divisible by 400. Thus we obtain the number of days, starting
with march of 0 AD, prior to the given month in the Gregorian calendar.
The day before 1 March of 0 AD happens to have JDN 1,721,119, which we
add to our expression, and finally, the day-of-month D is added to bring
us to the input date, resulting in the following formula:

(1) JDN = INT(367 * y + p) - 2 * INT(y) + INT(y / 4) -
INT(y / 100) + INT(y / 400) + D + 1,721,119

where y = Y + (M - 3) / 12.

In the actual implementation it turned out to be worthwhile to make a few
modifications in the above formula. The quantity Q - INT(y) + INT(y / 4)
can be replaced by INT(Q - .75 * INT(y)), as long as Q is an integer and
is large enough so that the INT function is not applied to any negative
numbers.

Also, Q - INT(y / 100) + INT(y / 400) can be replaced by
INT(Q - .75 * INT(y / 100)) with the same restrictions on Q.

Furthermore, instead of INT(367 * y + p) we can use INT(367 * y') - n
where y' = Y + (M - q) / 12 and n is any non-negative integer, provided
that the number q is between 3 - (8 + 12n) / 367 (exclusive) and
3 - (7 + 12n) / 367) (inclusive). (This restriction on q follows directly
from the restriction on p mentioned before) Choosing n = 4 leads to:

2.847411 < q <= 2.850136

allowing q = 2.85 to be used, and also insures that INT will not be applied
on negative numbers in the final result below. We can replace INT(y) by
INT(y'), and replace INT(y / 100) by INT(Y' / 100), as long as q is greater
than 2 (which it is according to out above choice). The modified formula is
then:

(2) JDN = INT(INT(INT(367 * y') - INT(y') - .75 * INT(y') + D) -
.75 * INT(y' / 100)) + 1,721,115

where y' = Y + (M - 2.85) / 12

For the Julian calendar the quantity INT(y' / 100) is simply replaced by 2,
this being possible because the two calendars coincide during most of the
200's (201-299 AD).


Formulae used in the JCx routines
=================================

Let N be the number of days that have elapsed since the beginning of
March 0 AD. Thus,

(1) N = JDN - 1,721,119

The average length of a Gregorian century is 36524.25 days, and the number
of whole Gregorian centuries that have elapsed since March 0 AD is:

(2) C = INT((N - e) / 36525.24)

where e is any number between 0 (exclusive) and .25 (inclusive). (In the
JCx routines e = .2 is used) The number

(3) N' = N + C - INT(C/ 4)

then gives the number of days since March, 0 AB, that would have elapsed
if all century years were leap years (as they actually were in the Julian
calendar), with a year being 365.25 days on the average. If the Julian
calendar has been selected, equation (3) is replaced by

(3') N' = N + 2

this being possible due to the fact that both calendars agree during the
time that C = 2. From here on the calculations are the same for both
calendars.

Let Y' and M' be the "shifted" year and month, where a "shifted year" runs
from March (M' = 0) of the same numbered ordinary year to February
(M' = 11) of the next ordinary year. Then Y' (which can also be thought of
as the number of whole shifted years that have elapsed since the beginning
of March, 0 AD) is given by

(4) Y' = INT((N' - e') / 365.25)

where e' is any number satisfying the same restriction as e (again the Cjx
routines use e = .2). The number of days that have elapsed since the beginning
of the shifted year is

(5) N'' = N' - INT(365.25 * Y')

and then the shifted month can be found by

(6) M' = INT((N'' - d) / 30.6)

where d is any number between .4 and .6 (exclusive); the Cjx routines
use .5. (The number 30.6 is the average length of a month during each
5-month cycle, beginning with march and lasting until the end of Febuary)
The day of the month is then

(7) D = INT(N'' - 30.6 * M' + d')

where d' has the same restrictions as d (again the Cjx routines use .5).
Finally, the ordinary year and month Y and M can be obtained from the
shifted year and month by

(8) Y = Y' and M = M' + 3 if M' < = 9
Y = Y' + 1 and M = M' - 9 if M' > 9

--
Robert AH Prins
pri...@wcg.co.uk

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

Dr John Stockton

unread,
Aug 13, 1998, 3:00:00 AM8/13/98
to
JRS: In article <6qvb5p$h8r$1...@nnrp1.dejanews.com> of Thu, 13 Aug 1998
18:27:04 in comp.lang.pascal.borland, Robert AH Prins
<pri...@wcg.co.uk> wrote:

>As promised in an earlier posting, here are the descriptions of the
>date-2-JDN and JDN-2-date routines.

> ...

Good. Saved.

The basis of these routines appears to have nothing in common with those
in my <URL:http://www.merlyn.demon.co.uk/programs/dateprox.pas>, except
for the underlying calendar; this makes it satisfying that they agree.

Dateprox covers years +/-32000; I have taken its date-to-day and day-to-
date routines and put them (so far, only Proleptic Gregorian
Astronomical) into Reverse Polish Notation as verbs in a Long Calculator
program <URL:http://www.merlyn.demon.co.uk/programs/longcalc.pas>. The
working range fundamentally is (10^1000 - 1) seconds. The Base Date is
(-400N)/03/01 - see Backoff in the code - restricted to -10^190 years by
the size of a string - presently -10000 or -1000000. It seems OK, but
there may be bugs - of course, it's *much* slower than yours.

It takes well under a second (PII/300) to calculate that 64-bit UNIX
signed time (seconds from 1970-01-01) will overflow at 15:30:08 UTC on
Sunday, December 4th, 292,277,026,596 Gregorian (ignoring Leap Seconds).

--
John Stockton, Surrey, UK. j...@merlyn.demon.co.uk Turnpike v1.12 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> -- includes FAQqish topics and links:
Dates - misctime.htm Year 2000 - date2000.htm Critical Dates - critdate.htm
Y2k for beginners - year2000.txt UK mini-FAQ - y2k-mfaq.txt Don't Mail News.

0 new messages