00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031 #include "Context/TimeStamp.h"
00032 #include <iostream>
00033 #include <cmath>
00034 #include <string>
00035 #include <algorithm>
00036 #include <limits.h>
00037 #include <cstring>
00038 #include <cstdio>
00039
00040 const int kNsPerSec = 1000000000;
00041
00042
00043 std::ostream& operator<<(std::ostream& os, const TimeStamp& ts)
00044 {
00045 if (os.good()) {
00046 if (os.tie()) os.tie()->flush();
00047 os << ts.AsString("c");
00048 }
00049
00050 if (os.flags() & std::ios::unitbuf) os.flush();
00051 return os;
00052 }
00053
00054 TimeStamp TimeStamp::GetBOT()
00055 {
00056 return TimeStamp((time_t)0,0);
00057 }
00058
00059 TimeStamp TimeStamp::GetEOT()
00060 {
00061 return TimeStamp((time_t)INT_MAX,0);
00062 }
00063
00064 TimeStamp TimeStamp::GetNBOT()
00065 {
00066 return TimeStamp((time_t)INT_MIN,0);
00067 }
00068
00069
00070
00071
00072
00073
00074
00075 TimeStamp::TimeStamp() { Set(); }
00076 TimeStamp::~TimeStamp() { ; }
00077
00078
00079 TimeStamp::TimeStamp(unsigned int year, unsigned int month,
00080 unsigned int day, unsigned int hour,
00081 unsigned int min, unsigned int sec,
00082 unsigned int nsec,
00083 bool isUTC, int secOffset)
00084 {
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 Set(year, month, day, hour, min, sec, nsec, isUTC, secOffset);
00096 }
00097
00098
00099 TimeStamp::TimeStamp(unsigned int date, unsigned int time, unsigned int nsec,
00100 bool isUTC, int secOffset)
00101 {
00102
00103
00104
00105 Set(date, time, nsec, isUTC, secOffset);
00106 }
00107
00108
00109 const char *TimeStamp::AsString(const char* option) const
00110 {
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 const int nbuffers = 8;
00144
00145 static char formatted[nbuffers][64];
00146 static char formatted2[nbuffers][64];
00147 static int ibuffer = nbuffers;
00148 ibuffer = (ibuffer+1)%nbuffers;
00149
00150 std::string opt = option;
00151 std::transform(opt.begin(),opt.end(),opt.begin(),::tolower);
00152
00153 if (opt.find("2") != std::string::npos) {
00154
00155 sprintf(formatted[ibuffer], "{%d,%d}", mSec, mNanoSec);
00156 return formatted[ibuffer];
00157 }
00158
00159 #ifdef linux
00160
00161 const char *RFC822 = "%a, %d %b %Y %H:%M:%S %z (%Z) +#9ld nsec";
00162 const char *ISO8601 = "%Y-%m-%d %H:%M:%S.#9.9ld%z";
00163 const char *ISO8601Z = "%Y-%m-%d %H:%M:%S.#9.9ldZ";
00164 #else
00165
00166 const char *RFC822 = "%a, %d %b %Y %H:%M:%S %Z +#9ld nsec";
00167 const char *ISO8601 = "%Y-%m-%d %H:%M:%S.#9.9ld%Z";
00168 const char *ISO8601Z = "%Y-%m-%d %H:%M:%S.#9.9ldZ";
00169 #endif
00170 const char *SQL = "%Y-%m-%d %H:%M:%S";
00171
00172 bool asLocal = (opt.find("l") != std::string::npos);
00173 bool asSQL = (opt.find("s") != std::string::npos);
00174 if (asSQL) asLocal = false;
00175
00176 const char *format = RFC822;
00177 if (opt.find("c") != std::string::npos) {
00178 format = ISO8601;
00179 if (!asLocal) format = ISO8601Z;
00180 }
00181 if (asSQL) format = SQL;
00182
00183 struct tm *ptm;
00184 time_t seconds = (time_t) mSec;
00185
00186
00187
00188
00189 ptm = (asLocal) ? localtime(&seconds) : gmtime(&seconds);
00190
00191
00192
00193 strftime(formatted[ibuffer], sizeof(formatted[ibuffer]), format, ptm);
00194
00195 if (asSQL) return formatted[ibuffer];
00196
00197
00198 char *ptr = strrchr(formatted[ibuffer], '#');
00199 if (ptr) *ptr = '%';
00200 sprintf(formatted2[ibuffer], formatted[ibuffer], mNanoSec);
00201
00202 return formatted2[ibuffer];
00203 }
00204
00205
00206 void TimeStamp::Copy(TimeStamp &ts) const
00207 {
00208
00209
00210 ts.mSec = mSec;
00211 ts.mNanoSec = mNanoSec;
00212
00213 }
00214
00215
00216 int TimeStamp::GetDate(bool inUTC, int secOffset,
00217 unsigned int* year, unsigned int* month, unsigned int* day) const
00218 {
00219
00220
00221
00222 time_t atime = mSec + secOffset;
00223 struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
00224
00225 if (year) *year = ptm->tm_year + 1900;
00226 if (month) *month = ptm->tm_mon + 1;
00227 if (day) *day = ptm->tm_mday;
00228
00229 return (1900+ptm->tm_year)*10000 + (1+ptm->tm_mon)*100 + ptm->tm_mday;
00230
00231 }
00232
00233
00234 int TimeStamp::GetTime(bool inUTC, int secOffset,
00235 unsigned int* hour, unsigned int* min, unsigned int* sec) const
00236 {
00237
00238
00239
00240 time_t atime = mSec + secOffset;
00241 struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
00242
00243 if (hour) *hour = ptm->tm_hour;
00244 if (min) *min = ptm->tm_min;
00245 if (sec) *sec = ptm->tm_sec;
00246
00247 return ptm->tm_hour*10000 + ptm->tm_min*100 + ptm->tm_sec;
00248
00249 }
00250
00251
00252 int TimeStamp::GetZoneOffset()
00253 {
00254
00255
00256
00257
00258 #ifndef R__WIN32
00259 tzset();
00260 #if !defined(R__FBSD) && !defined(__APPLE__)
00261 return timezone;
00262 #else
00263 time_t *tp = 0;
00264 time(tp);
00265 return localtime(tp)->tm_gmtoff;
00266 #endif
00267 #else
00268 _tzset();
00269 return _timezone;
00270 #endif
00271 }
00272
00273
00274 void TimeStamp::Add(const TimeStamp &offset)
00275 {
00276
00277
00278 mSec += offset.mSec;
00279 mNanoSec += offset.mNanoSec;
00280 NormalizeNanoSec();
00281
00282 }
00283
00284 void TimeStamp::Add(double seconds)
00285 {
00286
00287
00288 mSec += (int) seconds;
00289 mNanoSec += (int) (fmod(seconds,1.0) * 1e9);
00290 NormalizeNanoSec();
00291 if(seconds > 1e6)
00292 std::cerr << "TimeStamp moved by offset " << seconds <<" which is too large to maintain ns accuracy." << std::endl;
00293 }
00294
00295 void TimeStamp::Subtract(const TimeStamp &offset)
00296 {
00297
00298
00299 mSec -= offset.mSec;
00300 mNanoSec -= offset.mNanoSec;
00301 NormalizeNanoSec();
00302
00303 }
00304
00305 void TimeStamp::Subtract(double seconds)
00306 {
00307
00308
00309 mSec -= (int) seconds;
00310 mNanoSec -= (int) (fmod(seconds,1.0) * 1e9);
00311 NormalizeNanoSec();
00312 if(seconds > 1e6)
00313 std::cerr << "TimeStamp moved by offset " << seconds <<" which is too large to maintain ns accuracy." << std::endl;
00314 }
00315
00316
00317
00318 void TimeStamp::Print(const char* option) const
00319 {
00320
00321
00322 printf("Date/Time = %s\n", AsString(option));
00323
00324 }
00325
00326 #include <sys/time.h>
00327
00328
00329 void TimeStamp::Set()
00330 {
00331
00332
00333
00334
00335
00336
00337
00338
00339 struct timeval now;
00340 if (!gettimeofday(&now,0)) {
00341 mSec = now.tv_sec;
00342 mNanoSec = now.tv_usec * 1000;
00343 }
00344 else {
00345 time_t nowtime;
00346 time(&nowtime);
00347 mSec = nowtime;
00348 mNanoSec = 0;
00349 }
00350
00351 static int sec = 0, nsec = 0, fake_ns = 0;
00352
00353 if (mSec == sec && mNanoSec == nsec)
00354 mNanoSec += ++fake_ns;
00355 else {
00356 fake_ns = 0;
00357 sec = mSec;
00358 nsec = mNanoSec;
00359 }
00360
00361 }
00362
00363
00364 void TimeStamp::Set(int year, int month, int day,
00365 int hour, int min, int sec,
00366 int nsec, bool isUTC, int secOffset)
00367 {
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 if (year <= 37) year += 2000;
00384 if (year >= 70 && year <= 137) year += 1900;
00385
00386 if (year >= 1900) year -= 1900;
00387
00388 struct tm tmstruct;
00389 tmstruct.tm_year = year;
00390 tmstruct.tm_mon = month-1;
00391 tmstruct.tm_mday = day;
00392 tmstruct.tm_hour = hour;
00393 tmstruct.tm_min = min;
00394 tmstruct.tm_sec = sec + secOffset;
00395 tmstruct.tm_isdst = -1;
00396
00397 const time_t bad_time_t = (time_t) -1;
00398
00399
00400
00401
00402 time_t utc_sec = (isUTC) ? MktimeFromUTC(&tmstruct) : mktime(&tmstruct);
00403
00404
00405
00406 if (utc_sec == bad_time_t)
00407 std::cerr << "TimeStamp::Set mktime returned -1" << std::endl;
00408
00409 mSec = utc_sec;
00410 mNanoSec = nsec;
00411
00412 NormalizeNanoSec();
00413 }
00414
00415
00416 void TimeStamp::Set(int date, int time, int nsec,
00417 bool isUTC, int secOffset)
00418 {
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434 int year = date/10000;
00435 int month = (date-year*10000)/100;
00436 int day = date%100;
00437
00438
00439 const int oneday = 240000;
00440 while (time < 0) {
00441 time += oneday;
00442 day -= 1;
00443 }
00444 while (time > oneday) {
00445 time -= oneday;
00446 day += 1;
00447 }
00448 int hour = time/10000;
00449 int min = (time-hour*10000)/100;
00450 int sec = time%100;
00451
00452 Set(year, month, day, hour, min, sec, nsec, isUTC, secOffset);
00453
00454 }
00455
00456
00457 void TimeStamp::NormalizeNanoSec()
00458 {
00459
00460
00461
00462 while (mNanoSec < 0) {
00463 mNanoSec += kNsPerSec;
00464 mSec -= 1;
00465 }
00466
00467 while (mNanoSec >= kNsPerSec) {
00468 mNanoSec -= kNsPerSec;
00469 mSec += 1;
00470 }
00471 }
00472
00473 time_t TimeStamp::MktimeFromUTC(tm *tmstruct)
00474 {
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 const int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00487 const int daysLeap[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00488
00489 int year = tmstruct->tm_year + 1900;
00490 bool isleap = TimeStamp::IsLeapYear(year);
00491
00492 const int *daysInMonth = days;
00493 if (isleap) daysInMonth = daysLeap;
00494
00495
00496
00497 int &ref_tm_mon = tmstruct->tm_mon;
00498 int &ref_tm_mday = tmstruct->tm_mday;
00499
00500 tmstruct->tm_yday = 0;
00501 for (int imonth = 0; imonth < ref_tm_mon; imonth++) {
00502 tmstruct->tm_yday += daysInMonth[imonth];
00503 }
00504 tmstruct->tm_yday += ref_tm_mday - 1;
00505
00506
00507 while (ref_tm_mday > daysInMonth[ref_tm_mon]) {
00508 ref_tm_mday -= daysInMonth[ref_tm_mon];
00509 ref_tm_mon++;
00510 }
00511
00512
00513
00514
00515 tmstruct->tm_isdst = 0;
00516
00517
00518
00519
00520 int utc_sec = tmstruct->tm_sec +
00521 tmstruct->tm_min*60 +
00522 tmstruct->tm_hour*3600 +
00523 tmstruct->tm_yday*86400 +
00524 (tmstruct->tm_year-70)*31536000 +
00525 ((tmstruct->tm_year-69)/4)*86400;
00526
00527 return utc_sec;
00528 }
00529
00530
00531 bool TimeStamp::IsLeapYear(int year)
00532 {
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545 if (year%4 != 0) {
00546 return false;
00547 }
00548 else {
00549 if (year%400 == 0) {
00550 return true;
00551 }
00552 else {
00553 if (year%100 == 0) {
00554 return false;
00555 }
00556 else {
00557 return true;
00558 }
00559 }
00560 }
00561
00562 }
00563
00564
00565 void TimeStamp::DumpTMStruct(const tm &tmstruct)
00566 {
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 printf(" tm { year %4d, mon %2d, day %2d,\n",
00579 tmstruct.tm_year,
00580 tmstruct.tm_mon,
00581 tmstruct.tm_mday);
00582 printf(" hour %2d, min %2d, sec %2d,\n",
00583 tmstruct.tm_hour,
00584 tmstruct.tm_min,
00585 tmstruct.tm_sec);
00586 printf(" wday %2d, yday %3d, isdst %2d",
00587 tmstruct.tm_wday,
00588 tmstruct.tm_yday,
00589 tmstruct.tm_isdst);
00590 #ifdef linux
00591 printf(",\n tm_gmtoff %7ld, tm_zone \"%s\"",
00592 #ifdef __USE_BSD
00593 tmstruct.tm_gmtoff,tmstruct.tm_zone);
00594 #else
00595 tmstruct.__tm_gmtoff,tmstruct.__tm_zone);
00596 #endif
00597 #endif
00598 printf("}\n");
00599 }
00600