[comp.lang.c] Date Coversion Routines

gordan@maccs.McMaster.CA (gordan) (10/09/88)

In article <7618@rpp386.Dallas.TX.US> jfh@rpp386.Dallas.TX.US (The Beach Bum) writes:
-In article <44100014@hcx2> danr@hcx2.SSD.HARRIS.COM writes:
->>   Does anyone have a routine to change back and forth between
->>seconds from 19xx to a Year, Month, Day sort of Date?  

Well, astronomers tend to worry about this sort of thing a lot.

The September (or May?) 1984 issue of Sky and Telescope magazine devoted
some space to this problem, publishing two BASIC (yuck) programs that
convert from year/month/day to Julian date, and vice versa.  The Julian
date is simply the number of days since January 1, 4713 BC.

The two functions are astonishingly short, using some sort of floating
point trickery.  They seemed to work when I tested them.  Conversion to
C is left as an exercise for the reader.

Unless speed is critical, this sort of approach is suitable for all
manner of calendar-related problems.  For instance if you need to know
what the date will be tomorrow, you need only call the first function to
find the Julian date, add 1, and call the second function to convert
back to year, month, and day.  Absolutely no bother worrying about how
many days any month has or whether a year is a leap year.

This should help deal with the problem you're working on (just multiply
days by 86400 to get seconds, unless you have to worry about leap
seconds).

An added bonus is that the day of the week of any date can be determined
as well.  Just find the Julian date, divide by 7, and find the
remainder.  (If you use the routines below, I think a remainder of 0
indicates a Monday, 1 a Tuesday, and so on up to 6 being a Sunday.
It's a bit tricky since Julian days are considered to start at noon
rather than midnight.)

--
                 Gordan Palameta
            uunet!ai.toronto.edu!utgpu!maccs!gordan



***** Date to Julian Day number *********


Simplified from original in Sky and Telescope (no fractional days,
Gregorian calendar only).  May not work for negative years if your
version of Basic truncates (-10/6) to -1 rather than -2 (which is also
what Fortran and most pocket calculators do).  Note SGN is the sign
function (+1 or -1).  See September 1984 Sky and Telescope page 255.

The following are given as test cases:
DATE             JULIAN DAY
Mar 1 200        1794168
Feb 29 1984      2445760
Jan 1 2000       2451545
Mar 21 3000      2816867

Note astronomers should interpret the above as:
Mar 1.5 200 = JD 1794168.0, and so on.


800 REM   CALENDAR --> JD
801 REM
802 REM NOTE: JD THAT
803 REM IS CALCULATED IS THE JULIAN
804 REM DAY THAT BEGINS AT NOON
805 REM GREENWICH MEAN TIME OF THE
806 REM GIVEN DATE (Y,M,D).
809 REM
810 INPUT "Y,M,D ";Y,M,D
825 J=-INT(7*(INT((M+9)/12)+Y)/4)
835 S=SGN(M-9): A=ABS(M-9)
840 J1=INT(Y+S*INT(A/7))
845 J1=-INT((INT(J1/100)+1)*3/4)
850 J=J+INT(275*M/9)+D+J1
855 J=J+1721029+367*Y
870 PRINT "J.D.: ";J
875 END

900 REM   JD --> CALENDAR
901 REM
902 REM NOTE: CALENDAR DATE
903 REM CALCULATED CORRESPONDS TO THE
904 REM DATE ON WHICH THE JULIAN DAY
905 REM BEGINS AT NOON GREENWICH MEAN
906 REM TIME.
909 REM
910 INPUT "J.D. ";J
945 A1=INT((J/36524.25)-51.12264)
950 A=J+1+A1-INT(A1/4)
955 B=A+1524
960 C=INT((B/365.25)-0.3343)
965 D=INT(365.25*C)
970 E=INT((B-D)/30.61)
975 D=B-D-INT(30.61*E)
980 M=E-1: Y=C-4716
985 IF E>13.5 THEN M=M-12
990 IF M<2.5 THEN Y=Y+1
995 PRINT "DATE: ";Y;M;D
997 END

dal@midgard.mn.org (Dale Schumacher) (10/12/88)

In article <1483@maccs.McMaster.CA> gordan@maccs.UUCP () writes:
|In article <7618@rpp386.Dallas.TX.US> jfh@rpp386.Dallas.TX.US (The Beach Bum) writes:
|-In article <44100014@hcx2> danr@hcx2.SSD.HARRIS.COM writes:
|->>   Does anyone have a routine to change back and forth between
|->>seconds from 19xx to a Year, Month, Day sort of Date?  
|
|Well, astronomers tend to worry about this sort of thing a lot.
|
|The September (or May?) 1984 issue of Sky and Telescope magazine devoted
|some space to this problem, publishing two BASIC (yuck) programs that
|convert from year/month/day to Julian date, and vice versa.  The Julian
|date is simply the number of days since January 1, 4713 BC.
|
|The two functions are astonishingly short, using some sort of floating
|point trickery.  They seemed to work when I tested them.  Conversion to
|C is left as an exercise for the reader.

I don't think floating point is required.  I know that it isn't for the
formula that I have.  I haven't compared the to closely enough (nor do I
want to) to determine if they are identical.  In any case, the following
source code from dLibs (which is public domain) calculated julian date
very nicely, and it's supposed to be accurate to +/- 4 million years!

long julian_date(time)
	register struct tm *time;
/*
 *	Number of days since the base date of the Julian calendar.
 */
	{
	register long c, y, m, d;

	y = time->tm_year + 1900;	/* year - 1900 */
	m = time->tm_mon + 1;		/* month, 0..11 */
	d = time->tm_mday;		/* day, 1..31 */
	if(m > 2)
		m -= 3L;
	else
		{
		m += 9L;
		y -= 1L;
		}
	c = y / 100L;
	y %= 100L;
	return( ((146097L * c) >> 2) +
		((1461L * y) >> 2) +
		(((153L * m) + 2) / 5) +
		d +
		172119L );
	}

PS.  If you define your days of the week as:
	char *day[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
     the day-of-week is:
	day[(julian_date(t) + 1L) % 7L];
     (ie.  the julian day 0 is a Monday.)

gordan@maccs.McMaster.CA (gordan) (10/20/88)

In article <483@midgard.mn.org> dal@syntel.UUCP (Dale Schumacher) writes:
-In article <1483@maccs.McMaster.CA> gordan@maccs.UUCP () writes:
-|
-|The two functions are astonishingly short, using some sort of floating
-|point trickery.  They seemed to work when I tested them.  Conversion to
-|C is left as an exercise for the reader.
-
-I don't think floating point is required.  I know that it isn't for the
-formula that I have.  I haven't compared the to closely enough (nor do I

[code omitted]

Yes, but the code you supply only does   D/M/Y --> JD, not vice versa.

Believe it or not, there's a one-line Fortran statement that does
D/M/Y --> JD, which was also published in Sky & Telescope in 1984.

Actually it was the "vice versa" routine (JD --> D/M/Y) that did the
floating point.