home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 2
/
ctrom_ii_b.zip
/
ctrom_ii_b
/
PROGRAM
/
C
/
JULCAL10
/
TJUL.C
< prev
Wrap
C/C++ Source or Header
|
1992-12-21
|
11KB
|
335 lines
#define MKTIME
/*
NAME
tjul - test julcal family of Julian day number programs
SYNOPSIS
julcal [-v] [datafile]
NOTES
Default datafile name is "data". Nothing is printed unless an
error is found.
OPTIONS
-v verbose: print all comment lines, input data, calculated dates,
first 10 lines of each set of random tests
INPUT
A ';' introduces a comment.
If the first character is 'T', it is followed by the Julian
date for transition to the Gregorian calendar. (Initially, the
transition date is JD2361222 = September 14, 1752, as in England.)
Otherwise, each line has six items:
julian_day year month mday wday yday
2299159 1582 10 3 Wed 275
where
julian_day is the number of days since Jan 1, 4713 B.C.
year is negative for B.C.
month is in the range [1...12]
mday is in the range [1...31]
yday is in the range [0...365]
OUTPUT
In case of error...
The input data.
The Julian day calculated from the date by juldn.
The year, month, day, weekday, and day of year (0...365)
calculated from the Julian day by julcd.
Outputs that don't match the corresponding inputs are marked with '*'.
JD date juldn(date) julcd(JD)
------- ------------------ ----------- --------------------
2430336 1941 12 7 Sun 340 2430336 1941 12 7 Sun 340
There are also three sets of random tests. Again, '*'
indicates a disagreement.
The first set is for self consistency: two dates, ten days
apart, should result in Julian dates that differ by ten.
The second set compares the normalization of dates as found by
mktime and juldn. Due to buggy implementations of mktime
(Borland, Sun), in case of a disagreement the test program
tries to identify which function is incorrect. First, it
adjusts the month and compensates with the year. If the two
functions then agree, it prints their results. Otherwise, it
looks for a boundary between agreement and disagreement. It
then prints results for dates on each side of the boundary. In
either case, comparing the last two lines should show which
function is incorrect.
The third set compares tm_wday and tm_yday as found by julcd(),
juldn(), and gmtime().
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "julcal.h"
#define BUFSIZE 200
char buf[BUFSIZE+1];
FILE *ifile;
char *filename = "data";
#define streq(a,b) (strcmp(a,b)==0)
main(argc, argv) int argc; char **argv;
{ char *s, tdayname[4];
static char *weekdayname[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
static char item1_heading[]=
" JD date juldn(date) julcd(JD)\n\
------- ------------------ ----------- --------------------\n";
static char item2_heading[]=
"\n\
before after\n\
-------------- --------------------------\n\
year month day year month day Julian day\n";
#ifdef MKTIME
static char item3_heading[]=
"\n\
before mktime juldn\n\
-------------- -------------- --------------\n";
int item3=0;
#endif
static char item4_heading[]=
"\n\
gmtime julcd juldn\n\
---------------------- ---------- ----------\n\
time_t date wday yday wday yday wday yday\n";
/* xxxxxxxxxx -> 4444/22/22 -> 1 333 1 333 */
int item4=0;
int fields, same_jd, same_date, i;
int verbose=0, item1=0, item2=0;
long tjd; struct tm tbdt; /* test data, from file */
long rjd; struct tm rbdt; /* results, from functions */
long j0, j10;
int tyear, ryear, dy, dd, error;
time_t when;
struct tm *bdt1, *bdt2;
struct tm before, before0, before10, after0, after10, theirs, ours;
for (i = 1; i < argc; i++)
{if(streq(argv[i],"-v")) verbose=1;
else filename = argv[i];
}
ifile = fopen(filename, "r");
if(ifile == 0) {fprintf(stderr, "can't open file %s\n", filename); exit(1);}
while(fgets(buf, BUFSIZE, ifile))
{
if(s = strchr(buf, '\n')) *s = 0; /* zap LF */
if(buf[0] == ';')
{
if(verbose) printf("%s\n", buf); /* echo cmt line */
continue;
}
if(buf[0] == 'T')
{ /* set new default transition date */
sscanf(buf, "T%ld", &jul_transition);
if(verbose) printf("%s\n", buf);
continue;
}
if(s = strchr(buf, ';')) *s = 0; /* zap trailing comment */
tbdt.tm_year = 0;
tbdt.tm_mon = 0;
tbdt.tm_mday = 1;
tbdt.tm_wday = 1;
fields = sscanf(buf, "%ld %d %d %d %3s %d", &tjd, &tbdt.tm_year,
&tbdt.tm_mon, &tbdt.tm_mday, &tdayname, &tbdt.tm_yday);
if(fields < 1) continue;
for (i = 0; i < 7; i++)
if(streq(tdayname, weekdayname[i]))
break;
tbdt.tm_wday = i;
/* adjust for struct_tm offsets */
if(tbdt.tm_year < 0) tbdt.tm_year -= 1899;
else tbdt.tm_year -= 1900;
tbdt.tm_mon--;
rjd = juldn(&tbdt);
rbdt = *julcd(tjd);
same_date = (rbdt.tm_year == tbdt.tm_year)
&& (rbdt.tm_mon == tbdt.tm_mon)
&& (rbdt.tm_mday == tbdt.tm_mday)
&& (rbdt.tm_wday == tbdt.tm_wday)
&& (rbdt.tm_yday == tbdt.tm_yday);
same_jd = (rjd == tjd);
if(verbose || !same_jd || !same_date)
{
if(!item1) printf(item1_heading);
item1 = 1;
tyear = tbdt.tm_year + 1900; if(tyear < 1) tyear--;
ryear = rbdt.tm_year + 1900; if(ryear < 1) ryear--;
printf("%8ld %5d %2d %2d %3s %3d %7ld %s %5d %2d %2d %s %3d %s\n",
tjd, tyear, tbdt.tm_mon+1, tbdt.tm_mday, tdayname, tbdt.tm_yday,
rjd, same_jd?" ":"*",
ryear, rbdt.tm_mon+1, rbdt.tm_mday,
weekdayname[rbdt.tm_wday], rbdt.tm_yday,
same_date?" ":"*");
}
}
/*
Check normalization (correction for day or month out of the normal
range) of juldnj.
*/
for (i = 0; i < 5000; i++)
{ /* test period is 1780 - 5 - 1 ... 1780 + 700 + 5 + 1
or 1774 ... 2486
(after transition to Gregorian calendar) */
before0.tm_year = 1780 - 1900 + rand()%700;
before0.tm_mon = -60 + rand()%120;
before0.tm_mday = -360 + rand()%720;
before0.tm_sec = before0.tm_min = before0.tm_hour = 0;
before10 = before0;
dy = rand()%14;
before10.tm_year -= dy;
before10.tm_mon += dy*12;
before10.tm_mday += 10;
/* 'before10' now has a date 10 days later than 'before0' */
after0 = before0;
after10 = before10;
j0 = juldn(&after0);
j10 = juldn(&after10);
/* check that final dates are normalized & 10 days apart */
error = j10 != j0 + 10
|| after0.tm_mon < 0
|| after0.tm_mon > 11
|| after0.tm_mday < 1
|| after0.tm_mday > 31
|| after10.tm_mon < 0
|| after10.tm_mon > 11
|| after10.tm_mday < 1
|| after10.tm_mday > 31
|| ((after0.tm_mon == after10.tm_mon)?
(after10.tm_mday != after0.tm_mday + 10)
: ((after0.tm_mon + 1)%12 != after10.tm_mon
|| after0.tm_mday - after10.tm_mday + 10 > 31
|| after0.tm_mday - after10.tm_mday + 10 < 28));
if((verbose && i < 10) || error)
{
if(!item2) printf(item2_heading);
printf("%4d %4d %4d -> %4d %4d %4d = JD%ld\n",
before0.tm_year+1900, before0.tm_mon+1, before0.tm_mday,
after0.tm_year+1900, after0.tm_mon+1, after0.tm_mday, j0);
printf("%4d %4d %4d -> %4d %4d %4d = JD%ld\n\n",
before10.tm_year+1900, before10.tm_mon+1, before10.tm_mday,
after10.tm_year+1900, after10.tm_mon+1, after10.tm_mday, j10);
if(++item2 > 15) break;
}
}
#ifdef MKTIME
/*
Compare normalization (correction for day or month out of the
normal range) of juldnj with mktime().
*/
for (i = 0; i < 5000; i++)
{
before.tm_year = 1980 - 1900 + rand()%30;
before.tm_mon = -60 + rand()%120;
before.tm_mday = -200 + rand()%400;
before.tm_sec = before.tm_min = 0;
before.tm_hour = 0;
error = make_comparison(&before, &theirs, &ours);
if((verbose && i < 10) || error)
{
if(!item3) printf(item3_heading);
print_comparison(&before, &theirs, &ours, error);
if(error)
{
dy = before.tm_mon/12;
if(before.tm_mon < 0) dy--;
before.tm_mon -= dy*12;
before.tm_year += dy;
error = make_comparison(&before, &theirs, &ours);
if(!error) print_comparison(&before, &theirs, &ours, error);
else
{
dd = before.tm_mday>0 ? 1 : -1;
for (i = 0; i < 250; i++)
{
before.tm_mday -= dd;
error = make_comparison(&before, &theirs, &ours);
if(!error)
{
before.tm_mday += dd;
error = make_comparison(&before, &theirs, &ours);
print_comparison(&before, &theirs, &ours, error);
before.tm_mday -= dd;
break;
}
}
error = make_comparison(&before, &theirs, &ours);
print_comparison(&before, &theirs, &ours, error);
}
printf("\n");
}
if(++item3 > 15) break;
}
}
#endif /* MKTIME */
/*
Compare calculation of tm_wday and tm_yday with gmtime(). (All these
are after 1 Jan 1970, so necessarily A.D. and for Gregorian calendar.)
*/
for (i = 0; i < 5000; i++) /* this takes ~5 sec on a 25 MHz 386 */
{
when = (((long)rand())<<16) + rand();
bdt1 = gmtime(&when);
ours = *bdt1;
bdt2 = julcd(juldn(&ours)); /* both ours and *bdt2 get wday and yday */
error = bdt1->tm_wday != bdt2->tm_wday
|| bdt1->tm_yday != bdt2->tm_yday
|| bdt1->tm_wday != ours.tm_wday
|| bdt1->tm_yday != ours.tm_yday;
if((verbose && i < 10) || error)
{
if(!item4) printf(item4_heading);
printf("%11ld -> %4d/%02d/%02d %d %3d %d %3d",
when,
bdt1->tm_year+1900, bdt1->tm_mon+1, bdt1->tm_mday,
bdt1->tm_wday, bdt1->tm_yday,
bdt2->tm_wday, bdt2->tm_yday);
printf(" %d %3d %s\n",
ours.tm_wday, ours.tm_yday,
error?"*":" ");
if(++item4 > 15) break;
}
}
}
make_comparison(before, theirs, ours)
struct tm *before, *theirs, *ours;
{ *ours = *theirs = *before;
juldn(ours);
mktime(theirs);
return ours->tm_year != theirs->tm_year
|| ours->tm_mon != theirs->tm_mon
|| ours->tm_mday != theirs->tm_mday;
}
print_comparison(before, theirs, ours, error)
struct tm *before, *theirs, *ours; int error;
{
printf("%4d %4d %4d -> %4d %4d %4d %4d %4d %4d %s\n",
before->tm_year+1900, before->tm_mon+1, before->tm_mday,
theirs->tm_year+1900, theirs->tm_mon+1, theirs->tm_mday,
ours->tm_year+1900, ours->tm_mon+1, ours->tm_mday,
error?"*":" ");
}