/* Day-Of-Week program, version 2.01, by Craig Bruce, 1995/08/11. ** ** This code is Public Domain Software. */ #include #include int main( int argc, char *argv[] ); void TestConsecutiveAndInverse( void ); long DayCount( int year, int month, int day ); int NumberToDate( long dayNum, int *outYear, int *outMonth, int *outDay ); int YearDayToDate( int year, int dayNum, int *outYear, int *outMonth, int *outDay ); /****************************************************************************/ int main( int argc, char *argv[] ) { int year, month, day, sc, dow, invYear, invMonth, invDay, doy; long dayCount; static char *dowNames[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; if (argc != 2) { fprintf(stderr, "usage: %s YYYY/MM/DD\n", argv[0]); exit( 1 ); } if (argv[1][0]=='-' && argv[1][1]=='t') { TestConsecutiveAndInverse(); return( 0 ); } sc = sscanf(argv[1], "%d/%d/%d", &year, &month, &day); if (sc != 3) { fprintf(stderr, "the date you gave is not in the correct format!\n"); exit( 1 ); } dayCount = DayCount( year, month, day ); if (dayCount==-1) { printf("The give date is invalid or before 1582/10/15\n"); } else { dow = (dayCount+5) % 7; NumberToDate( dayCount, &invYear, &invMonth, &invDay ); doy = dayCount-DayCount(year, 1, 1)+1; if (year == 1582) doy = dayCount + 288; printf( "%s%s%s (dayCount=%ld) (inv:%04d/%02d/%02d) (d.o.year=%d)\n", argv[1], " is a ", dowNames[dow], dayCount, invYear, invMonth, invDay, doy); } return( 0 ); } /****************************************************************************/ void TestConsecutiveAndInverse( void ) { int year, month, day, outYear, outMonth, outDay; int dayCount, validDay; validDay = 0; for (year=1582; year<=9999; year++) { printf("testing year %d...\n", year); for (month=1; month<=12; month++) { for (day=1; day<=31; day++) { dayCount = DayCount( year, month, day ); if (dayCount>=0) { if (dayCount != validDay) { printf("%s: %04d/%d/%d: dayCount=%ld, validDay=%ld\n" ,"Consecutive error: ", year, month, day, dayCount, validDay); exit( 1 ); } validDay += 1; NumberToDate( dayCount, &outYear, &outMonth, &outDay ); if (outYear!=year || outMonth!=month || outDay!=day) { printf("Date-Inverse error: %d/%d/%d ret %d/%d/%d\n", year, month, day, outYear, outMonth, outDay); exit( 1 ); } } } } } printf("Test completed successfully\n"); } /****************************************************************************\ ** DayCount(): written 1995/05/16 by Craig Bruce. ** ** Returns the number of days between 1582/10/15 and the given date, where ** calling with the epoch date would return zero. If the given date is ** invalid, before the epoch date, or after 9999/12/31, then a value of -1 ** is returned instead. The epoch date was a Friday, according to the ** Gregorian calendar, which is what this function uses. Note that the ** calendar used by Britian and its colonies did not synch with the ** Gregorian calendar until 1752/09/14. ** ** This function can be used to compute the day-of-week of a given date ** by using the formula "(returnValue+5)%7", which gives Sunday as zero; ** this function can be used to count the number of days between two ** different dates by subtracting the returned values; and this function ** can be used simply to check the validity of a date (like 2000/02/29). \****************************************************************************/ static int cumDayInYear[12+1] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; long DayCount( int year, int month, int day ) { int leap; long n; if (year<1582 || year>9999) return( -1 ); if (month<1 || month>12 || day<1 || day>31) return( -1 ); n = (year * 365L) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400); n = n + cumDayInYear[month-1] + (day-1); leap = (year%4==0 && year%100!=0) || year%400==0; if (leap && month>=3) n+=1; n -= 578100; if (n<0 || day>cumDayInYear[month]-cumDayInYear[month-1]) { if ( !(n>=0 && month==2 && leap && day==29) ) { return( -1 ); } } return( n ); } /****************************************************************************\ ** NumberToDate(): written 1995/08/04 by Craig Bruce. ** ** Returns the year, month, and day of the given day number. This is the ** inverse of the DayCount() function. The date must be between 1582/10/15 ** and 9999/12/31 inclusive or the function will return a value of -1 ** indicating an error (the regular return value is 0). \****************************************************************************/ int NumberToDate( long dayNum, int *outYear, int *outMonth, int *outDay ) { long n; int year; *outYear = *outMonth = *outDay = 0; if (dayNum<0 || dayNum>3074323) return( -1 ); n = dayNum + 578100; year = n/365 - n/550426; if (year>9999) year = 9999; n = DayCount( year, 1, 1 ); if (dayNum < n) { year -= 1; n = DayCount( year, 1, 1 ); if (dayNum < n) { year -= 1; n = DayCount( year, 1, 1 ); } } if (year == 1582) n = -287; return( YearDayToDate( year, dayNum-n+1, outYear, outMonth, outDay ) ); } /****************************************************************************\ ** YearDayToDate(): written 1995/08/04 by Craig Bruce. ** ** Returns the year, month, and day of the given day number of the given ** year. The date must be between 1582-288 and 9999-365 inclusive or the ** function will return a value of -1 indicating an error (the regular ** return value is 0). Note that the year 1582 is a bit screwy in this ** algorithm, since it assumes that Oct. 15 is the 288th day of that year, ** which is not historically accurate. \****************************************************************************/ int YearDayToDate( int year, int dayNum, int *outYear, int *outMonth, int *outDay ) { int leap, n, extra, month; *outYear = *outMonth = *outDay = 0; if (year<1582 || year>9999 || (year==1582 && dayNum<288)) return( -1 ); leap = (year%4==0 && year%100!=0) || year%400==0; n = (leap && dayNum>=60) ? dayNum-2 : dayNum-1; if (dayNum<1 || n>364) return( -1 ); month = n/30; if (month>11) month=11; if (n=cumDayInYear[month+1]) month += 1; *outYear = year; *outMonth = month+1; if (leap && month+1==2) { *outDay = dayNum - 32 + 1; } else { *outDay = n - cumDayInYear[month] + 1; } return( 0 ); }