atotm.c
上传用户:ladybrid91
上传日期:2007-01-04
资源大小:287k
文件大小:7k
源码类别:

Web服务器

开发平台:

Unix_Linux

  1. /************************************************************************/
  2. /* atotm - converts a date in ASCII format to both a tm structure and */
  3. /* the time in seconds. Can be used to compare two times. */
  4. /* */
  5. /* Author: Marcus E. Hennecke <marcush@leland.stanford.edu> */
  6. /* Copyright (C) 1995 by Marcus E. Hennecke */
  7. /* This program is free software; you can redistribute it and/or modify */
  8. /* it under the terms of the GNU General Public License as published by */
  9. /* the Free Software Foundation; either version 2 of the License, or */
  10. /* (at your option) any later version. */
  11. /* */
  12. /* This program is distributed in the hope that it will be useful, */
  13. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  14. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the */
  15. /* GNU General Public License for more details. */
  16. /* You should have received a copy of the GNU General Public License */
  17. /* along with this program; if not, write to the Free Software */
  18. /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  19. /* */
  20. /* This function is extremely liberal in what it accepts as date or */
  21. /* time. Essentially, it looks at certain patterns and tries to */
  22. /* interpret them in reasonable ways. For example, any string of */
  23. /* digits with one or two colons is a time of the format hh:mm or */
  24. /* hh:mm:ss (with at least one digit required for hh, mm, or ss). If */
  25. /* the seconds are omitted, they are assumed to be zero. */
  26. /* All numbers that are not part of a time are assumed to be part of a */
  27. /* date (i.e. either day, month, or year). Thus, there must be either */
  28. /* three such numbers or two such numbers and a month name. A month */
  29. /* name is a (possibly abbreviated to at least three characters) */
  30. /* English name of a month. */
  31. /************************************************************************/
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <time.h>
  35. #include "phttpd.h"
  36. static const char *days[] =
  37. { "Sunday", "Monday", "Tuesday", "Wednesday",
  38.     "Thursday", "Friday", "Saturday"
  39. };
  40. struct month_t {
  41.   const char *name;
  42.   int length;
  43. };
  44. static const struct month_t months[] =
  45. { {"January", 31}, {"February", 28}, {"March", 31}, {"April", 30},
  46.     {"May", 31}, {"June", 30}, {"July", 31}, {"August", 31},
  47.     {"September", 30}, {"October", 31}, {"November", 30},
  48.     {"December", 31}
  49. };
  50. int atotm(const char *date_str, struct tm *date)
  51. {
  52.   const char *token;
  53.   int i, ch, len, tmp;
  54.   int value, values[3], value_ctr;
  55.   int colons, slashes, dashes;
  56.   int date_values[3], date_ctr, mday, mon, year, yday, seconds, leapday;
  57.   int safe_month = -1;
  58.   int ispm = 0;
  59.   int isam = 0;
  60.   struct tm dummy;
  61.   if ( date == NULL )
  62.     date = &dummy;
  63.   mon = 0;
  64.   date->tm_sec = date->tm_min = date->tm_hour = date->tm_mday =
  65.     date->tm_mon = date->tm_year = date->tm_wday = date->tm_yday =
  66.       date->tm_isdst = -1;
  67.   date_ctr = 0;
  68.   while ( (ch = *date_str++) != '' ) {
  69.     if ( !s_isalnum(ch) ) continue;
  70.     if ( s_isdigit(ch) ) { /* Is a number */
  71.       /* Read in number and maybe following numbers */
  72.       value = ch - '0';
  73.       len = 1;
  74.       value_ctr = colons = slashes = dashes = 0;
  75.       ch = *date_str;
  76.       while ( s_isdigit(ch) || ch == ':' || ch == '/' || ch == '-') {
  77. if ( s_isdigit(ch) ) {
  78.   value = value*10 + ch - '0';
  79.   len++;
  80. } else {
  81.   if ( value_ctr >= 2 ) return(-1); /* Too many numbers */
  82.   if ( len == 0 ) return(-1); /* Empty number (e.g. --) */
  83.   switch (ch) {
  84.     case ':': colons++; break;
  85.     case '/': slashes++; break;
  86.     case '-': dashes++; break;
  87.   };
  88.   values[value_ctr++] = value;
  89.   value = len = 0;
  90. };
  91. ch = *++date_str;
  92.       };
  93.       if ( len )
  94. values[value_ctr] = value;
  95.       else
  96. value_ctr--;
  97.       /* Try to make sense of the numbers read. */
  98.       if ( colons >= 1 ) { /* Must have been time */
  99. if ( colons != value_ctr )
  100.   return(-1); /* Mixed colons, dashes, and/or slashes */
  101. if ( date->tm_hour >= 0 ) return(-1); /* Two times */
  102. if ( values[0] >= 24 ) return(-1);
  103. date->tm_hour = values[0];
  104. if ( values[1] >= 60 ) return(-1);
  105. date->tm_min = values[1];
  106. if ( colons == 2 ) {
  107.   if ( values[2] > 61 ) /* 61 to allow for leap seconds */
  108.     return(-1);
  109.   date->tm_sec = values[2];
  110. } else
  111.   date->tm_sec = 0;
  112.       } else { /* Must have been date */
  113. if ( value_ctr == 2 ) { /* We have a complete date */
  114.   if ( date_ctr > 0 ) return(-1); /* Already had date */
  115.   if ( slashes != 2 && dashes != 2 )
  116.     return(-1); /* Mixed slashes and dashes */
  117.   date_values[0] = values[0];
  118.   date_values[1] = values[1];
  119.   date_values[2] = values[2];
  120.   date_ctr = 3;
  121. } else if ( value_ctr == 0 ) { /* Just one number */
  122.   if ( date_ctr >= 3 ) return(-1);
  123.   date_values[date_ctr++] = values[0];
  124. } else
  125.   return(-1);
  126.       };
  127.     } else { /* Is a letter string */
  128.       token = date_str - 1; /* Remember starting position */
  129.       while (s_isalpha(*date_str))
  130.   date_str++; /* Skip letters */
  131.       len = date_str - token; /* Compute length */
  132.       if ( len == 2 && token[1] == 'm' )
  133.       {
  134. if ( token[0] == 'p' )
  135.   ispm = 1;
  136. else if ( token[0] == 'a' )
  137.   isam = 1;
  138.       }
  139.       if ( len < 3 ) continue;
  140.       for ( i = 0; i < 7; i++ )
  141. if ( !strncasecmp(token, days[i], len) )
  142. {
  143.   if ( date->tm_wday < 0 || date->tm_wday == i ) {
  144.     date->tm_wday = i;
  145.     break;
  146.   } else
  147.     return(-1); /* More than one weekday */
  148. }
  149.       if ( i < 7 ) continue;
  150.       for ( i = 0; i < 12; i++ )
  151. if ( !strncasecmp(token, months[i].name, len) ) {
  152.   if ( safe_month >= 0 && safe_month != i )
  153.     return(-1); /* More than one month */
  154.   date->tm_mon = mon = safe_month = i;
  155.   break;
  156. }
  157.       if ( i < 12 ) continue;
  158.     };
  159.   };
  160.   /* If we didn't find a time, check out if maybe the date was only an */
  161.   /* integer number (i.e. no month and no weekday and no more than one */
  162.   /* number). If there was only one number, use it as number of */
  163.   /* seconds and return immediately. Otherwise, report an error. */
  164.   if ( date->tm_hour < 0 ) /* There was no time */
  165.   {
  166.     if ( date_ctr == 1 && safe_month < 0 && date->tm_wday < 0 )
  167.       return(date_values[0]);
  168.     else
  169.       return(-1);
  170.   }
  171.   if ( isam || ispm ) {
  172.     if ( ispm && isam ) return(-1);
  173.     if ( date->tm_hour >= 12 )
  174.       date->tm_hour -= 12;
  175.     if (ispm)
  176.       date->tm_hour += 12;
  177.   };
  178.   if ( safe_month >= 0 ) {
  179.     if ( date_ctr < 2 ) return(-1);
  180.     mday = date_values[0];
  181.     year = date_values[1];
  182.     if ( date_ctr == 3 )
  183.     {
  184.       if        ( date_values[0] == safe_month ) {
  185. mday = date_values[1];
  186. year = date_values[2];
  187.       } else if ( date_values[1] == safe_month )
  188. year = date_values[2];
  189.     }
  190.     leapday = (mon == 1 && (year & 0x3) ? 0 : 1);
  191.     if ( mday > months[mon].length+leapday &&
  192.  year <= months[mon].length+leapday  ) {
  193.       tmp = mday;
  194.       mday = year;
  195.       year = tmp;
  196.     };
  197.     leapday = (mon == 1 && (year & 0x3) ? 0 : 1);
  198.     if ( mday > months[mon].length+leapday ) return(-1);
  199.   } else {
  200.     if ( date_ctr != 3 ) return(-1);
  201.     mon  = date_values[0] - 1;
  202.     mday = date_values[1];
  203.     year = date_values[2];
  204.   };
  205.   if ( year >= 1900 ) year -= 1900;
  206.   if ( year < 70 )    year += 100;
  207.   date->tm_mday = mday;
  208.   date->tm_mon  = mon;
  209.   date->tm_year = year;
  210.   yday = mday-1;
  211.   for ( i = 0; i < mon; i++ ) yday += months[i].length;
  212.   if ( mon > 1 && (year & 0x3) == 0 ) yday++;
  213.   date->tm_yday = yday;
  214.   seconds = year - 70;
  215.   if ( seconds < 0 ) seconds += 100;
  216.   seconds = seconds * 365 + (seconds+1)/4;
  217.   seconds += yday;
  218.   seconds *= 24*60*60;
  219.   seconds += (date->tm_hour * 60 + date->tm_min) * 60 + date->tm_sec;
  220.   return( seconds );
  221. }