/* 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