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

Revision:
10:5734dbc2f5cc
Parent:
7:1de342fa7840
Child:
11:1d880a50da8a
--- a/TimeInterface.cpp	Sat Mar 26 20:36:02 2016 +0000
+++ b/TimeInterface.cpp	Sun Jan 22 04:06:16 2017 +0000
@@ -50,7 +50,7 @@
     res = ntp.setTime(host, port, timeout);
     INFO("  ret: %d\r\n", res);
     if (res == NTP_OK) {
-        // if the time was fetched successfully, then 
+        // if the time was fetched successfully, then
         // let's save the time last set with the local tzo applied
         // and this saves the last time set for later precision
         // tuning.
@@ -63,7 +63,7 @@
 {
     int x;
     dst_event_t test_dst;
-    
+
     x = atoi(dstr);
     if (x >= 1 && x <= 12) {
         test_dst.MM = x;
@@ -99,9 +99,9 @@
 bool TimeInterface::set_dst(const char * dstStart, const char * dstStop)
 {
     dst_event_pair_t test_pair;
-    
+
     if (parseDSTstring(&test_pair.dst_start, dstStart)
-    && parseDSTstring(&test_pair.dst_stop, dstStop)) {
+            && parseDSTstring(&test_pair.dst_stop, dstStop)) {
         memcpy(&dst_pair, &test_pair, sizeof(dst_event_pair_t));
         INFO("set_dst from (%s,%s)", dstStart, dstStop);
         return true;
@@ -118,7 +118,7 @@
 
 bool TimeInterface::get_dst(void)
 {
-    return dst;   
+    return dst;
 }
 
 clock_t TimeInterface::clock(void)
@@ -140,15 +140,15 @@
 {
     time_t privTime;
     struct tm * tminfo;
-    
+
     if (dst_pair.dst_start.MM) {    // may have to change the dst
         std::time(&privTime);
         tminfo = std::localtime(&privTime);
-        
+
         uint32_t min_since_jan = minutesSinceJan(tminfo->tm_mon + 1, tminfo->tm_mday, tminfo->tm_hour, tminfo->tm_min);
         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();
         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();
-        
+
         if (min_since_jan >= min_dst_start && min_since_jan < min_dst_stop) {
             dst = 1;
             //INFO(" is dst: %u - %u - %u", min_since_jan, min_dst_start, min_dst_stop);
@@ -164,7 +164,7 @@
 char * TimeInterface::ctime(const time_t * timer)
 {
     char * p = std::ctime(timer);
-    
+
     if (strlen(p) < sizeof(result)) {
         strcpy(result, p);
         p = strchr(result, '\n');
@@ -185,21 +185,40 @@
         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
     };
+    struct tm_ex tmp = *timeptr;
     
+    tmp.tm_min += tmp.tm_tzo_min;
+    while (tmp.tm_min >= 60) {
+        tmp.tm_min -= 60;
+        tmp.tm_hour++;
+    }
+    while (tmp.tm_min < 0) {
+        tmp.tm_min += 60;
+        tmp.tm_hour--;
+    }
+    while (tmp.tm_hour >= 24) {
+        tmp.tm_wday = (tmp.tm_wday + 1) % 7;
+        tmp.tm_mday++;
+        tmp.tm_hour -= 24;
+    }
+    while (tmp.tm_hour < 0) {
+        tmp.tm_wday = (tmp.tm_wday + 6) % 7;
+        tmp.tm_mday--;
+        tmp.tm_hour += 24;
+    }
     sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d",
-            wday_name[timeptr->tm_wday % 7],
-            mon_name[timeptr->tm_mon % 12],
-            timeptr->tm_mday, timeptr->tm_hour,
-            timeptr->tm_min, timeptr->tm_sec,
-            1900 + timeptr->tm_year);
+            wday_name[tmp.tm_wday % 7],
+            mon_name[tmp.tm_mon % 12],
+            tmp.tm_mday, tmp.tm_hour,
+            tmp.tm_min, tmp.tm_sec,
+            1900 + tmp.tm_year);
     return result;
 }
 
-struct tm_ex * TimeInterface::gmtime(const time_t * timer)
-{
+struct tm_ex * TimeInterface::gmtime(const time_t * timer) {
     time_t priv = *timer + get_tzo_min() * 60 + dst * 3600;
     struct tm * tmp = std::localtime(&priv);
-    
+
     tm_ext.tm_sec     = tmp->tm_sec;
     tm_ext.tm_min     = tmp->tm_min;
     tm_ext.tm_hour    = tmp->tm_hour;
@@ -213,10 +232,9 @@
     return &tm_ext;
 }
 
-struct tm_ex * TimeInterface::localtime(const time_t * timer)
-{
+struct tm_ex * TimeInterface::localtime(const time_t * timer) {
     struct tm * tmp = std::localtime(timer);
-    
+
     tm_ext.tm_sec = tmp->tm_sec;
     tm_ext.tm_min = tmp->tm_min;
     tm_ext.tm_hour = tmp->tm_hour;
@@ -262,7 +280,7 @@
 {
     uint16_t th;
     uint32_t treg;
-    
+
     if (tzo_min >= -720 && tzo_min <= 720) {
         th = (uint16_t)(-tzo_min);
         treg = (th << 16) | (uint16_t)tzo_min;
@@ -274,7 +292,7 @@
 int16_t TimeInterface::get_tzo_min(void)
 {
     uint16_t th, tl;
-    
+
     th = LPC_RTC->GPREG0 >> 16;
     tl = LPC_RTC->GPREG0;
     //printf("get_tzo() is %04X %04X\r\n", th, tl);
@@ -290,16 +308,18 @@
     return LPC_RTC->GPREG1;
 }
 
-int32_t TimeInterface::get_cal() {
+int32_t TimeInterface::get_cal()
+{
     int32_t calvalue = LPC_RTC->CALIBRATION & 0x3FFFF;
 
     if (calvalue & 0x20000) {
         calvalue = -(calvalue & 0x1FFFF);
-    }    
+    }
     return calvalue;
 }
 
-void TimeInterface::set_cal(int32_t calibration) {
+void TimeInterface::set_cal(int32_t calibration)
+{
     if (calibration) {
         if (calibration < 0) {
             calibration = (-calibration & 0x1FFFF) | 0x20000;
@@ -314,7 +334,7 @@
 bool TimeInterface::adjust_sec(int32_t adjustSeconds)
 {
     time_t lastSet = get_timelastset();
-    
+
     if (lastSet != 0) {
         time_t seconds = time(NULL);    // get "now" according to the rtc
         int32_t delta = seconds - lastSet;
@@ -322,11 +342,11 @@
         int32_t calMAX = 131071;
         int32_t secPerDay = 86400;
         float errSecPerDay;
-                
+
         // Convert the current calibration and the adjustment into
         // the new calibration value
         // assume it is +10sec and it has been 2days, then the adjustment
-        // needs to be +5 sec per day, or one adjustment every 1/5th 
+        // needs to be +5 sec per day, or one adjustment every 1/5th
         // of a day, or 1 adjustment every 86400/5 counts.
         // delta = now - then (number of elapsed seconds)
         if (adjustSeconds != 0 && delta != 0) {
@@ -346,3 +366,381 @@
         return false;
     }
 }
+
+
+// #############################################################################
+/*
+ * Enhancement to use a custom tm_ex struct and the time zone by D. Smart
+ *  %Z
+ *
+ * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgement:
+ *      This product includes software developed by Powerdog Industries.
+ * 4. The name of Powerdog Industries may not be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define asizeof(a)      (sizeof (a) / sizeof ((a)[0]))
+
+struct dtconv {
+    char    *abbrev_month_names[12];
+    char    *month_names[12];
+    char    *abbrev_weekday_names[7];
+    char    *weekday_names[7];
+    char    *time_format;
+    char    *sdate_format;
+    char    *dtime_format;
+    char    *am_string;
+    char    *pm_string;
+    char    *ldate_format;
+    char    *zone_names[9];
+    int8_t  zone_offsets[9];
+};
+
+static struct dtconv    En_US = {
+    {
+        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+    },
+    {
+        "January", "February", "March", "April",
+        "May", "June", "July", "August",
+        "September", "October", "November", "December"
+    },
+    { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
+    {
+        "Sunday", "Monday", "Tuesday", "Wednesday",
+        "Thursday", "Friday", "Saturday"
+    },
+    "%H:%M:%S",
+    "%m/%d/%y",
+    "%a %b %e %T %Z %Y",
+    "AM",
+    "PM",
+    "%A, %B, %e, %Y",
+    { "UTC", "EST", "CST", "MST", "PST" },
+    {     0,   -5,    -6,    -7,    -8  },
+};
+
+#ifndef isprint
+#define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)
+#define isprint(c)           in_range(c, 0x20, 0x7f)
+#define isdigit(c)           in_range(c, '0', '9')
+#define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
+#define islower(c)           in_range(c, 'a', 'z')
+#define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
+#endif
+
+
+const char * TimeInterface::strptime(const char *buf, char *fmt, struct tm_ex *tm)
+{
+    char c, *ptr;
+    int i, len;
+
+    ptr = fmt;
+    while (*ptr != 0) {
+        if (*buf == 0)
+            break;
+
+        c = *ptr++;
+
+        if (c != '%') {
+            if (isspace(c))
+                while (*buf != 0 && isspace(*buf))
+                    buf++;
+            else if (c != *buf++)
+                return 0;
+            continue;
+        }
+
+        c = *ptr++;
+        switch (c) {
+            case 0:
+            case '%':
+                if (*buf++ != '%')
+                    return 0;
+                break;
+
+            case 'C':
+                buf = strptime(buf, En_US.ldate_format, tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'c':
+                buf = strptime(buf, "%x %X", tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'D':
+                buf = strptime(buf, "%m/%d/%y", tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'R':
+                buf = strptime(buf, "%H:%M", tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'r':
+                buf = strptime(buf, "%I:%M:%S %p", tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'T':
+                buf = strptime(buf, "%H:%M:%S", tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'X':
+                buf = strptime(buf, En_US.time_format, tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'x':
+                buf = strptime(buf, En_US.sdate_format, tm);
+                if (buf == 0)
+                    return 0;
+                break;
+
+            case 'j':
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (i > 365)
+                    return 0;
+
+                tm->tm_yday = i;
+                break;
+
+            case 'M':
+            case 'S':
+                if (*buf == 0 || isspace(*buf))
+                    break;
+
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (i > 59)
+                    return 0;
+
+                if (c == 'M')
+                    tm->tm_min = i;
+                else
+                    tm->tm_sec = i;
+
+                if (*buf != 0 && isspace(*buf))
+                    while (*ptr != 0 && !isspace(*ptr))
+                        ptr++;
+                break;
+
+            case 'H':
+            case 'I':
+            case 'k':
+            case 'l':
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (c == 'H' || c == 'k') {
+                    if (i > 23)
+                        return 0;
+                } else if (i > 11)
+                    return 0;
+
+                tm->tm_hour = i;
+
+                if (*buf != 0 && isspace(*buf))
+                    while (*ptr != 0 && !isspace(*ptr))
+                        ptr++;
+                break;
+
+            case 'p':
+                len = strlen(En_US.am_string);
+                if (strncasecmp(buf, En_US.am_string, len) == 0) {
+                    if (tm->tm_hour > 12)
+                        return 0;
+                    if (tm->tm_hour == 12)
+                        tm->tm_hour = 0;
+                    buf += len;
+                    break;
+                }
+
+                len = strlen(En_US.pm_string);
+                if (strncasecmp(buf, En_US.pm_string, len) == 0) {
+                    if (tm->tm_hour > 12)
+                        return 0;
+                    if (tm->tm_hour != 12)
+                        tm->tm_hour += 12;
+                    buf += len;
+                    break;
+                }
+
+                return 0;
+
+            case 'A':
+            case 'a':
+                for (i = 0; i < asizeof(En_US.weekday_names); i++) {
+                    len = strlen(En_US.weekday_names[i]);
+                    if (strncasecmp(buf,
+                                    En_US.weekday_names[i],
+                                    len) == 0)
+                        break;
+
+                    len = strlen(En_US.abbrev_weekday_names[i]);
+                    if (strncasecmp(buf,
+                                    En_US.abbrev_weekday_names[i],
+                                    len) == 0)
+                        break;
+                }
+                if (i == asizeof(En_US.weekday_names))
+                    return 0;
+
+                tm->tm_wday = i;
+                buf += len;
+                break;
+
+            case 'd':
+            case 'e':
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (i > 31)
+                    return 0;
+
+                tm->tm_mday = i;
+
+                if (*buf != 0 && isspace(*buf))
+                    while (*ptr != 0 && !isspace(*ptr))
+                        ptr++;
+                break;
+
+            case 'B':
+            case 'b':
+            case 'h':
+                for (i = 0; i < asizeof(En_US.month_names); i++) {
+                    len = strlen(En_US.month_names[i]);
+                    if (strncasecmp(buf,
+                                    En_US.month_names[i],
+                                    len) == 0)
+                        break;
+
+                    len = strlen(En_US.abbrev_month_names[i]);
+                    if (strncasecmp(buf,
+                                    En_US.abbrev_month_names[i],
+                                    len) == 0)
+                        break;
+                }
+                if (i == asizeof(En_US.month_names))
+                    return 0;
+
+                tm->tm_mon = i;
+                buf += len;
+                break;
+
+            case 'm':
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (i < 1 || i > 12)
+                    return 0;
+
+                tm->tm_mon = i - 1;
+
+                if (*buf != 0 && isspace(*buf))
+                    while (*ptr != 0 && !isspace(*ptr))
+                        ptr++;
+                break;
+
+            case 'Y':
+            case 'y':
+                if (*buf == 0 || isspace(*buf))
+                    break;
+
+                if (!isdigit(*buf))
+                    return 0;
+
+                for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
+                    i *= 10;
+                    i += *buf - '0';
+                }
+                if (c == 'Y')
+                    i -= 1900;
+                if (i < 0)
+                    return 0;
+
+                tm->tm_year = i;
+
+                if (*buf != 0 && isspace(*buf))
+                    while (*ptr != 0 && !isspace(*ptr))
+                        ptr++;
+                break;
+            case 'Z':
+                for (i = 0; i < asizeof(En_US.zone_names); i++) {
+                    len = strlen(En_US.zone_names[i]);
+                    if (strncasecmp(buf,
+                                    En_US.zone_names[i],
+                                    len) == 0)
+                        break;
+                }
+                if (i == asizeof(En_US.zone_names))
+                    return 0;
+printf("z: %s => %d\r\n", En_US.zone_names[i], En_US.zone_offsets[i]);
+                tm->tm_tzo_min = En_US.zone_offsets[i] * 60;
+                buf += len;
+                break;
+        }
+    }
+
+    return buf;
+}
+