00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "tzwrapper.h"
00014 #include <string.h>
00015 #include <stdio.h>
00016 #include <string>
00017
00018 using namespace std;
00019
00020 namespace Barry { namespace Sync {
00021
00022 time_t utc_mktime(struct tm *utctime)
00023 {
00024 time_t result;
00025 struct tm tmp, check;
00026
00027
00028
00029
00030
00031
00032 tmp = *utctime;
00033 tmp.tm_isdst = -1;
00034 result = mktime(&tmp);
00035 if( result == (time_t)-1 )
00036 return (time_t)-1;
00037 if( gmtime_r(&result, &check) == NULL )
00038 return (time_t)-1;
00039
00040
00041 while( check.tm_year != utctime->tm_year ||
00042 check.tm_mon != utctime->tm_mon ||
00043 check.tm_mday != utctime->tm_mday ||
00044 check.tm_hour != utctime->tm_hour ||
00045 check.tm_min != utctime->tm_min )
00046 {
00047 tmp.tm_min += utctime->tm_min - check.tm_min;
00048 tmp.tm_hour += utctime->tm_hour - check.tm_hour;
00049 tmp.tm_mday += utctime->tm_mday - check.tm_mday;
00050 tmp.tm_year += utctime->tm_year - check.tm_year;
00051 tmp.tm_isdst = -1;
00052
00053 result = mktime(&tmp);
00054 if( result == (time_t)-1 )
00055 return (time_t)-1;
00056 gmtime_r(&result, &check);
00057 if( gmtime_r(&result, &check) == NULL )
00058 return (time_t)-1;
00059 }
00060
00061 return result;
00062 }
00063
00064 struct tm* iso_to_tm(const char *timestamp,
00065 struct tm *result,
00066 bool &utc,
00067 bool *zone,
00068 int *zoneminutes)
00069 {
00070 memset(result, 0, sizeof(struct tm));
00071
00072
00073
00074 string ts = timestamp;
00075 string::iterator i = ts.begin();
00076 bool date = true;
00077 while( i != ts.end() ) {
00078 if( *i == 'T' )
00079 date = false;
00080 if( (date && *i == '-') || *i == ':' )
00081 ts.erase(i);
00082 else
00083 ++i;
00084 }
00085
00086 int found = sscanf(ts.c_str(), "%04d%02d%02dT%02d%02d%02d",
00087 &(result->tm_year), &(result->tm_mon), &(result->tm_mday),
00088 &(result->tm_hour), &(result->tm_min), &(result->tm_sec));
00089
00090 result->tm_year -= 1900;
00091 result->tm_mon -= 1;
00092 result->tm_isdst = -1;
00093 if( found == 3 ) {
00094
00095 result->tm_hour = 0;
00096 result->tm_min = 0;
00097 result->tm_sec = 0;
00098 }
00099 else if( found != 6 ) {
00100 return 0;
00101 }
00102
00103 utc = ts.find('Z', 15) != string::npos;
00104
00105 if( zone && zoneminutes ) {
00106 *zone = false;
00107
00108 size_t neg = ts.find('-', 15);
00109 size_t pos = ts.find('+', 15);
00110
00111 if( neg != string::npos || pos != string::npos ) {
00112
00113 size_t it = neg != string::npos ? neg : pos;
00114 it++;
00115 string offset = ts.substr(it);
00116
00117 int hour, min;
00118 found = sscanf(offset.c_str(), "%02d%02d",
00119 &hour, &min);
00120 if( offset.size() == 4 && found == 2 ) {
00121 *zone = true;
00122 *zoneminutes = hour * 60 + min;
00123 if( neg != string::npos )
00124 *zoneminutes *= -1;
00125 }
00126 }
00127 }
00128
00129 return result;
00130 }
00131
00132 std::string tm_to_iso(const struct tm *t, bool utc)
00133 {
00134 char tmp[128];
00135
00136 int cc = snprintf(tmp, sizeof(tmp), "%04d%02d%02dT%02d%02d%02d",
00137 t->tm_year + 1900,
00138 t->tm_mon + 1,
00139 t->tm_mday,
00140 t->tm_hour,
00141 t->tm_min,
00142 t->tm_sec
00143 );
00144 if( cc < 0 || (size_t)cc >= sizeof(tmp) )
00145 return "";
00146
00147 if( utc ) {
00148 if( (size_t)cc >= (sizeof(tmp) - 1) )
00149 return "";
00150 tmp[cc++] = 'Z';
00151 tmp[cc] = 0;
00152 }
00153
00154 return tmp;
00155 }
00156
00157 TzWrapper& TzWrapper::SetOffset(int zoneminutes)
00158 {
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 char buf[128];
00175 sprintf(buf, "XXX%c%02d:%02d",
00176 (zoneminutes < 0 ? '+' : '-'),
00177 abs(zoneminutes) / 60,
00178 abs(zoneminutes) % 60
00179 );
00180 return Set(buf);
00181 }
00182
00183 time_t TzWrapper::iso_mktime(const char *timestamp)
00184 {
00185 bool utc, zone;
00186 struct tm t;
00187 int zoneminutes;
00188 if( !iso_to_tm(timestamp, &t, utc, &zone, &zoneminutes) )
00189 return (time_t)-1;
00190
00191 TzWrapper tzw;
00192 if( utc ) {
00193 tzw.SetUTC();
00194 }
00195 else if( zone ) {
00196 tzw.SetOffset(zoneminutes);
00197 }
00198 return tzw.mktime(&t);
00199 }
00200
00201 }}
00202
00203
00204 #ifdef TZ_TEST_MODE
00205 #include <iostream>
00206 using namespace std;
00207 using namespace Barry::Sync;
00208 int main()
00209 {
00210 time_t now = time(NULL);
00211
00212 cout << "TZ: " << TzWrapper().ctime(&now);
00213 cout << "UTC: " << TzWrapper("").ctime(&now);
00214 cout << "UTC: " << TzWrapper().SetUTC().ctime(&now);
00215 cout << "SysLocaltime: " << TzWrapper().SetUTC().SetSysLocal().ctime(&now);
00216 cout << "TZ: " << TzWrapper().SetUTC().SetDefault().ctime(&now);
00217 cout << "Canada/Eastern: " << TzWrapper("Canada/Eastern").ctime(&now);
00218 cout << "Canada/Pacific: " << TzWrapper("Canada/Pacific").ctime(&now);
00219
00220 {
00221 TzWrapper tzw("UTC");
00222 cout << "UTC: " << ctime(&now);
00223 }
00224
00225 cout << "TZ: " << ctime(&now);
00226
00227
00228 cout << "Using Canada/Eastern:" << endl;
00229 TzWrapper tzw("Canada/Eastern");
00230 const char *iso1 = "20100430T231500";
00231 const char *iso2 = "20100501T031500Z";
00232 time_t t1 = TzWrapper::iso_mktime(iso1);
00233 time_t t2 = TzWrapper::iso_mktime(iso2);
00234 cout << " " << iso1 << ": (" << t1 << ") " << ctime(&t1);
00235 cout << iso2 << ": (" << t2 << ") " << ctime(&t2);
00236 if( t1 == t2 )
00237 cout << "t1 == t2: passed" << endl;
00238 else
00239 cout << "t1 != t2: ERROR" << endl;
00240
00241 time_t t3 = TzWrapper::iso_mktime("2010-05-01T03:15:00.000Z");
00242 cout << ctime(&t3);
00243 if( t2 == t3 )
00244 cout << "t2 == t3: passed" << endl;
00245 else
00246 cout << "t2 != t3: ERROR" << endl;
00247
00248 time_t t4 = TzWrapper::iso_mktime("2010-05-01T04:15:00.000+01:00");
00249 cout << ctime(&t4);
00250 if( t3 == t4 )
00251 cout << "t3 == t4: passed" << endl;
00252 else
00253 cout << "t3 != t4: ERROR" << endl;
00254
00255 time_t t5 = TzWrapper::iso_mktime("2010-05-01T00:15:00.000-03:00");
00256 cout << ctime(&t5);
00257 if( t4 == t5 )
00258 cout << "t4 == t5: passed" << endl;
00259 else
00260 cout << "t4 != t5: ERROR: t4: " << t4 << " t5: " << t5 << endl;
00261
00262 if( TzWrapper::iso_mktime("20100430") != (time_t)-1 )
00263 cout << "Date check: passed" << endl;
00264 else
00265 cout << "Date check: ERROR" << endl;
00266
00267 cout << "t1: " << tm_to_iso(gmtime(&t1), true) << endl;
00268
00269 bool utc, zone;
00270 int zoneminutes;
00271 struct tm zonetest;
00272 if( !iso_to_tm("2010-05-01T04:15:00.000-", &zonetest, utc, &zone, &zoneminutes) )
00273 cout << "iso_to_tm failed wrongly: ERROR" << endl;
00274 if( zone )
00275 cout << "zone true?: ERROR" << endl;
00276 else
00277 cout << "zone fail check: passed" << endl;
00278
00279 if( !iso_to_tm("2010-05-01T04:15:00.000-010", &zonetest, utc, &zone, &zoneminutes) )
00280 cout << "iso_to_tm failed wrongly: ERROR" << endl;
00281 if( zone )
00282 cout << "zone true?: ERROR" << endl;
00283 else
00284 cout << "zone fail check2: passed" << endl;
00285 }
00286 #endif
00287