home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 2
/
ctrom_ii_b.zip
/
ctrom_ii_b
/
PROGRAM
/
C
/
JULCAL10
/
JULCAL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-21
|
9KB
|
299 lines
/*
Julian (sense 1) date routines, handling both Julian (sense 2) and
Gregorian calendars
SYNOPSIS
long juldn (struct tm *bdt)
long juldnj (struct tm *bdt, long Transition)
long juldnd (struct tm *bdt, struct tm *Transition_date)
struct tm *julcd (long J)
struct tm *julcdj (long J, long Transition)
struct tm *julcdd (long J, struct tm *Transition_date)
extern long jul_transition;
DESCRIPTION
juldn* returns the Julian day number (days since Jan 1, 4713 B.C.)
for the date specified by the struct tm (a broken down time)
pointed to by 'bdt'. Only the tm_year, tm_mon, and tm_mday fields
are examined. If the month or day fields are out of their normal
range, they are adjusted. The tm_wday and tm_yday fields are also
set.
julcd* returns a pointer to a struct tm filled in with the date
corresponding to the Julian day number 'J'. Five fields are set:
tm_year, tm_mon, tm_mday, tm_wday, and tm_yday. The pointer is to
a static structure which is reused on each call.
For both juldn and julcd, the Gregorian calendar is assumed
provided the Julian day number falls on or after the value in the
global variable 'jul_transition', otherwise the Julian calendar is
used. 'jul_transition' is initialized to 2361222 (or September 14,
1752), as in the United Kingdom and the colonies. A different
transition can be specified by Julian day number (for juldnj or
julcdj) or Gregorian date (for juldnd or julcdd). Alternatively,
'jul_transition' can be reset. If the transition is specified by
date, ensure it is interpreted as a Gregorian date by using julcdj
with a small number:
jul_transition = julcdj(&my_transition_date, 1L);
Algorithm is valid from 4713 B.C. to 19,999 A.D. For caveats,
see below.
Aside: In a struct tm, the tm_year field is "year-1900". For the
year 1 A.D., that would be -1899. There was no year 0 (the number
zero had not been invented!), so the previous year was 1 B.C.,
which is represented by -1900.
HISTORY
$Id: julcal.c%v 1.10 1992/12/13 03:15:59 jrv Exp jrv $
$Log: julcal.c%v $
* Revision 1.10 1992/12/13 03:15:59 jrv
* default transition date is that for the United Kingdom
*
* Revision 1.9 1992/12/13 03:07:07 jrv
* juldnj gives correct value even if month is outside normal range.
* juldnj normalizes mday, month, and year.
* _juldnj introduced to let julcdj set yday without causing infinite recursion.
*
* Revision 1.8 1992/12/08 00:23:38 jrv
* Test program moved to a separate file.
*
* Revision 1.7 1992/12/06 01:57:20 jrv
* julcd* return pointers to a static struct tm, like localtime and gmtime.
*
* Revision 1.6 1992/12/05 23:14:58 jrv
* The default transition date is a global variable, initialized to 15 Oct 1582.
* Some variable names changed. All variables are lower case.
*
* Revision 1.5 1992/12/05 22:20:11 jrv
* juldnd accepts a struct tm (a "broken-down time") instead of a
* unique struct. julcdd produces a struct tm (including tm_wday
* and tm_yday fields) instead of a unique struct.
*
* Revision 1.4 1992/12/05 20:04:51 jrv
* Test program prints input values, then computed values.
* Test program is silent by default.
*
* Revision 1.3 1992/12/04 02:57:54 jrv
* Reformatted to more standard C.
* Eliminated some redundant typedefs.
* Type Year is now an int rather than a long.
* Some variables converted to lower case.
*
* Revision 1.2 1992/12/04 02:15:58 jrv
* A Year is no longer unsigned, so years BC work.
* Regression test driver added.
*
* Revision 1.1 1992/12/04 00:21:37 jrv
* Initial revision
*
Translated from Pascal to C by Jim Van Zandt, July 1992.
Error-free translation based on error-free PL/I source
Based on Pascal code copyright 1985 by Michael A. Covington,
published in P.C. Tech Journal, December 1985, based on formulae
appearing in Astronomical Formulae for Calculators by Jean Meeus
Reconversion to normal Julian epoch, integer arithmetic and
4000-year correction by John W. Kennedy
[The 4000-year adjustment is controversial. It is not mentioned in
the paper "Calendrical Calculations" by Nachum Dershowitz and
Edward M. Reingold in Software Practice and Experience, v 20 n 9
pp 899-928 (Sep 1990). I have left it in mainly because it will
make no difference for a very long time. - jvz]
Historical exceptions _not_ allowed for in this package:
Until Julius Caesar established the Julian calendar in 45 B.C.,
calendars were irregular. This package assumes the Julian calendar
back to 4713 B.C.
The Julian calendar was altered in 8 B.C. From 45 B.C. to 8 B.C.,
the months were
Jan=31, Feb=29(30), Mar=31, Apr=30, May=31, Jun=30,
Jul=31, Aug=30, Sep=31, Oct=30, Nov=31, Dec=30
This package assumes the month lengths as we know them.
Leap years from 45 B.C. to 8 A.D. were miscalculated: (45, 42,
39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, then none at all until 8
A.D.) This package assumes leap years every four years, as they
were meant to have been.
January 1 was not always the first day of the year. The United
Kingdom, in particular, started the year on March 25 until 1752.
(However, the year ended on December 31, leaving the days between
in limbo.) This package assumes January 1 is the first day of the
year.
Leap-year day was originally done by having February 24 (25 from 45
to 8 B.C.) twice. This package assumes Leap-year day is February
29.
"Transition" argument is the first Julian date to be considered as
belonging to the Gregorian calendar. Usual values are:
2299161 = October 5/15, 1582, as in Rome, or
2361222 = September 3/14, 1752, as in the United Kingdom
and the Colonies
For more on the history of calendars, including transition dates in
other countries, see Bob Douglas' article in dates.txt.
*/
#include <time.h>
#include "julcal.h"
typedef long Julian;
typedef int Year;
typedef int Month;
typedef int Day;
Julian jul_transition=JUL_ENGLAND;
/*
Julian juldnj (struct tm *bdt, Julian Transition);
Julian juldn (struct tm *bdt);
Julian juldnd (struct tm *bdt, struct tm *Transition_date);
struct tm *julcdj (Julian J, Julian Transition);
struct tm *julcd (Julian J);
struct tm *julcdd (Julian J, struct tm *Transition_date);
*/
typedef long Work;
static Julian
_juldnj(bdt, Transition) struct tm *bdt; Julian Transition;
{
Year ay, y, dy;
Month m;
Julian jd_julian, jd_gregorian, jd;
y = bdt->tm_year + 1900;
m = bdt->tm_mon;
dy = m/12;
y += dy;
m -= dy*12;
/* assert( -11 <= m && m <= 11 ) */
if(m < 0)
{
m += 12;
y--;
}
/* assert( 0 <= m && m <= 11 ) */
if ( m < 2 )
{
m += 1 + 12;
y--;
}
else
m++;
ay = y + 4716;
jd_julian = ((1461*(Work)ay) >> 2) + (153*(m + 1)/5)
+ (Work)bdt->tm_mday - 1524;
jd_gregorian = jd_julian + 2 - y/100 + y/400 - y/4000;
if ( jd_gregorian >= Transition ) jd = jd_gregorian;
else jd = jd_julian;
return jd;
}
/* this wrapper can call julcdj without causing infinite recursion */
Julian
juldnj(bdt, Transition) struct tm *bdt; Julian Transition;
{ Julian jd;
struct tm *normal;
jd = _juldnj(bdt, Transition);
normal = julcdj(jd, Transition);
bdt->tm_year = normal->tm_year;
bdt->tm_mon = normal->tm_mon;
bdt->tm_mday = normal->tm_mday;
bdt->tm_wday = normal->tm_wday;
bdt->tm_yday = normal->tm_yday;
return jd;
}
Julian
juldn (bdt) struct tm *bdt;
{ return juldnj (bdt, jul_transition);
}
Julian
juldnd (bdt, Transition_date) struct tm *bdt; struct tm *Transition_date;
{ return juldnj (bdt, _juldnj (Transition_date, 1L));
}
struct tm *
julcdj (jd, Transition) Julian jd; Julian Transition;
{
Julian aa, ab, a;
Work b, d, ee;
Year ay;
Month em, m;
Year y;
struct tm newyears;
static struct tm date;
memset(&date, 0, sizeof(date));
if ( jd < Transition ) /* Julian Calendar */
a = (Work)(jd);
else /* Gregorian Calendar */
{
aa = jd - 1721120L;
ab = 31*(aa/1460969L); aa = aa % 1460969L;
ab = ab + 3*(aa/146097L); aa = aa % 146097L;
if ( aa == 146096L ) ab = ab + 3;
else ab = ab + aa/36524L;
a = jd + (ab - 2);
}
b = a + 1524;
ay = (Year)((20*b - 2442)/7305);
d = (1461*(Work)(ay)) >> 2;
ee = b - d;
em = (Month)(10000L*ee/306001L);
date.tm_mday = (Day)(ee - 306001L*em/10000L);
m = em - 1;
if(m > 12) m -= 12;
date.tm_mon = m - 1;
if ( m > 2 ) y = ay - 4716;
else y = ay - 4715;
date.tm_year = y - 1900;
date.tm_wday = (jd+1)%7;
newyears = date;
newyears.tm_mon = 0;
newyears.tm_mday = 1;
date.tm_yday = jd - _juldnj(&newyears, Transition);
return &date;
}
struct tm *
julcd(jd) Julian jd;
{ return julcdj (jd, jul_transition);
}
struct tm *
julcdd(jd, Transition_date) Julian jd; struct tm *Transition_date;
{ return julcdj (jd, _juldnj (Transition_date, 1L));
}