A time interface class. This class replicates the normal time functions, but goes a couple of steps further. mbed library 82 and prior has a defective gmtime function. Also, this class enables access to setting the time, and adjusting the accuracy of the RTC.

Dependencies:   CalendarPage

Dependents:   CI-data-logger-server WattEye X10Svr SSDP_Server

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TimeInterface.cpp Source File

TimeInterface.cpp

00001 
00002 #include "TimeInterface.h"
00003 
00004 #include "rtc_api.h"
00005 
00006 //#define DEBUG "Time"
00007 #include <cstdio>
00008 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
00009 #define DBG(x, ...)  std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00010 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00011 #define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00012 #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00013 #else
00014 #define DBG(x, ...)
00015 #define WARN(x, ...)
00016 #define ERR(x, ...)
00017 #define INFO(x, ...)
00018 #endif
00019 
00020 #ifdef WIN32
00021 // Fake it out for Win32 development and testing
00022 struct LPC {
00023     unsigned long CCR;          // Clock Control register
00024     unsigned long GPREG0;       // General Purpose Register #0 - 32-bit Battery backed
00025     unsigned long GPREG1;       // General Purpose Register #1 - 32-bit Battery backed
00026     unsigned long CALIBRATION;  // Calibration Register
00027 };
00028 struct LPC X;
00029 struct LPC * LPC_RTC = &X;
00030 #define set_time(x) (void)x
00031 #endif
00032 
00033 
00034 TimeInterface::TimeInterface(EthernetInterface *net)
00035 {
00036     m_net = net;
00037     dst = false;
00038     memset(&dst_pair, 0, sizeof(dst_pair));  // that's enough to keep it from running
00039 }
00040 
00041 TimeInterface::~TimeInterface()
00042 {
00043 }
00044 
00045 NTPResult TimeInterface::setTime(const char* host, uint16_t port, uint32_t timeout)
00046 {
00047     NTPResult res;
00048     
00049     if (m_net) {
00050         NTPClient ntp(m_net);
00051         // int16_t tzomin = get_tzo_min();
00052         INFO("setTime(%s, %d, %d)\r\n", host, port, timeout);
00053         res = ntp.setTime(host, port, timeout);
00054         INFO("  ret: %d\r\n", res);
00055         if (res == NTP_OK) {
00056             // if the time was fetched successfully, then
00057             // let's save the time last set with the local tzo applied
00058             // and this saves the last time set for later precision
00059             // tuning.
00060             set_time(std::time(NULL));
00061         }
00062     } else {
00063         ERR("No connection");
00064         res = NTP_CONN;
00065     }
00066     return res;
00067 }
00068 
00069 bool TimeInterface::parseDSTstring(TimeInterface::dst_event_t * result, const char * dstr)
00070 {
00071     int x;
00072     dst_event_t test_dst;
00073 
00074     x = atoi(dstr);
00075     if (x >= 1 && x <= 12) {
00076         test_dst.MM = x;
00077         dstr = strchr(dstr, '/');
00078         if (dstr++) {
00079             x = atoi(dstr);
00080             if (x >= 1 && x <= 31) {
00081                 test_dst.DD = x;
00082                 dstr = strchr(dstr, ',');
00083                 if (dstr++) {
00084                     x = atoi(dstr);
00085                     if (x >= 0 && x <= 23) {
00086                         test_dst.hh = x;
00087                         dstr = strchr(dstr, ':');
00088                         if (dstr++) {
00089                             x = atoi(dstr);
00090                             if (x >= 0 && x <= 59) {
00091                                 test_dst.mm = x;
00092                                 memcpy(result, &test_dst, sizeof(dst_event_t));
00093                                 INFO("parsed: %d/%d %d:%02d", test_dst.MM, test_dst.DD, test_dst.hh, test_dst.mm);
00094                                 return true;
00095                             }
00096                         }
00097                     }
00098                 }
00099             }
00100         }
00101     }
00102     return false;
00103 }
00104 
00105 // parse MM/DD,hh:mm
00106 bool TimeInterface::set_dst(const char * dstStart, const char * dstStop)
00107 {
00108     dst_event_pair_t test_pair;
00109 
00110     if (parseDSTstring(&test_pair.dst_start, dstStart)
00111     && parseDSTstring(&test_pair.dst_stop, dstStop)) {
00112         memcpy(&dst_pair, &test_pair, sizeof(dst_event_pair_t));
00113         INFO("set_dst from (%s,%s)", dstStart, dstStop);
00114         return true;
00115     }
00116     WARN("failed to set_dst from (%s,%s)", dstStart, dstStop);
00117     return false;
00118 }
00119 
00120 bool TimeInterface::set_dst(bool isdst)
00121 {
00122     dst = isdst;
00123     return true;
00124 }
00125 
00126 bool TimeInterface::get_dst(void)
00127 {
00128     return dst;
00129 }
00130 
00131 clock_t TimeInterface::clock(void)
00132 {
00133     return std::clock();
00134 }
00135 
00136 time_t TimeInterface::time(time_t * timer)
00137 {
00138     return std::time(timer);
00139 }
00140 
00141 uint32_t TimeInterface::minutesSinceJan(int mon, int day, int hr, int min)
00142 {
00143     return (mon * 60 * 24 * 31) + (day * 60 * 24) + (hr * 60) + min;
00144 }
00145 
00146 time_t TimeInterface::timelocal(time_t * timer)
00147 {
00148     time_t privTime;
00149     struct tm * tminfo;
00150 
00151     if (dst_pair.dst_start.MM) {    // may have to change the dst
00152         std::time(&privTime);
00153         tminfo = std::localtime(&privTime);
00154 
00155         uint32_t min_since_jan = minutesSinceJan(tminfo->tm_mon + 1, tminfo->tm_mday, tminfo->tm_hour, tminfo->tm_min);
00156         uint32_t min_dst_start = minutesSinceJan(dst_pair.dst_start.MM, dst_pair.dst_start.DD, dst_pair.dst_start.hh, dst_pair.dst_start.mm) + get_tzo_min();
00157         uint32_t min_dst_stop  = minutesSinceJan(dst_pair.dst_stop.MM, dst_pair.dst_stop.DD, dst_pair.dst_stop.hh, dst_pair.dst_stop.mm) + get_tzo_min();
00158 
00159         if (min_since_jan >= min_dst_start && min_since_jan < min_dst_stop) {
00160             dst = 1;
00161             //INFO(" is dst: %u - %u - %u", min_since_jan, min_dst_start, min_dst_stop);
00162         } else {
00163             dst = 0;
00164             //INFO("not dst: %u - %u - %u", min_since_jan, min_dst_start, min_dst_stop);
00165         }
00166     }
00167     INFO(" timelocal: %u, %d, %d", std::time(timer), get_tzo_min(), dst);
00168     return std::time(timer) + get_tzo_min() * 60 + dst * 3600;
00169 }
00170 
00171 char * TimeInterface::ctime(const time_t * timer)
00172 {
00173     char * p = std::ctime(timer);
00174 
00175     if (strlen(p) < sizeof(result)) {
00176         strcpy(result, p);
00177         p = strchr(result, '\n');
00178         if (p)
00179             *p = '\0';
00180     } else {
00181         result[0] = '\0';
00182     }
00183     return result;
00184 }
00185 
00186 char * TimeInterface::asctime(const struct tm_ex * timeptr)
00187 {
00188     static const char wday_name[][4] = {
00189         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
00190     };
00191     static const char mon_name[][4] = {
00192         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00193         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00194     };
00195     struct tm_ex tmp = *timeptr;
00196     
00197     tmp.tm_min += tmp.tm_tzo_min;
00198     while (tmp.tm_min >= 60) {
00199         tmp.tm_min -= 60;
00200         tmp.tm_hour++;
00201     }
00202     while (tmp.tm_min < 0) {
00203         tmp.tm_min += 60;
00204         tmp.tm_hour--;
00205     }
00206     while (tmp.tm_hour >= 24) {
00207         tmp.tm_wday = (tmp.tm_wday + 1) % 7;
00208         tmp.tm_mday++;
00209         tmp.tm_hour -= 24;
00210     }
00211     while (tmp.tm_hour < 0) {
00212         tmp.tm_wday = (tmp.tm_wday + 6) % 7;
00213         tmp.tm_mday--;
00214         tmp.tm_hour += 24;
00215     }
00216     sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d",
00217             wday_name[tmp.tm_wday % 7],
00218             mon_name[tmp.tm_mon % 12],
00219             tmp.tm_mday, tmp.tm_hour,
00220             tmp.tm_min, tmp.tm_sec,
00221             1900 + tmp.tm_year);
00222     return result;
00223 }
00224 
00225 struct tm_ex * TimeInterface::localtime(const time_t * timer)
00226 {
00227     time_t priv = *timer + get_tzo_min() * 60 + dst * 3600;
00228     struct tm * tmp = std::localtime(&priv);
00229 
00230     tm_ext.tm_sec     = tmp->tm_sec;
00231     tm_ext.tm_min     = tmp->tm_min;
00232     tm_ext.tm_hour    = tmp->tm_hour;
00233     tm_ext.tm_mday    = tmp->tm_mday;
00234     tm_ext.tm_mon     = tmp->tm_mon;
00235     tm_ext.tm_year    = tmp->tm_year;
00236     tm_ext.tm_wday    = tmp->tm_wday;
00237     tm_ext.tm_yday    = tmp->tm_yday;
00238     tm_ext.tm_isdst   = tmp->tm_isdst;
00239     tm_ext.tm_tzo_min = get_tzo_min();
00240     return &tm_ext;
00241 }
00242 
00243 struct tm_ex * TimeInterface::gmtime(const time_t * timer)
00244 {
00245     struct tm * tmp = std::localtime(timer);
00246 
00247     tm_ext.tm_sec = tmp->tm_sec;
00248     tm_ext.tm_min = tmp->tm_min;
00249     tm_ext.tm_hour = tmp->tm_hour;
00250     tm_ext.tm_mday = tmp->tm_mday;
00251     tm_ext.tm_mon = tmp->tm_mon;
00252     tm_ext.tm_year = tmp->tm_year;
00253     tm_ext.tm_wday = tmp->tm_wday;
00254     tm_ext.tm_yday = tmp->tm_yday;
00255     tm_ext.tm_isdst = tmp->tm_isdst;
00256     tm_ext.tm_tzo_min = get_tzo_min();
00257     return &tm_ext;
00258 }
00259 
00260 time_t TimeInterface::mktime(struct tm_ex * timeptr)
00261 {
00262     timeptr->tm_tzo_min = get_tzo_min();
00263     return std::mktime((struct tm *)timeptr);
00264 }
00265 
00266 size_t TimeInterface::strftime(char * ptr, size_t maxsize, const char * format, const struct tm_ex * timeptr)
00267 {
00268     return std::strftime(ptr, maxsize, format, (struct tm *)timeptr);
00269 }
00270 
00271 double TimeInterface::difftime(time_t end, time_t beginning)
00272 {
00273     return std::difftime(end, beginning);
00274 }
00275 
00276 
00277 
00278 // time zone functions
00279 
00280 void TimeInterface::set_time(time_t t, int16_t tzo_min)
00281 {
00282     time_t tval = t - (tzo_min * 60);
00283     rtc_init();
00284     rtc_write(tval);
00285     LPC_RTC->GPREG1 = tval;
00286     INFO("set_time(%s)", ctime(&tval));
00287 }
00288 
00289 void TimeInterface::set_tzo_min(int16_t tzo_min)
00290 {
00291     uint16_t th;
00292     uint32_t treg;
00293 
00294     if (tzo_min >= -720 && tzo_min <= 720) {
00295         th = (uint16_t)(-tzo_min);
00296         treg = (th << 16) | (uint16_t)tzo_min;
00297         LPC_RTC->GPREG0 = treg;
00298         //printf("set_tzo(%d) %d is %08X\r\n", tzo, th, LPC_RTC->GPREG0);
00299     }
00300 }
00301 
00302 int16_t TimeInterface::get_tzo_min(void)
00303 {
00304     uint16_t th, tl;
00305 
00306     th = LPC_RTC->GPREG0 >> 16;
00307     tl = LPC_RTC->GPREG0;
00308     //printf("get_tzo() is %04X %04X\r\n", th, tl);
00309     if ((uint16_t)(th + tl) == 0) {
00310         return tl;
00311     } else {
00312         return 0;
00313     }
00314 }
00315 
00316 time_t TimeInterface::get_timelastset(void)
00317 {
00318     return LPC_RTC->GPREG1;
00319 }
00320 
00321 int32_t TimeInterface::get_cal()
00322 {
00323     int32_t calvalue = LPC_RTC->CALIBRATION & 0x3FFFF;
00324 
00325     if (calvalue & 0x20000) {
00326         calvalue = -(calvalue & 0x1FFFF);
00327     }
00328     return calvalue;
00329 }
00330 
00331 void TimeInterface::set_cal(int32_t calibration)
00332 {
00333     if (calibration) {
00334         if (calibration < 0) {
00335             calibration = (-calibration & 0x1FFFF) | 0x20000;
00336         }
00337         LPC_RTC->CCR = 0x000001; //(LPC_RTC->CCR & 0x0003);   // Clear CCALEN to enable it
00338     } else {
00339         LPC_RTC->CCR = 0x000011; //(LPC_RTC->CCR & 0x0003) | 0x0010;   // Set CCALEN to disable it
00340     }
00341     LPC_RTC->CALIBRATION = calibration;
00342 }
00343 
00344 bool TimeInterface::adjust_sec(int32_t adjustSeconds)
00345 {
00346     time_t lastSet = get_timelastset();
00347 
00348     if (lastSet != 0) {
00349         time_t seconds = time(NULL);    // get "now" according to the rtc
00350         int32_t delta = seconds - lastSet;
00351         //int32_t curCal = get_cal();   // calibration might want to leverage the current cal factor.
00352         int32_t calMAX = 131071;
00353         int32_t secPerDay = 86400;
00354         float errSecPerDay;
00355 
00356         // Convert the current calibration and the adjustment into
00357         // the new calibration value
00358         // assume it is +10sec and it has been 2days, then the adjustment
00359         // needs to be +5 sec per day, or one adjustment every 1/5th
00360         // of a day, or 1 adjustment every 86400/5 counts.
00361         // delta = now - then (number of elapsed seconds)
00362         if (adjustSeconds != 0 && delta != 0) {
00363             int32_t calFactor;
00364 
00365             // Make the clock correct
00366             seconds = seconds + adjustSeconds;
00367             set_time(seconds);
00368             // Compute the calibration factor
00369             errSecPerDay = (float)adjustSeconds / ((float)(delta)/secPerDay);
00370             calFactor = (int32_t)((float)secPerDay/errSecPerDay);
00371             if (abs(calFactor) < calMAX)
00372                 set_cal(calFactor);
00373         }
00374         return true;
00375     } else {
00376         return false;
00377     }
00378 }
00379 
00380 
00381 // #############################################################################
00382 /*
00383  * Enhancement to use a custom tm_ex struct and the time zone by D. Smart
00384  *  %Z
00385  *
00386  * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
00387  *
00388  * Redistribution and use in source and binary forms, without
00389  * modification, are permitted provided that the following conditions
00390  * are met:
00391  * 1. Redistributions of source code must retain the above copyright
00392  *    notice, this list of conditions and the following disclaimer.
00393  * 2. Redistributions in binary form must reproduce the above copyright
00394  *    notice, this list of conditions and the following disclaimer
00395  *    in the documentation and/or other materials provided with the
00396  *    distribution.
00397  * 3. All advertising materials mentioning features or use of this
00398  *    software must display the following acknowledgement:
00399  *      This product includes software developed by Powerdog Industries.
00400  * 4. The name of Powerdog Industries may not be used to endorse or
00401  *    promote products derived from this software without specific prior
00402  *    written permission.
00403  *
00404  * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
00405  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00406  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00407  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
00408  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00409  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00410  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
00411  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00412  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00413  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00414  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00415  */
00416 
00417 #define asizeof(a)      (sizeof (a) / sizeof ((a)[0]))
00418 
00419 struct dtconv {
00420     char    *abbrev_month_names[12];
00421     char    *month_names[12];
00422     char    *abbrev_weekday_names[7];
00423     char    *weekday_names[7];
00424     char    *time_format;
00425     char    *sdate_format;
00426     char    *dtime_format;
00427     char    *am_string;
00428     char    *pm_string;
00429     char    *ldate_format;
00430     char    *zone_names[10];
00431     int8_t  zone_offsets[10];
00432 };
00433 
00434 static const struct dtconv    En_US = {
00435     {
00436         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00437         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00438     },
00439     {
00440         "January", "February", "March", "April",
00441         "May", "June", "July", "August",
00442         "September", "October", "November", "December"
00443     },
00444     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
00445     {
00446         "Sunday", "Monday", "Tuesday", "Wednesday",
00447         "Thursday", "Friday", "Saturday"
00448     },
00449     "%H:%M:%S",
00450     "%m/%d/%y",
00451     "%a %b %e %T %Z %Y",
00452     "AM",
00453     "PM",
00454     "%A, %B, %e, %Y",
00455     { "UTC", "EST", "CST", "MST", "PST", "YST", "CAT", "HST", "CET", "EET", },
00456     {     0,    -5,    -6,    -7,    -8,    -9,   -10,   -10,    +1,    +2, },
00457 };
00458 
00459 
00460 #ifndef isprint
00461 #define in_range(c, lo, up)  ((uint8_t)c >= lo && (uint8_t)c <= up)
00462 #define isprint(c)           in_range(c, 0x20, 0x7f)
00463 #define isdigit(c)           in_range(c, '0', '9')
00464 #define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
00465 #define islower(c)           in_range(c, 'a', 'z')
00466 #define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
00467 #endif
00468 
00469 
00470 const char * TimeInterface::strptime(const char *buf, char *fmt, struct tm_ex *tm)
00471 {
00472     char c, *ptr;
00473     int i, len;
00474     bool fSet_wday = false;     // so we can notice if the wday was set
00475     
00476     ptr = fmt;
00477     while (*ptr != 0) {
00478         if (*buf == 0)
00479             break;
00480 
00481         c = *ptr++;
00482 
00483         if (c != '%') {
00484             if (isspace(c))
00485                 while (*buf != 0 && isspace(*buf))
00486                     buf++;
00487             else if (c != *buf++)
00488                 return 0;
00489             continue;
00490         }
00491 
00492         c = *ptr++;
00493         switch (c) {
00494             case 0:
00495             case '%':
00496                 if (*buf++ != '%')
00497                     return 0;
00498                 break;
00499 
00500             case 'C':
00501                 buf = strptime(buf, En_US.ldate_format, tm);
00502                 if (buf == 0)
00503                     return 0;
00504                 break;
00505 
00506             case 'c':
00507                 buf = strptime(buf, "%x %X", tm);
00508                 if (buf == 0)
00509                     return 0;
00510                 break;
00511 
00512             case 'D':
00513                 buf = strptime(buf, "%m/%d/%y", tm);
00514                 if (buf == 0)
00515                     return 0;
00516                 break;
00517 
00518             case 'R':
00519                 buf = strptime(buf, "%H:%M", tm);
00520                 if (buf == 0)
00521                     return 0;
00522                 break;
00523 
00524             case 'r':
00525                 buf = strptime(buf, "%I:%M:%S %p", tm);
00526                 if (buf == 0)
00527                     return 0;
00528                 break;
00529 
00530             case 'T':
00531                 buf = strptime(buf, "%H:%M:%S", tm);
00532                 if (buf == 0)
00533                     return 0;
00534                 break;
00535 
00536             case 'X':
00537                 buf = strptime(buf, En_US.time_format, tm);
00538                 if (buf == 0)
00539                     return 0;
00540                 break;
00541 
00542             case 'x':
00543                 buf = strptime(buf, En_US.sdate_format, tm);
00544                 if (buf == 0)
00545                     return 0;
00546                 break;
00547 
00548             case 'j':
00549                 if (!isdigit(*buf))
00550                     return 0;
00551 
00552                 for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
00553                     i *= 10;
00554                     i += *buf - '0';
00555                 }
00556                 if (i > 365)
00557                     return 0;
00558 
00559                 tm->tm_yday = i;
00560                 break;
00561 
00562             case 'M':
00563             case 'S':
00564                 if (*buf == 0 || isspace(*buf))
00565                     break;
00566 
00567                 if (!isdigit(*buf))
00568                     return 0;
00569 
00570                 for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
00571                     i *= 10;
00572                     i += *buf - '0';
00573                 }
00574                 if (i > 59)
00575                     return 0;
00576 
00577                 if (c == 'M')
00578                     tm->tm_min = i;
00579                 else
00580                     tm->tm_sec = i;
00581 
00582                 if (*buf != 0 && isspace(*buf))
00583                     while (*ptr != 0 && !isspace(*ptr))
00584                         ptr++;
00585                 break;
00586 
00587             case 'H':
00588             case 'I':
00589             case 'k':
00590             case 'l':
00591                 if (!isdigit(*buf))
00592                     return 0;
00593 
00594                 for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
00595                     i *= 10;
00596                     i += *buf - '0';
00597                 }
00598                 if (c == 'H' || c == 'k') {
00599                     if (i > 23)
00600                         return 0;
00601                 } else if (i > 11)
00602                     return 0;
00603 
00604                 tm->tm_hour = i;
00605 
00606                 if (*buf != 0 && isspace(*buf))
00607                     while (*ptr != 0 && !isspace(*ptr))
00608                         ptr++;
00609                 break;
00610 
00611             case 'p':
00612                 len = strlen(En_US.am_string);
00613                 if (strncasecmp(buf, En_US.am_string, len) == 0) {
00614                     if (tm->tm_hour > 12)
00615                         return 0;
00616                     if (tm->tm_hour == 12)
00617                         tm->tm_hour = 0;
00618                     buf += len;
00619                     break;
00620                 }
00621 
00622                 len = strlen(En_US.pm_string);
00623                 if (strncasecmp(buf, En_US.pm_string, len) == 0) {
00624                     if (tm->tm_hour > 12)
00625                         return 0;
00626                     if (tm->tm_hour != 12)
00627                         tm->tm_hour += 12;
00628                     buf += len;
00629                     break;
00630                 }
00631 
00632                 return 0;
00633 
00634             case 'A':
00635             case 'a':
00636                 for (i = 0; i < asizeof(En_US.weekday_names); i++) {
00637                     len = strlen(En_US.weekday_names[i]);
00638                     if (strncasecmp(buf,
00639                                     En_US.weekday_names[i],
00640                                     len) == 0)
00641                         break;
00642 
00643                     len = strlen(En_US.abbrev_weekday_names[i]);
00644                     if (strncasecmp(buf,
00645                                     En_US.abbrev_weekday_names[i],
00646                                     len) == 0)
00647                         break;
00648                 }
00649                 if (i == asizeof(En_US.weekday_names))
00650                     return 0;
00651                 fSet_wday = true;
00652                 tm->tm_wday = i;
00653                 buf += len;
00654                 break;
00655 
00656             case 'd':
00657             case 'e':
00658                 if (!isdigit(*buf))
00659                     return 0;
00660 
00661                 for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
00662                     i *= 10;
00663                     i += *buf - '0';
00664                 }
00665                 if (i > 31)
00666                     return 0;
00667 
00668                 tm->tm_mday = i;
00669 
00670                 if (*buf != 0 && isspace(*buf))
00671                     while (*ptr != 0 && !isspace(*ptr))
00672                         ptr++;
00673                 break;
00674 
00675             case 'B':
00676             case 'b':
00677             case 'h':
00678                 for (i = 0; i < asizeof(En_US.month_names); i++) {
00679                     len = strlen(En_US.month_names[i]);
00680                     if (strncasecmp(buf,
00681                                     En_US.month_names[i],
00682                                     len) == 0)
00683                         break;
00684 
00685                     len = strlen(En_US.abbrev_month_names[i]);
00686                     if (strncasecmp(buf,
00687                                     En_US.abbrev_month_names[i],
00688                                     len) == 0)
00689                         break;
00690                 }
00691                 if (i == asizeof(En_US.month_names))
00692                     return 0;
00693 
00694                 tm->tm_mon = i;
00695                 buf += len;
00696                 break;
00697 
00698             case 'm':
00699                 if (!isdigit(*buf))
00700                     return 0;
00701 
00702                 for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
00703                     i *= 10;
00704                     i += *buf - '0';
00705                 }
00706                 if (i < 1 || i > 12)
00707                     return 0;
00708 
00709                 tm->tm_mon = i - 1;
00710 
00711                 if (*buf != 0 && isspace(*buf))
00712                     while (*ptr != 0 && !isspace(*ptr))
00713                         ptr++;
00714                 break;
00715 
00716             case 'Y':
00717             case 'y':
00718                 if (*buf == 0 || isspace(*buf))
00719                     break;
00720 
00721                 if (!isdigit(*buf))
00722                     return 0;
00723 
00724                 for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
00725                     i *= 10;
00726                     i += *buf - '0';
00727                 }
00728                 if (c == 'Y')
00729                     i -= 1900;
00730                 if (i < 0)
00731                     return 0;
00732 
00733                 tm->tm_year = i;
00734 
00735                 if (*buf != 0 && isspace(*buf))
00736                     while (*ptr != 0 && !isspace(*ptr))
00737                         ptr++;
00738                 break;
00739             case 'Z':
00740                 for (i = 0; i < asizeof(En_US.zone_names); i++) {
00741                     len = strlen(En_US.zone_names[i]);
00742                     if (strncasecmp(buf,
00743                                     En_US.zone_names[i],
00744                                     len) == 0)
00745                         break;
00746                 }
00747                 if (i == asizeof(En_US.zone_names))
00748                     return 0;
00749                 tm->tm_tzo_min = En_US.zone_offsets[i] * 60;
00750                 buf += len;
00751                 break;
00752         }
00753     }
00754     if (!fSet_wday) {
00755         if (mktime(tm) == (time_t)-1)
00756             tm->tm_wday = 7;
00757     }
00758     return buf;
00759 }