Path: utzoo!attcan!uunet!wyse!vsi1!ames!elroy!peregrine!zardoz!dhw68k!jimb
From: jimb@dhw68k.cts.com (Jim Bacon)
Newsgroups: comp.sources.wanted
Subject: Date manipulation routines (repost)
Keywords: julian dates gregorian calendar
Message-ID: <11858@dhw68k.cts.com>
Date: 20 Sep 88 03:19:59 GMT
Organization: Wolfskill residence; Anaheim, CA (USA)
Lines: 305

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 '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       
X#include       
X#include       
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