Simple time management w/o the Network interface

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