home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume3 / calcdate < prev    next >
Text File  |  1989-02-03  |  9KB  |  435 lines

  1. Path: xanth!mcnc!gatech!bloom-beacon!tut.cis.ohio-state.edu!mandrill!hal!ncoast!allbery
  2. From: gordon@1solaria.ori-cal.com (Gordon)
  3. Newsgroups: comp.sources.misc
  4. Subject: v03i022: calcdate.c -- date calculator
  5. Message-ID: <8805172143.AA00235@1solaria.ORI-CAL.COM>
  6. Date: 17 May 88 01:15:21 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: gordon@1solaria.ori-cal.com (Gordon)
  9. Lines: 423
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. comp.sources.misc: Volume 3, Issue 22
  13. Submitted-By: "Gordon" <gordon@1solaria.ori-cal.com>
  14. Archive-Name: calcdate
  15.  
  16. I thought the net folks might find this useful, if something like
  17. it doesn't exist already.  I couldn't find anything, so...
  18.  
  19. I probably should make a little disclaimer here, in reference to
  20. the lack of a "user-friendly" option of being prompted for the
  21. information, so here goes;
  22.  
  23. This is just something I whipped up fairly quickly and then redid
  24. to add the second feature (diff between dates), and for our uses
  25. here it was deemed (yes, I consulted the users) unnecessary to
  26. have prompts.  If anyone out there disagrees, please feel free to
  27. make the mod and post it.
  28.  
  29. Hope some of you find it useful...
  30.  
  31. -=gordon=-
  32.  
  33. Oh, yeah...
  34. Neither ORI/Calculon nor myself, nor anyone else, warranty this product in
  35. any way, and accept no responsibility if it doesn't work right.  Of course,
  36. I know for sure that it works under SCO XENIX V, Altos UNIX V, and
  37. Intel XENIX 3.5 (a brain-dead Sys III port), so it probably works on most
  38. other systems as well.  ;-)
  39.  
  40. --------------------- CUT HERE ------------------------->>
  41. /****************************************************************************
  42.  
  43. Program:    calcdate
  44.  
  45. Synopsis:    calcdate mmddyy { -o [-]offset | -d mmddyy }
  46.  
  47. Purpose:    Calculate the target date when given an initial date and an
  48.         offset in days, or the difference between two dates when
  49.         given two dates.
  50.  
  51. Options:    There are two options as listed below.  One or the other must
  52.         be entered.
  53.  
  54.         -o [-]offset    Allows the user to enter an offset (in days)
  55.                 and returns the initial date plus the offset.
  56.                 Negative offsets are permitted.
  57.  
  58.         -d mmddyy    Allows the user to enter a second date, and
  59.                 returns the difference between the two dates
  60.                 relative to the first date.
  61.  
  62. Author:        Gordon A. Runkle                ORI/Calculon
  63.         ...uunet!men2a!1solaria!gordon
  64.  
  65. *********************************************************************}********/
  66.  
  67. #include <stdio.h>
  68.  
  69. #define REG    0
  70. #define LEAP    1
  71. #define NEG    0
  72. #define POS    1
  73.  
  74. /* Version and usage information.  usage is used to print */
  75. char *version = "calcdate v2.01, 17 May 88, Gordon A. Runkle, ORI/Calculon\n";
  76. char *usage =   "Usage: calcdate mmddyy { -o [-]offset | -d mmddyy }\n\n";
  77. char *prog = "calcdate";
  78.  
  79. /* External variables for holding results of parsing of date values */
  80. int month_1, day_1, year_1, month_2, day_2, year_2;
  81.  
  82. /* no_days[0] is for reg yrs, no_days[1] is for leap yrs */
  83. int no_days[2][12] = 
  84.         {
  85.         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  86.         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  87.         };
  88.  
  89.  
  90.  
  91. main(argc, argv)
  92. int argc;
  93. char *argv[];
  94. {
  95. extern char *version, *usage;
  96.  
  97.  
  98. /* Test for the proper number of args. */
  99. if (argc != 4)
  100.     {
  101.     fprintf(stderr, version);
  102.     fprintf(stderr, usage);
  103.     exit(-1);
  104.     }
  105.  
  106. /* Tests first date for valid format and contents */
  107. if (valid_date(argv[1], 1) != 0)
  108.     exit(-1);           /* The error message is in the function */
  109.  
  110. /* Test for an option flag in the second arg */
  111. if (argv[2][0] != '-')
  112.     {
  113.     fprintf(stderr, usage);
  114.     exit(-1);
  115.     }
  116.  
  117. /* Make a decision based on the option */
  118. if (argv[2][1] == 'o')
  119.     {
  120.     if (off_calc(argv[3]) != 0)
  121.         exit(-1);
  122.     }
  123. else if (argv[2][1] == 'd')
  124.     {
  125.     if (valid_date(argv[3], 2) != 0)
  126.         exit(-1);
  127.     else
  128.         {
  129.         if (dates_calc() != 0)    /* no arg is needed - valid_date */
  130.             exit (-1);    /* takes care of the dates */
  131.         }
  132.     }
  133. else
  134.     {
  135.     fprintf(stderr, usage);
  136.     exit(-1);
  137.     }
  138.  
  139. return(0);
  140. }
  141.  
  142.  
  143. /***************************************/
  144. valid_date(tst_date, date_flag)
  145. char tst_date[];
  146. int date_flag;
  147. {
  148. extern int month_1, day_1, year_1;
  149. extern int month_2, day_2, year_2;
  150. extern char *prog;
  151.  
  152. int i, leap_flag, month, day, year;
  153.  
  154.  
  155. if (strlen(tst_date) != 6)
  156.     {
  157.     fprintf(stderr, "%s: date must be entered as mmddyy\n", prog);
  158.     return(-1);
  159.     }
  160.  
  161. for (i = 0; i < 6; i++)
  162.     if (tst_date[i] < '0' || tst_date[i] > '9')
  163.         {
  164.         fprintf(stderr, "%s: date must be entered as mmddyy\n", prog);
  165.         return(-1);
  166.         }
  167.  
  168.  
  169. sscanf(tst_date, "%2d%2d%2d", &month, &day, &year);
  170.  
  171. if (month > 12)
  172.     {
  173.     fprintf(stderr, "%s: invalid month %d\n", prog, month);
  174.     return(-1);
  175.     }
  176.  
  177. if (year % 4 == 0)
  178.     leap_flag = LEAP;
  179.   else
  180.     leap_flag = REG;
  181.  
  182. if (day > no_days[leap_flag][month - 1])
  183.     {
  184.     fprintf(stderr, "%s: invalid day %d\n", prog, day);
  185.     return(-1);
  186.     }
  187.  
  188. /* This determines where our carefully-checked values are stored */
  189. if (date_flag == 1)
  190.     {
  191.     day_1 = day;
  192.     month_1 = month;
  193.     year_1 = year;
  194.     }
  195. else if (date_flag == 2)
  196.     {
  197.     day_2 = day;
  198.     month_2 = month;
  199.     year_2 = year;
  200.     }
  201. else
  202.     {
  203.     fprintf(stderr, "%s: unexpected error assigning date values\n", prog);
  204.     return(-1);
  205.     }
  206.  
  207. return(0);
  208. }
  209.         
  210.  
  211. /***************************************/
  212. off_calc(offset)
  213. char offset[];
  214. {
  215. extern int no_days[2][12];
  216. extern int month_1, day_1, year_1;
  217. extern char *prog;
  218.  
  219. int atoi();
  220. int i_offset, n_month, n_day, n_year, month_bal;
  221. int i, leap_flag;
  222.  
  223. char newdate[7];
  224.  
  225.  
  226. /* This checks for a valid offset value.  Negative values are allowed
  227.    and checked for.  It stops at the first null. */
  228. for (i = 0; i < 4; i++)
  229.     {
  230.     if (offset[i] == '\0')
  231.         break;
  232.  
  233.     if (i == 0 && offset[i] == '-')
  234.         continue;
  235.  
  236.     if (offset[i] < '0' || offset[i] > '9')
  237.         {
  238.         fprintf(stderr, "%s: offset must be entered as an integer\n", prog);
  239.         exit(-1);
  240.         }
  241.     }
  242.  
  243. i_offset = atoi(offset);
  244.  
  245. /* This is the beginning of the neat stuff.  I hope it works! */
  246. /* leap year is when =>>  year % 4 == 0  */
  247.  
  248. n_year = year_1;    /* the *_1 is used, as this is the value of the */
  249. n_month = month_1;    /* first date entered */
  250. n_day = day_1;
  251.  
  252. if (i_offset >= 0)
  253.     {
  254.     while (i_offset > 0)
  255.         {
  256.         if (n_year % 4 == 0)
  257.             leap_flag = LEAP;
  258.           else
  259.             leap_flag = REG;
  260.  
  261.         month_bal = no_days[leap_flag][n_month - 1] - n_day;
  262.  
  263.         if (i_offset > month_bal)
  264.             {
  265.             i_offset -= month_bal;
  266.             n_month++;
  267.  
  268.             if (n_month > 12)
  269.                 {
  270.                 n_month = 1;
  271.                 n_year++;
  272.  
  273.                 if (n_year > 99)
  274.                     n_year = 0;
  275.                 }
  276.  
  277.             n_day = 0;
  278.             }
  279.           else
  280.             {
  281.             n_day += i_offset;
  282.             i_offset = 0;
  283.             }
  284.         }
  285.     }
  286. else
  287.     {
  288.     while (i_offset < 0)        /* this loop processes neg offsets */
  289.         {
  290.         if (n_year % 4 == 0)
  291.             leap_flag = LEAP;
  292.           else
  293.             leap_flag = REG;
  294.  
  295.         month_bal = n_day - 1;
  296.  
  297.         if (abs(i_offset) > month_bal)
  298.             {
  299.             i_offset += month_bal;
  300.             n_month--;
  301.  
  302.             if (n_month < 1)
  303.                 {
  304.                 n_month = 12;
  305.                 n_year--;
  306.  
  307.                 if (n_year < 0)
  308.                     n_year = 99;
  309.                 }
  310.  
  311.             n_day = no_days[leap_flag][n_month - 1] + 1;
  312.             }
  313.           else
  314.             {
  315.             n_day += i_offset;
  316.             i_offset = 0;
  317.             }
  318.         }
  319.     }
  320.  
  321. sprintf(newdate, "%2d%2d%2d", n_month, n_day, n_year);
  322.  
  323. for (i = 0; i < 7; i++)
  324.     if (newdate[i] == ' ')
  325.         newdate[i] = '0';
  326.  
  327. fprintf(stdout, "%s\n", newdate);
  328.  
  329. return(0);
  330. }
  331.  
  332.  
  333. /***************************************/
  334. dates_calc()
  335. {
  336. extern int no_days[2][12];
  337. extern int month_1, day_1, year_1, month_2, day_2, year_2;
  338.  
  339. int first_rec = 0, curr_offset = 0;
  340. int leap_flag, sign_flag;
  341. int start_day, start_month, start_year, end_day, end_month, end_year;
  342.  
  343.  
  344. /****
  345.     This section determines which date is later, so that the program
  346.     may evaluate the earlier one first.  There is a flag set to indicate
  347.     what sign the end result should have based on whether the first date
  348.     entered is earlier or later than the second.
  349. ****/
  350.  
  351. /* set the default sign */
  352. sign_flag = NEG;
  353.  
  354. if (year_1 < year_2)
  355.     sign_flag = POS;
  356.   else
  357.     if (year_1 == year_2 && month_1 < month_2)
  358.         sign_flag = POS;
  359.       else
  360.         if (year_1 == year_2 && month_1 == month_2 && day_1 < day_2)
  361.             sign_flag = POS;
  362.  
  363. /* This makes the earlier date be set to start_* */
  364. if (sign_flag == POS)
  365.     {
  366.     start_day = day_1;
  367.     start_month = month_1;
  368.     start_year = year_1;
  369.     end_day = day_2;
  370.     end_month = month_2;
  371.     end_year = year_2;
  372.     }
  373.   else
  374.     {
  375.     start_day = day_2;
  376.     start_month = month_2;
  377.     start_year = year_2;
  378.     end_day = day_1;
  379.     end_month = month_1;
  380.     end_year = year_1;
  381.     }
  382.  
  383. /* The calculations below keep incrementing curr_offset and start_* until
  384.    start_* == end_*  */
  385.  
  386. for (;;)
  387.     {
  388.     if (start_year % 4 == 0)
  389.         leap_flag = LEAP;
  390.       else
  391.         leap_flag = REG;
  392.  
  393.     if (first_rec == 0)
  394.         {
  395.         /* This is for when the month and year start out the same, and 
  396.            the user just wants the days (ie.  051688 052688 */
  397.         if (start_month == end_month && start_year == end_year)
  398.             {
  399.             curr_offset = end_day - start_day;
  400.             break;
  401.             }
  402.  
  403.         curr_offset = no_days[leap_flag][start_month - 1] - start_day;
  404.         first_rec = 1;
  405.         }
  406.       else if (start_month == end_month && start_year == end_year)
  407.         {
  408.         curr_offset += end_day;
  409.         break;            /* This is the end of it */
  410.         }
  411.       else
  412.         curr_offset += no_days[leap_flag][start_month - 1];
  413.  
  414.  
  415.     start_month++;
  416.  
  417.     if (start_month > 12)
  418.         {
  419.         start_month = 1;
  420.         start_year++;
  421.  
  422.         if (start_year > 99)
  423.             start_year = 0;
  424.         }
  425.     }
  426.  
  427. if (sign_flag == NEG)
  428.     curr_offset = -curr_offset;
  429.  
  430. fprintf(stdout, "%d\n", curr_offset);
  431.  
  432. return(0);
  433. }
  434. /* end of calcdate.c  -=gordon=- */
  435.