tzwrapper.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       tzwrapper.cc
00003 ///             Timezone adjustment class, wrapping the TZ environment
00004 ///             variable to make struct tm -> time_t conversions easier.
00005 ///
00006 
00007 /*
00008     Copyright (C) 2010, Chris Frey <cdfrey@foursquare.net>, To God be the glory
00009     Released to the public domain.
00010     Included in Barry and Barrified the namespace July 2010
00011 */
00012 
00013 #include "tzwrapper.h"
00014 #include <string.h>
00015 #include <stdio.h>
00016 
00017 namespace Barry { namespace Sync {
00018 
00019 time_t utc_mktime(struct tm *utctime)
00020 {
00021         time_t result;
00022         struct tm tmp, check;
00023 
00024         // loop, converting "local time" to time_t and back to utc tm,
00025         // and adjusting until there are no differences... this
00026         // automatically takes care of DST issues.
00027 
00028         // do first conversion
00029         tmp = *utctime;
00030         tmp.tm_isdst = -1;
00031         result = mktime(&tmp);
00032         if( result == (time_t)-1 )
00033                 return (time_t)-1;
00034         if( gmtime_r(&result, &check) == NULL )
00035                 return (time_t)-1;
00036 
00037         // loop until match
00038         while(  check.tm_year != utctime->tm_year ||
00039                 check.tm_mon != utctime->tm_mon ||
00040                 check.tm_mday != utctime->tm_mday ||
00041                 check.tm_hour != utctime->tm_hour ||
00042                 check.tm_min != utctime->tm_min )
00043         {
00044                 tmp.tm_min  += utctime->tm_min - check.tm_min;
00045                 tmp.tm_hour += utctime->tm_hour - check.tm_hour;
00046                 tmp.tm_mday += utctime->tm_mday - check.tm_mday;
00047                 tmp.tm_year += utctime->tm_year - check.tm_year;
00048                 tmp.tm_isdst = -1;
00049 
00050                 result = mktime(&tmp);
00051                 if( result == (time_t)-1 )
00052                         return (time_t)-1;
00053                 gmtime_r(&result, &check);
00054                 if( gmtime_r(&result, &check) == NULL )
00055                         return (time_t)-1;
00056         }
00057 
00058         return result; 
00059 }
00060 
00061 struct tm* iso_to_tm(const char *timestamp,
00062                         struct tm *result,
00063                         bool &utc)
00064 {
00065         memset(result, 0, sizeof(struct tm));
00066         char zflag = 0;
00067 
00068         int found = sscanf(timestamp, "%04d%02d%02dT%02d%02d%02d%c",
00069                 &(result->tm_year), &(result->tm_mon), &(result->tm_mday),
00070                 &(result->tm_hour), &(result->tm_min), &(result->tm_sec),
00071                 &zflag);
00072 
00073         result->tm_year -= 1900;
00074         result->tm_mon -= 1;
00075         result->tm_isdst = -1;
00076 
00077         utc = (found == 7 && zflag == 'Z');
00078 
00079         return (found >= 6) ? result : 0;
00080 }
00081 
00082 std::string tm_to_iso(const struct tm *t, bool utc)
00083 {
00084         char tmp[128];
00085 
00086         int cc = snprintf(tmp, sizeof(tmp), "%04d%02d%02dT%02d%02d%02d",
00087                 t->tm_year + 1900,
00088                 t->tm_mon + 1,
00089                 t->tm_mday,
00090                 t->tm_hour,
00091                 t->tm_min,
00092                 t->tm_sec
00093                 );
00094         if( cc < 0 || (size_t)cc >= sizeof(tmp) )
00095                 return "";
00096 
00097         if( utc ) {
00098                 if( (size_t)cc >= (sizeof(tmp) - 1) )
00099                         return "";              // not enough room for Z
00100                 tmp[cc++] = 'Z';
00101                 tmp[cc] = 0;
00102         }
00103 
00104         return tmp;
00105 }
00106 
00107 time_t TzWrapper::iso_mktime(const char *timestamp)
00108 {
00109         bool utc;
00110         struct tm t;
00111         if( !iso_to_tm(timestamp, &t, utc) )
00112                 return (time_t)-1;
00113         TzWrapper tzw;
00114         if( utc )
00115                 tzw.SetUTC();
00116         return tzw.mktime(&t);
00117 }
00118 
00119 }} // namespace Barry::Sync
00120 
00121 
00122 #ifdef TZ_TEST_MODE
00123 #include <iostream>
00124 using namespace std;
00125 using namespace Barry::Sync;
00126 int main()
00127 {
00128         time_t now = time(NULL);
00129 
00130         cout << "TZ:             " << TzWrapper().ctime(&now);
00131         cout << "UTC:            " << TzWrapper("").ctime(&now);
00132         cout << "UTC:            " << TzWrapper().SetUTC().ctime(&now);
00133         cout << "SysLocaltime:   " << TzWrapper().SetUTC().SetSysLocal().ctime(&now);
00134         cout << "TZ:             " << TzWrapper().SetUTC().SetDefault().ctime(&now);
00135         cout << "Canada/Eastern: " << TzWrapper("Canada/Eastern").ctime(&now);
00136         cout << "Canada/Pacific: " << TzWrapper("Canada/Pacific").ctime(&now);
00137 
00138         {
00139                 TzWrapper tzw("UTC");
00140                 cout << "UTC:            " << ctime(&now);
00141         }
00142 
00143         cout << "TZ:             " << ctime(&now);
00144 
00145         // test iso_mktime()... the test values assume a Canada/Eastern TZ
00146         cout << "Using Canada/Eastern:" << endl;
00147         TzWrapper tzw("Canada/Eastern");
00148         const char *iso1 = "20100430T231500";
00149         const char *iso2 = "20100501T031500Z";
00150         time_t t1 = TzWrapper::iso_mktime(iso1);
00151         time_t t2 = TzWrapper::iso_mktime(iso2);
00152         cout << " " << iso1 << ": (" << t1 << ") " << ctime(&t1);
00153         cout        << iso2 << ": (" << t2 << ") " << ctime(&t2);
00154 
00155         if( TzWrapper::iso_mktime("20100430") == (time_t)-1 )
00156                 cout << "Fail check: passed" << endl;
00157         else
00158                 cout << "Fail check: ERROR" << endl;
00159 
00160         cout << "t1: " << tm_to_iso(gmtime(&t1), true) << endl;
00161 }
00162 #endif
00163 
Generated by  doxygen 1.6.2-20100208