/* datediff.c
 *
 * A return number of days difference between short form dates.
 * Things to note in structure: 1) The declaration of adate, and bdate
 * must be as the specifically alloted arrays.  Pointers will not not
 * work !!!  There is the problem of alloting apace for pointers, and
 * this cannot be done without an initialization. There is none here.
 * hence neccessity of array declaration.  2) format for the conversion
 * of char nature of argv to int type.  DO NOT EVER use atoi() function,
 * it is both machine, and op. sys. dependent, and is not portable.
 * 3) specific %*c for skipping separation chars of int fields in argv[1]
 * and argv[2], is neccessary in the sscanf format.  Sccanf arguments are
 * ints hence "&adate[0]" etc., even though one is reading a conversion
 * into an array.
 * NB argv is a very special pointer,  it DOES NOT require space alloted
 * and is local to main.  Copying to an external variable is required
 * in order to pass it.
 */

#include <stdio.h>
#include  <stdfun.h> 

#define YEARDAYS 365

/* Century prefix for short year designation */
#define CENTURYPRE( y ) ( (y < 90) ? 20 : 19 )

/* yr -> 19yr or 20yr */
#define CENTURY( yr ) (100 * CENTURYPRE( yr ))


/* Indicies of the date arrays */
#define MONTH	0
#define DATE	1
#define YEAR	2

#define OPTSTRING "s"

        static int mon[2][13] = {{0,31,28,31,30,31,30,31,31,30,31,30,31},
                                 {0,31,29,31,30,31,30,31,31,30,31,30,31}};


static char _sccsid[] = { " %M% %I% %H% " };

main( argc, argv )
int argc;
char **argv;
{
	extern int getopt();

	int dayofyear();
	int diffdate();

	extern int optind;
	extern char *optarg;	/* Captures arguments to options */

	int c_opt;
        int leap, aleap, bleap;
        int a_yr, b_yr;
        long int diff;
        int bdate[3], adate[3];
        int terse = 0;
	int bdatearg = 1;
	int adatearg = 2;
        char sl1, sl2;

        if( argc == 1 )   {
                fprintf( stderr, "Usage: datediff [-s] mm/dd/yy mm/dd/yy\n" );
                exit( 1 );
        }



	while( ( c_opt = getopt( argc, argv, OPTSTRING ) ) != EOF )    {
		switch( c_opt )    {
			case 's':
				/* -s */
				terse = 1;
				++bdatearg;
				++adatearg;
				break;
			default:
				printf( "%s: Bad Option\n", argv[0] );
				printf( "Usage: %s -[%s] mm/dd/yy mm/dd/yy\n", argv[0], OPTSTRING );
				exit( 1 );
		}
	}
	/* On exiting loop of option parsing optarg[optind] is the next
	 * argument to the function.
	 */

if( sscanf( argv[bdatearg],"%d%c%d%c%d",&bdate[MONTH],&sl1,&bdate[DATE],&sl2,&bdate[YEAR]) != 5){
        fprintf( stderr, "datediff: can't read first date: %s\n", argv[bdatearg] );
        if( sl1 != '/' || sl2 != '/' )  {
                fprintf( stderr, "slash is missing.\n" );
        }
        exit( 1 );
}

if( sscanf(argv[adatearg],"%d%c%d%c%d",&adate[MONTH],&sl1,&adate[DATE],&sl2,&adate[YEAR]) != 5){
        fprintf( stderr, "datediff: can't read second date: %s\n", argv[adatearg] );
        if( sl1 != '/' || sl2 != '/' )  {
                fprintf( stderr, "slash is missing.\n" );
        }
        exit( 1 );
}

        a_yr = adate[YEAR] + CENTURY( adate[YEAR] );
        b_yr = bdate[YEAR] + CENTURY( bdate[YEAR] );

        aleap = ( a_yr%4 == 0 && a_yr%100 != 0 || a_yr%400 == 0 );
        bleap = ( b_yr%4 == 0 && b_yr%100 != 0 || b_yr%400 == 0 );

        if( bdate[MONTH] > 12 )   {
                fprintf( stderr, "datediff: first argument (%02d/%02d/%02d) month argument out of bounds\n", bdate[MONTH], bdate[DATE], bdate[YEAR] );
                exit( 1 );
        }
        if( adate[MONTH] > 12 )   {
                fprintf( stderr, "datediff: second argument (%02d/%02d/%02d) month argument out of bounds\n", adate[MONTH], adate[DATE], adate[YEAR] );
                exit( 1 );
        }
        if( bdate[DATE] > mon[bleap][bdate[MONTH]] )   {
		fprintf( stderr, "datediff: first date out of bounds for month\n" );
		exit( 1 );
        }
        if( adate[DATE] > mon[aleap][adate[MONTH]] )   {
		fprintf( stderr, "datediff: second date out of bounds for month\n" );
		exit( 1 );
        }

	/* --------------------------------------------------------------- */

	diff = diffdate( bdate, adate );

	if( terse )    {
		/*
		printf( "%ld\n", diff );
		*/
		printf( "%ld", diff );
	}
	else    {
		printf( "\tThe number of days difference is: %ld.\n", diff );
	}

	exit( 0 );
	return( 0 );

} /* End main() */


/* This assumes that date[YEAR] originally containg the 2 digit designation
 * of the year has been heuristically adjusted to the actual year with
 * century included.
 */
dayofyear( date )
int date[3];
{

        int i;
        int leap;
        int day;

        leap = ( date[YEAR]%4 == 0 && date[YEAR]%100 != 0 || date[YEAR]%400 == 0 );
#ifdef DEBUG
fprintf( stderr, "dayofyear: year = %d,  leap = %d\n", date[YEAR], leap );
#endif

        day = date[DATE];
        for( i = 1; i < date[MONTH]; i++ )
                day += mon[leap][i];
        return( day );

}

/* bdate = the before date; adate = the after date
 */
int diffdate( bdate, adate ) /* Get days between two dates */
int *bdate, *adate;
{
	int dayofyear();
	int leap;
	int yr;
	int diff;
	int a_cent, b_cent;

	a_cent = CENTURY( adate[YEAR] );
	b_cent = CENTURY( bdate[YEAR] );

	adate[YEAR] += a_cent;
	bdate[YEAR] += b_cent;


	diff = 0;
	/* if dates are within the same year */
	if( adate[YEAR] == bdate[YEAR] )    {
		diff = dayofyear( adate ) - dayofyear( bdate );
	}
	/* else if dates are NOT in contiguous years */
	else if( adate[YEAR]-1 > bdate[YEAR] )    {
		yr = bdate[YEAR] + 1;
		while( yr < adate[YEAR] )   {
			leap = ( yr%4 == 0 && yr%100 != 0 || yr%400 == 0 );
			if( leap )    {
				diff += YEARDAYS+1;
			}
			else    {
				diff += YEARDAYS;
			}
			++yr;
		}
		diff += dayofyear( adate );
		yr = bdate[YEAR];
		leap = ( yr%4 == 0 && yr%100 != 0 || yr%400 == 0 );
		if( leap )    {
			diff += YEARDAYS + 1 - dayofyear( bdate );
		}
		else    {
			diff += YEARDAYS - dayofyear( bdate );

		}
	}
	/* if dates are in contiguous years */
	else if( bdate[YEAR]+1 == adate[YEAR] )   {
		diff += dayofyear( adate );
		yr = bdate[YEAR];
		leap = ( yr%4 == 0 && yr%100 != 0 || yr%400 == 0 );
		if( leap )    {
			diff += YEARDAYS+1 - dayofyear( bdate );
		}
		else    {
			diff += YEARDAYS - dayofyear( bdate );
		}
	} /* end else-if */

	/* this is to redajust the adate and bdate to their incomming
	 * values, in case these integer arrays are globally defined, and
	 * modifiable by this function.
	 */
	adate[YEAR] -= a_cent;
	bdate[YEAR] -= b_cent;

	return( diff );

} /* End diffdate() */


Return to Home Page
Return to Metayoga Page
Return to C Language Page


The URL for this document is:
http://graham.main.nc.us/~bhammel/graham/CPROGS/datediff.html
Created: 1997
Last Updated: May 28, 2000 Email me, Bill Hammel at
bhammel@graham.main.nc.us
READ WARNING BEFORE SENDING E-MAIL