home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / snip9707.zip / PARSDATE.C < prev    next >
C/C++ Source or Header  |  1997-07-05  |  6KB  |  227 lines

  1. /* +++Date last modified: 05-Jul-1997 */
  2.  
  3. /*
  4. **  PARSDATE.C - A simple parser to extract dates from strings.
  5. **
  6. **  Original Copyright 1995 by Robert B. Stout as part of
  7. **  the MicroFirm Function Library (MFL)
  8. **
  9. **  The user is granted a free limited license to use this source file
  10. **  to create royalty-free programs, subject to the terms of the
  11. **  license restrictions specified in the LICENSE.MFL file.
  12. */
  13.  
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include "datetime.h"
  18.  
  19. static unsigned  year_norml(unsigned year);
  20. static Boolean_T get_fields(char *str);
  21. static Boolean_T validate(unsigned year, unsigned month, unsigned day);
  22. static Boolean_T isleap (unsigned yr);
  23. static unsigned  get_month(char *month);
  24.  
  25. static char *fields[3];
  26. static char *month[2][12] = {
  27.       {"January", "February", "March", "April", "May", "June",
  28.        "July", "August", "September", "October", "November", "December"},
  29.       {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  30.        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
  31. };
  32.  
  33. /*
  34. **  parse_date() - Parse a date string into its components
  35. **
  36. **  Arguments: 1 - String to parse
  37. **             2 - Address of year storage
  38. **             3 - Address of month storage
  39. **             4 - Address of day storage
  40. **             5 - Syntax to use
  41. **
  42. **  Returns: 0 For success, non-zero for range errors
  43. **
  44. **  Notes: The following syntaxes are supported:
  45. **
  46. **    Date ordering: USA (month, day, year),
  47. **                   ISO (year, month, day)
  48. **                   EUROPE (day, month, year)
  49. **    Delimiters:    Spaces, commas, dashes, periods, slashes. (" ,-./")
  50. **    Years:         2-digit years assumed to be between 1970 and 2069
  51. **                   4-digit years required otherwise
  52. */
  53.  
  54. Boolean_T parse_date(const char *str,
  55.                      unsigned   *year,
  56.                      unsigned   *month,
  57.                      unsigned   *day,
  58.                      Syntax_T   syntax)
  59. {
  60.       unsigned yy, mm, dd;                /* Local data                 */
  61.       char str_copy[512];                 /* Nice and roomy             */
  62.  
  63.       strcpy(str_copy, str);
  64.       if (Error_ == get_fields(str_copy))
  65.             return Error_;
  66.  
  67.       switch (syntax)
  68.       {
  69.       case USA:
  70.             yy = atoi(fields[2]);
  71.             dd = atoi(fields[1]);
  72.             if (isalpha(*fields[0]))
  73.             {
  74.                   mm = get_month(fields[0]);
  75.                   if (0 == mm)
  76.                   {
  77.                         return Error_;
  78.                   }
  79.             }
  80.             else  mm = atoi(fields[0]);
  81.             break;
  82.  
  83.       case ISO:
  84.             yy = atoi(fields[0]);
  85.             dd = atoi(fields[2]);
  86.             if (isalpha(*fields[1]))
  87.             {
  88.                   mm = get_month(fields[1]);
  89.                   if (0 == mm)
  90.                         return Error_;
  91.             }
  92.             else  mm = atoi(fields[1]);
  93.             break;
  94.  
  95.       case EUROPE:
  96.             yy = atoi(fields[2]);
  97.             dd = atoi(fields[0]);
  98.             if (isalpha(*fields[1]))
  99.             {
  100.                   mm = get_month(fields[1]);
  101.                   if (0 == mm)
  102.                         return Error_;
  103.             }
  104.             else  mm = atoi(fields[1]);
  105.             break;
  106.  
  107.       default:
  108.             return Error_;
  109.       }
  110.       yy = year_norml(yy);
  111.       if (Error_ == validate(yy, mm, dd))
  112.             return Error_;
  113.       *year  = yy;
  114.       *day   = dd;
  115.       *month = mm;
  116.       return Success_;
  117. }
  118.  
  119. /*
  120. **  Utility function to split string fields
  121. */
  122.  
  123. static Boolean_T get_fields(char *str)
  124. {
  125.       if (NULL == (fields[0] = strtok(str, " ,-./")))
  126.             return Error_;
  127.       if (NULL == (fields[1] = strtok(NULL, " ,-./")))
  128.             return Error_;
  129.       if (NULL == (fields[2] = strtok(NULL, " ,-./")))
  130.             return Error_;
  131.       if (NULL != strtok(NULL, " ,-./"))
  132.             return Error_;
  133.       return Success_;
  134. }
  135.  
  136. /*
  137. **  Utility function to validate dates
  138. */
  139.  
  140. static Boolean_T validate(unsigned year, unsigned month, unsigned day)
  141. {
  142.       unsigned int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  143.  
  144.       if (1 > month || 12 < month)
  145.             return Error_;
  146.       if (1 > day || day > (days[month - 1] + (2 == month && isleap(year))))
  147.             return Error_;
  148.       else  return Success_;
  149. }
  150.  
  151. /*
  152. **  Utility function to detect leap years
  153. */
  154.  
  155. static Boolean_T isleap (unsigned yr)
  156. {
  157.    return yr % 400 == 0 || (yr % 4 == 0 && yr % 100 != 0);
  158. }
  159.  
  160. /*
  161. **  Utility function to normalize years
  162. */
  163.  
  164. static unsigned year_norml(unsigned year)
  165. {
  166.       if (99 < year)
  167.             return year;
  168.       if (69 < year)
  169.             return year + 1900;
  170.       else  return year + 2000;
  171. }
  172.  
  173. /*
  174. **  Utility function to determine month from string
  175. **
  176. **  (Note: Uses non-standard stricmp(), common to all DOS compilers
  177. */
  178.  
  179. static unsigned get_month(char *str)
  180. {
  181.       int ix, iy;                         /* Indexes                    */
  182.  
  183.       for (ix = 0; ix < 2; ++ix)
  184.       {
  185.             for (iy = 0; iy < 12; ++iy)
  186.             {
  187.                   if (Success_ == stricmp(str, month[ix][iy]))
  188.                         return iy + 1;
  189.             }
  190.       }
  191.       return 0;
  192. }
  193.  
  194. #ifdef TEST
  195.  
  196. #include <stdio.h>
  197.  
  198. main(int argc, char *argv[])
  199. {
  200.       if (2 > argc)
  201.       {
  202.             puts("Usage: PARSDATE syntax date_string");
  203.             puts("       syntax = 0, 1, or 2");
  204.             return EXIT_FAILURE;
  205.       }
  206.       while (--argc)
  207.       {
  208.             Syntax_T syntax;
  209.             char *str;
  210.             unsigned yy, mm, dd;
  211.             Boolean_T retval;
  212.  
  213.             if (4 > argc)
  214.                   break;
  215.             syntax = atoi(*++argv);
  216.             str = *++argv;
  217.             printf("str = \"%s\"\n", str);
  218.             retval = parse_date(str, &yy, &mm, &dd, syntax);
  219.             printf("parse_date(%d, \"%s\") returned %d\n"
  220.                   "  date = %u-%u-%u\n\n",
  221.                   syntax, str, retval, mm, dd, yy);
  222.       }
  223.       return EXIT_SUCCESS;
  224. }
  225.  
  226. #endif /* TEST */
  227.