home *** CD-ROM | disk | FTP | other *** search
- Path: xanth!mcnc!gatech!bloom-beacon!tut.cis.ohio-state.edu!mandrill!hal!ncoast!allbery
- From: gordon@1solaria.ori-cal.com (Gordon)
- Newsgroups: comp.sources.misc
- Subject: v03i022: calcdate.c -- date calculator
- Message-ID: <8805172143.AA00235@1solaria.ORI-CAL.COM>
- Date: 17 May 88 01:15:21 GMT
- Sender: allbery@ncoast.UUCP
- Reply-To: gordon@1solaria.ori-cal.com (Gordon)
- Lines: 423
- Approved: allbery@ncoast.UUCP
-
- comp.sources.misc: Volume 3, Issue 22
- Submitted-By: "Gordon" <gordon@1solaria.ori-cal.com>
- Archive-Name: calcdate
-
- I thought the net folks might find this useful, if something like
- it doesn't exist already. I couldn't find anything, so...
-
- I probably should make a little disclaimer here, in reference to
- the lack of a "user-friendly" option of being prompted for the
- information, so here goes;
-
- This is just something I whipped up fairly quickly and then redid
- to add the second feature (diff between dates), and for our uses
- here it was deemed (yes, I consulted the users) unnecessary to
- have prompts. If anyone out there disagrees, please feel free to
- make the mod and post it.
-
- Hope some of you find it useful...
-
- -=gordon=-
-
- Oh, yeah...
- Neither ORI/Calculon nor myself, nor anyone else, warranty this product in
- any way, and accept no responsibility if it doesn't work right. Of course,
- I know for sure that it works under SCO XENIX V, Altos UNIX V, and
- Intel XENIX 3.5 (a brain-dead Sys III port), so it probably works on most
- other systems as well. ;-)
-
- --------------------- CUT HERE ------------------------->>
- /****************************************************************************
-
- Program: calcdate
-
- Synopsis: calcdate mmddyy { -o [-]offset | -d mmddyy }
-
- Purpose: Calculate the target date when given an initial date and an
- offset in days, or the difference between two dates when
- given two dates.
-
- Options: There are two options as listed below. One or the other must
- be entered.
-
- -o [-]offset Allows the user to enter an offset (in days)
- and returns the initial date plus the offset.
- Negative offsets are permitted.
-
- -d mmddyy Allows the user to enter a second date, and
- returns the difference between the two dates
- relative to the first date.
-
- Author: Gordon A. Runkle ORI/Calculon
- ...uunet!men2a!1solaria!gordon
-
- *********************************************************************}********/
-
- #include <stdio.h>
-
- #define REG 0
- #define LEAP 1
- #define NEG 0
- #define POS 1
-
- /* Version and usage information. usage is used to print */
- char *version = "calcdate v2.01, 17 May 88, Gordon A. Runkle, ORI/Calculon\n";
- char *usage = "Usage: calcdate mmddyy { -o [-]offset | -d mmddyy }\n\n";
- char *prog = "calcdate";
-
- /* External variables for holding results of parsing of date values */
- int month_1, day_1, year_1, month_2, day_2, year_2;
-
- /* no_days[0] is for reg yrs, no_days[1] is for leap yrs */
- int no_days[2][12] =
- {
- { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
- { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
- };
-
-
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- extern char *version, *usage;
-
-
- /* Test for the proper number of args. */
- if (argc != 4)
- {
- fprintf(stderr, version);
- fprintf(stderr, usage);
- exit(-1);
- }
-
- /* Tests first date for valid format and contents */
- if (valid_date(argv[1], 1) != 0)
- exit(-1); /* The error message is in the function */
-
- /* Test for an option flag in the second arg */
- if (argv[2][0] != '-')
- {
- fprintf(stderr, usage);
- exit(-1);
- }
-
- /* Make a decision based on the option */
- if (argv[2][1] == 'o')
- {
- if (off_calc(argv[3]) != 0)
- exit(-1);
- }
- else if (argv[2][1] == 'd')
- {
- if (valid_date(argv[3], 2) != 0)
- exit(-1);
- else
- {
- if (dates_calc() != 0) /* no arg is needed - valid_date */
- exit (-1); /* takes care of the dates */
- }
- }
- else
- {
- fprintf(stderr, usage);
- exit(-1);
- }
-
- return(0);
- }
-
-
- /***************************************/
- valid_date(tst_date, date_flag)
- char tst_date[];
- int date_flag;
- {
- extern int month_1, day_1, year_1;
- extern int month_2, day_2, year_2;
- extern char *prog;
-
- int i, leap_flag, month, day, year;
-
-
- if (strlen(tst_date) != 6)
- {
- fprintf(stderr, "%s: date must be entered as mmddyy\n", prog);
- return(-1);
- }
-
- for (i = 0; i < 6; i++)
- if (tst_date[i] < '0' || tst_date[i] > '9')
- {
- fprintf(stderr, "%s: date must be entered as mmddyy\n", prog);
- return(-1);
- }
-
-
- sscanf(tst_date, "%2d%2d%2d", &month, &day, &year);
-
- if (month > 12)
- {
- fprintf(stderr, "%s: invalid month %d\n", prog, month);
- return(-1);
- }
-
- if (year % 4 == 0)
- leap_flag = LEAP;
- else
- leap_flag = REG;
-
- if (day > no_days[leap_flag][month - 1])
- {
- fprintf(stderr, "%s: invalid day %d\n", prog, day);
- return(-1);
- }
-
- /* This determines where our carefully-checked values are stored */
- if (date_flag == 1)
- {
- day_1 = day;
- month_1 = month;
- year_1 = year;
- }
- else if (date_flag == 2)
- {
- day_2 = day;
- month_2 = month;
- year_2 = year;
- }
- else
- {
- fprintf(stderr, "%s: unexpected error assigning date values\n", prog);
- return(-1);
- }
-
- return(0);
- }
-
-
- /***************************************/
- off_calc(offset)
- char offset[];
- {
- extern int no_days[2][12];
- extern int month_1, day_1, year_1;
- extern char *prog;
-
- int atoi();
- int i_offset, n_month, n_day, n_year, month_bal;
- int i, leap_flag;
-
- char newdate[7];
-
-
- /* This checks for a valid offset value. Negative values are allowed
- and checked for. It stops at the first null. */
- for (i = 0; i < 4; i++)
- {
- if (offset[i] == '\0')
- break;
-
- if (i == 0 && offset[i] == '-')
- continue;
-
- if (offset[i] < '0' || offset[i] > '9')
- {
- fprintf(stderr, "%s: offset must be entered as an integer\n", prog);
- exit(-1);
- }
- }
-
- i_offset = atoi(offset);
-
- /* This is the beginning of the neat stuff. I hope it works! */
- /* leap year is when =>> year % 4 == 0 */
-
- n_year = year_1; /* the *_1 is used, as this is the value of the */
- n_month = month_1; /* first date entered */
- n_day = day_1;
-
- if (i_offset >= 0)
- {
- while (i_offset > 0)
- {
- if (n_year % 4 == 0)
- leap_flag = LEAP;
- else
- leap_flag = REG;
-
- month_bal = no_days[leap_flag][n_month - 1] - n_day;
-
- if (i_offset > month_bal)
- {
- i_offset -= month_bal;
- n_month++;
-
- if (n_month > 12)
- {
- n_month = 1;
- n_year++;
-
- if (n_year > 99)
- n_year = 0;
- }
-
- n_day = 0;
- }
- else
- {
- n_day += i_offset;
- i_offset = 0;
- }
- }
- }
- else
- {
- while (i_offset < 0) /* this loop processes neg offsets */
- {
- if (n_year % 4 == 0)
- leap_flag = LEAP;
- else
- leap_flag = REG;
-
- month_bal = n_day - 1;
-
- if (abs(i_offset) > month_bal)
- {
- i_offset += month_bal;
- n_month--;
-
- if (n_month < 1)
- {
- n_month = 12;
- n_year--;
-
- if (n_year < 0)
- n_year = 99;
- }
-
- n_day = no_days[leap_flag][n_month - 1] + 1;
- }
- else
- {
- n_day += i_offset;
- i_offset = 0;
- }
- }
- }
-
- sprintf(newdate, "%2d%2d%2d", n_month, n_day, n_year);
-
- for (i = 0; i < 7; i++)
- if (newdate[i] == ' ')
- newdate[i] = '0';
-
- fprintf(stdout, "%s\n", newdate);
-
- return(0);
- }
-
-
- /***************************************/
- dates_calc()
- {
- extern int no_days[2][12];
- extern int month_1, day_1, year_1, month_2, day_2, year_2;
-
- int first_rec = 0, curr_offset = 0;
- int leap_flag, sign_flag;
- int start_day, start_month, start_year, end_day, end_month, end_year;
-
-
- /****
- This section determines which date is later, so that the program
- may evaluate the earlier one first. There is a flag set to indicate
- what sign the end result should have based on whether the first date
- entered is earlier or later than the second.
- ****/
-
- /* set the default sign */
- sign_flag = NEG;
-
- if (year_1 < year_2)
- sign_flag = POS;
- else
- if (year_1 == year_2 && month_1 < month_2)
- sign_flag = POS;
- else
- if (year_1 == year_2 && month_1 == month_2 && day_1 < day_2)
- sign_flag = POS;
-
- /* This makes the earlier date be set to start_* */
- if (sign_flag == POS)
- {
- start_day = day_1;
- start_month = month_1;
- start_year = year_1;
- end_day = day_2;
- end_month = month_2;
- end_year = year_2;
- }
- else
- {
- start_day = day_2;
- start_month = month_2;
- start_year = year_2;
- end_day = day_1;
- end_month = month_1;
- end_year = year_1;
- }
-
- /* The calculations below keep incrementing curr_offset and start_* until
- start_* == end_* */
-
- for (;;)
- {
- if (start_year % 4 == 0)
- leap_flag = LEAP;
- else
- leap_flag = REG;
-
- if (first_rec == 0)
- {
- /* This is for when the month and year start out the same, and
- the user just wants the days (ie. 051688 052688 */
- if (start_month == end_month && start_year == end_year)
- {
- curr_offset = end_day - start_day;
- break;
- }
-
- curr_offset = no_days[leap_flag][start_month - 1] - start_day;
- first_rec = 1;
- }
- else if (start_month == end_month && start_year == end_year)
- {
- curr_offset += end_day;
- break; /* This is the end of it */
- }
- else
- curr_offset += no_days[leap_flag][start_month - 1];
-
-
- start_month++;
-
- if (start_month > 12)
- {
- start_month = 1;
- start_year++;
-
- if (start_year > 99)
- start_year = 0;
- }
- }
-
- if (sign_flag == NEG)
- curr_offset = -curr_offset;
-
- fprintf(stdout, "%d\n", curr_offset);
-
- return(0);
- }
- /* end of calcdate.c -=gordon=- */
-