jimb@dhw68k.cts.com (Jim Bacon) (09/11/88)
I have seen at least two requests for date manipulation routines lately. Here is the library that I use. It is based heavily on the routines found in "Common C Functions" (Que). Because it allows Julian dates based on any given year, it easily allows for math to be performed on dates. Notice also that it will work with dates without leading zeroes in the MM/DD/YY format. I can be reached at turnkey!anacom1!jim or jim@anacom1.tcc.com Enjoy! #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: lldates.c # Wrapped by jim@anacom1.tcc.com on Sun Sep 11 01:15:47 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'lldates.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'lldates.c'\" else echo shar: Extracting \"'lldates.c'\" \(4967 characters\) sed "s/^X//" >'lldates.c' <<'END_OF_FILE' X/***************************************************************************** X * X * MODULE NAME: datelib.c X * X * FUNCTIONS: long juldate(), julcmp() X * int isleap(), zeller() X * char *julrev() X * X * REVISION HISTORY: X * Version/--date--/-by-/reason------------------------------------------ X * 1.0 12/28/85 jb julian date functiX#define INT(x) ((int)(x)) X X#define MO 0 X#define DAY 1 X#define YR 2 X X#define BAD_DATE 0 X#define BAD_DAY 1 X#define BAD_MO 2 X#define BAD_YR 3 X#define BAD_DIGIT 4 X#define BAD_JUL 5 X Xchar *wk_day[] = { X "ERROR", "Sunday", "Monday", "Tuesday", "Wednesday", X "Thursday", "Friday", "Saturday" }; X X Xint days_mo[] = { X 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; X X Xint _julerr; /* global error return */ X X/** X * FUNCTION NAME: int isleap() X * X * DESCRIPTION: determines whether a given year is leap or not. X * X * INPUTS: int year X * X * OUTPUTS: TRUE if leap, otherwise FALSE X */ X Xint isleap(year) Xint year; X{ X return( year % 4 == 0 && year % 100 != 0 || year % 400 == 0 ); X} X X X/** X * FUNCTION NAME: long juldate() X * X * DESCRIPTION: converts a date string to number of days from a X * given base year. X * X * INPUTS: char *date pointer to date string X * 3], n; X long retjul; X X for ( n = 0; n < 3; n++) mdy[n] = 0; X _julerr = 0; X n = 0; return(BAD_DATE); X } X X if ( mdy[YR] < 100 ) { X if ( mdy[YR] < base - 1900) X mdy[YR] += 2000; X else X mdy[YR] += 1900; X } X X if ( mdy[YR] < base ) { X _julerr = BAD_YR; X return(BAD_DATE); X } X X days_mo[2] = isleap(mdy[YR]) ? 29 : 28; X X if ( mdy[DAY] < 1 || mdy[DAY] > days_mo[mdy[MO]] ) { X _julerr = BAD_DAY; X return(BAD_DATE); X } X X retjul = mdy[DAY]; X X for (n = 1; n < mdy[MO]; n++) X retjul += days_mo[n]; X X for X * INPUTS: char *str1,*str2 date strings X * X * OUTPUTS: difference between julian dates based on common X * year of 1900. X * X * PROBLEMS: both input dates must be >= 1/1/1900. X * returns 0 if bad date strings are input. X */ X Xlong julcmp(str1, str2) Xchar *str1, *str2; X{ X long jul1, jul2; X X _julerr = 0; X X if ( !(jul1 = juldate(str1, 1900)) ) X return(BAD_DATE); X X if ( !(jul2 = juldate(str2, 1900)) ) X return(BAD_DATE); X X return(jul2 - jul1); X} X X X/** X * FUNCTION NAME: char *julrev() X * X * DESCRIPTION: returns a date string from an unsigned julian integer X * X * INPUTS: long jul julian number X * int year base year X * X * OUTPUTS: pointer to date string. NULL if negative jul X */ X Xchar *julrev(jul, year) Xlong jul; Xint year; X{ X static char date[11]; X int days_year, n = 1; X X memset(date, '\0', sizeof(date)); X X days_mo[2] = 28; X X if ( jul > 0 ) X _julerr = 0; X else { X _julerr = BAD_JUL; X return(NULL); X } X X do { X days_year = isleap(year) ? 366 : 365; X year++; X jul -= days_year; X } while ( jul > 0 ); X X year--; X jul += days_year; X X if ( days_year == 366 ) X days_mo[2] = 29; X X do X jul -= days_mo[n++]; X while ( jul > 0 ); X X --n; X jul += d input date. X * X * INPUTS: char *date mm/dd/yy or mm/dd/yyyy X * X * OUTPUTS: int n sun = 1, sat = 7, 0 if error X */ X Xint zeller(date) Xchar *date; X{ X X char c; X int mdy[3], month, year, century, offset, n = 0; X X _julerr = 0; X X mdy[DAY] = mdy[MO] = mdy[YR] = 0; X X while ( c = *date++) { X if ( c == '-' || c == '/' ) { X n++; X continue; X } X if ( !isdigit(c) ) { X _julerr = BAD_DIGIT; X return(BAD_DATE); X } X mdy[n] = 10 * mdy[n] + (c - '0'); X } X X mdy[YR] = (mdy[YR] < 100 ? mdy[YR] + 1900 : mdy[YR]); X X if ( mdy[MO] > 2 ) { X month = mdy[MO] - 2; X year = mdy[YR]; X } else X { X month = mdy[MO] + 10; X year = mdy[YR] - 1; X } X X century = year / 100; tes.c'`; then echo shar: \"'lldates.c'\" unpacked with wrong size! fi # end of 'lldates.c' fi echo shar: End of shell archive. exit 0
jimb@dhw68k.cts.com (Jim Bacon) (09/20/88)
Here is a re-post of the routines I posted earlier. Several of you have informed me of a grunged post, this should be better. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: lldates.c # Wrapped by jim@anacom1.tcc.com on Sun Sep 11 01:15:47 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'lldates.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'lldates.c'\" else echo shar: Extracting \"'lldates.c'\" \(4967 characters\) sed "s/^X//" >'lldates.c' <<'END_OF_FILE' X/***************************************************************************** X * X * MODULE NAME: datelib.c X * X * FUNCTIONS: long juldate(), julcmp() X * int isleap(), zeller() X * char *julrev() X * X * REVISION HISTORY: X * Version/--date--/-by-/reason------------------------------------------ X * 1.0 12/28/85 jb julian date function library X * 1.1 9/10/88 jgb cleaned up for UNIX X * X * DESCRIPTION: routines for date manipulations X * X ****************************************************************************/ X X#include <stdio.h> X#include <ctype.h> X#include <memory.h> X X#define INT(x) ((int)(x)) X X#define MO 0 X#define DAY 1 X#define YR 2 X X#define BAD_DATE 0 X#define BAD_DAY 1 X#define BAD_MO 2 X#define BAD_YR 3 X#define BAD_DIGIT 4 X#define BAD_JUL 5 X Xchar *wk_day[] = { X "ERROR", "Sunday", "Monday", "Tuesday", "Wednesday", X "Thursday", "Friday", "Saturday" }; X X Xint days_mo[] = { X 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; X X Xint _julerr; /* global error return */ X X/** X * FUNCTION NAME: int isleap() X * X * DESCRIPTION: determines whether a given year is leap or not. X * X * INPUTS: int year X * X * OUTPUTS: TRUE if leap, otherwise FALSE X */ X Xint isleap(year) Xint year; X{ X return( year % 4 == 0 && year % 100 != 0 || year % 400 == 0 ); X} X X X/** X * FUNCTION NAME: long juldate() X * X * DESCRIPTION: converts a date string to number of days from a X * given base year. X * X * INPUTS: char *date pointer to date string X * in mm/dd/yy or yyyy format X * int base base year, >= 1900 X * X * OUTPUTS: number of days from 1/1/base or 0 if error X */ X Xlong juldate(date, base) Xchar *date; Xint base; X{ X char c; X int mdy[3], n; X long retjul; X X for ( n = 0; n < 3; n++) mdy[n] = 0; X _julerr = 0; X n = 0; X days_mo[2] = 28; /* fix possible prior feb 29 */ X X while ( c = *date++) { X if ( c == '-' || c == '/' ) { X n++; X continue; X } X if ( !isdigit(c) ) { X _julerr = BAD_DIGIT; X return(BAD_DATE); X } X mdy[n] = 10 * mdy[n] + (c - '0'); X } X X if ( mdy[MO] < 1 || mdy[MO] > 12 ) { X _julerr = BAD_MO; X return(BAD_DATE); X } X X if ( mdy[YR] < 100 ) { X if ( mdy[YR] < base - 1900) X mdy[YR] += 2000; X else X mdy[YR] += 1900; X } X X if ( mdy[YR] < base ) { X _julerr = BAD_YR; X return(BAD_DATE); X } X X days_mo[2] = isleap(mdy[YR]) ? 29 : 28; X X if ( mdy[DAY] < 1 || mdy[DAY] > days_mo[mdy[MO]] ) { X _julerr = BAD_DAY; X return(BAD_DATE); X } X X retjul = mdy[DAY]; X X for (n = 1; n < mdy[MO]; n++) X retjul += days_mo[n]; X X for (n = base; n < mdy[YR]; n++) X retjul += ( isleap(n) ? 366 : 365 ); X X return(retjul); X} X X X/** X * FUNCTION NAME: long julcmp() X * X * DESCRIPTION: returns the numbers of days between 2 dates. X * negative if str1 > str2. X * X * INPUTS: char *str1,*str2 date strings X * X * OUTPUTS: difference between julian dates based on common X * year of 1900. X * X * PROBLEMS: both input dates must be >= 1/1/1900. X * returns 0 if bad date strings are input. X */ X Xlong julcmp(str1, str2) Xchar *str1, *str2; X{ X long jul1, jul2; X X _julerr = 0; X X if ( !(jul1 = juldate(str1, 1900)) ) X return(BAD_DATE); X X if ( !(jul2 = juldate(str2, 1900)) ) X return(BAD_DATE); X X return(jul2 - jul1); X} X X X/** X * FUNCTION NAME: char *julrev() X * X * DESCRIPTION: returns a date string from an unsigned julian integer X * X * INPUTS: long jul julian number X * int year base year X * X * OUTPUTS: pointer to date string. NULL if negative jul X */ X Xchar *julrev(jul, year) Xlong jul; Xint year; X{ X static char date[11]; X int days_year, n = 1; X X memset(date, '\0', sizeof(date)); X X days_mo[2] = 28; X X if ( jul > 0 ) X _julerr = 0; X else { X _julerr = BAD_JUL; X return(NULL); X } X X do { X days_year = isleap(year) ? 366 : 365; X year++; X jul -= days_year; X } while ( jul > 0 ); X X year--; X jul += days_year; X X if ( days_year == 366 ) X days_mo[2] = 29; X X do X jul -= days_mo[n++]; X while ( jul > 0 ); X X --n; X jul += days_mo[n]; X X year = (year > 1999 ? year : year - 1900); X X sprintf(date, "%02d/%02d/%02d", n, (int)jul, year); X X X return(date); X} X X X/** X * FUNCTION NAME: int *zeller() X * X * DESCRIPTION: produces zeller congruence give an input date. X * X * INPUTS: char *date mm/dd/yy or mm/dd/yyyy X * X * OUTPUTS: int n sun = 1, sat = 7, 0 if error X */ X Xint zeller(date) Xchar *date; X{ X X char c; X int mdy[3], month, year, century, offset, n = 0; X X _julerr = 0; X X mdy[DAY] = mdy[MO] = mdy[YR] = 0; X X while ( c = *date++) { X if ( c == '-' || c == '/' ) { X n++; X continue; X } X if ( !isdigit(c) ) { X _julerr = BAD_DIGIT; X return(BAD_DATE); X } X mdy[n] = 10 * mdy[n] + (c - '0'); X } X X mdy[YR] = (mdy[YR] < 100 ? mdy[YR] + 1900 : mdy[YR]); X X if ( mdy[MO] > 2 ) { X month = mdy[MO] - 2; X year = mdy[YR]; X } else X { X month = mdy[MO] + 10; X year = mdy[YR] - 1; X } X X century = year / 100; X offset = year % 100; X X n = INT((13 * month - 1) / 5) + mdy[DAY] + offset + INT(offset / 4) X + INT(century / 4) - 2 * century + 77; X n = n - 7 * INT(n / 7); X X return(n + 1); X} END_OF_FILE if test 4967 -ne `wc -c <'lldates.c'`; then echo shar: \"'lldates.c'\" unpacked with wrong size! fi # end of 'lldates.c' fi echo shar: End of shell archive. exit 0