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