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.27 2006/06/22 23:24:05 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() { 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 {
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 Set(year, month, day, hour, min, sec, nsec, isUTC, secOffset);
00104 }
00105
00106
00107 VldTimeStamp::VldTimeStamp(UInt_t date, UInt_t time, UInt_t nsec,
00108 Bool_t isUTC, Int_t secOffset)
00109 {
00110
00111
00112
00113 Set(date, time, nsec, isUTC, secOffset);
00114 }
00115
00116
00117 const char *VldTimeStamp::AsString(Option_t *option) const
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
00144
00145
00146
00147
00148
00149
00150
00151 const int nbuffers = 8;
00152
00153 static char formatted[nbuffers][64];
00154 static char formatted2[nbuffers][64];
00155 static int ibuffer = nbuffers;
00156 ibuffer = (ibuffer+1)%nbuffers;
00157
00158 TString opt = option;
00159 opt.ToLower();
00160
00161 if (opt.Contains("2")) {
00162
00163 sprintf(formatted[ibuffer], "{%d,%d}", fSec, fNanoSec);
00164 return formatted[ibuffer];
00165 }
00166
00167 #ifdef linux
00168
00169 const char *RFC822 = "%a, %d %b %Y %H:%M:%S %z (%Z) +#9ld nsec";
00170 const char *ISO8601 = "%Y-%m-%d %H:%M:%S.#9.9ld%z";
00171 const char *ISO8601Z = "%Y-%m-%d %H:%M:%S.#9.9ldZ";
00172 #else
00173
00174 const char *RFC822 = "%a, %d %b %Y %H:%M:%S %Z +#9ld nsec";
00175 const char *ISO8601 = "%Y-%m-%d %H:%M:%S.#9.9ld%Z";
00176 const char *ISO8601Z = "%Y-%m-%d %H:%M:%S.#9.9ldZ";
00177 #endif
00178 const char *SQL = "%Y-%m-%d %H:%M:%S";
00179
00180 Bool_t asLocal = opt.Contains("l");
00181 Bool_t asSQL = opt.Contains("s");
00182 if (asSQL) asLocal = kFALSE;
00183
00184 const char *format = RFC822;
00185 if (opt.Contains("c")) {
00186 format = ISO8601;
00187 if (!asLocal) format = ISO8601Z;
00188 }
00189 if (asSQL) format = SQL;
00190
00191 struct tm *ptm;
00192 time_t seconds = (time_t) fSec;
00193
00194
00195
00196
00197 ptm = (asLocal) ? localtime(&seconds) : gmtime(&seconds);
00198
00199
00200
00201 strftime(formatted[ibuffer], sizeof(formatted[ibuffer]), format, ptm);
00202
00203 if (asSQL) return formatted[ibuffer];
00204
00205
00206 char *ptr = strrchr(formatted[ibuffer], '#');
00207 if (ptr) *ptr = '%';
00208 sprintf(formatted2[ibuffer], formatted[ibuffer], fNanoSec);
00209
00210 return formatted2[ibuffer];
00211 }
00212
00213
00214 void VldTimeStamp::Copy(VldTimeStamp &ts) const
00215 {
00216
00217
00218 ts.fSec = fSec;
00219 ts.fNanoSec = fNanoSec;
00220
00221 }
00222
00223
00224 Int_t VldTimeStamp::GetDate(Bool_t inUTC, Int_t secOffset,
00225 UInt_t* year, UInt_t* month, UInt_t* day) const
00226 {
00227
00228
00229
00230 time_t atime = fSec + secOffset;
00231 struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
00232
00233 if (year) *year = ptm->tm_year + 1900;
00234 if (month) *month = ptm->tm_mon + 1;
00235 if (day) *day = ptm->tm_mday;
00236
00237 return (1900+ptm->tm_year)*10000 + (1+ptm->tm_mon)*100 + ptm->tm_mday;
00238
00239 }
00240
00241
00242 Int_t VldTimeStamp::GetTime(Bool_t inUTC, Int_t secOffset,
00243 UInt_t* hour, UInt_t* min, UInt_t* sec) const
00244 {
00245
00246
00247
00248 time_t atime = fSec + secOffset;
00249 struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
00250
00251 if (hour) *hour = ptm->tm_hour;
00252 if (min) *min = ptm->tm_min;
00253 if (sec) *sec = ptm->tm_sec;
00254
00255 return ptm->tm_hour*10000 + ptm->tm_min*100 + ptm->tm_sec;
00256
00257 }
00258
00259
00260 Int_t VldTimeStamp::GetZoneOffset()
00261 {
00262
00263
00264
00265
00266 #ifndef R__WIN32
00267 tzset();
00268 #if !defined(R__MACOSX) && !defined(R__FBSD)
00269 return timezone;
00270 #else
00271 time_t *tp = 0;
00272 time(tp);
00273 return localtime(tp)->tm_gmtoff;
00274 #endif
00275 #else
00276 _tzset();
00277 return _timezone;
00278 #endif
00279 }
00280
00281
00282 void VldTimeStamp::Add(const VldTimeStamp &offset)
00283 {
00284
00285
00286 fSec += offset.fSec;
00287 fNanoSec += offset.fNanoSec;
00288 NormalizeNanoSec();
00289
00290 }
00291
00292 void VldTimeStamp::Add(Double_t seconds)
00293 {
00294
00295
00296 fSec += (Int_t) seconds;
00297 fNanoSec += (Int_t) (fmod(seconds,1.0) * 1e9);
00298 NormalizeNanoSec();
00299 if(seconds > 1e6)
00300 MSG("Vld",Msg::kWarning) << "VldTimeStamp moved by offset " << seconds <<" which is too large to maintain ns accuracy." << endl;
00301 }
00302
00303
00304 void VldTimeStamp::Print(Option_t *option) const
00305 {
00306
00307
00308 printf("Date/Time = %s\n", AsString(option));
00309
00310 }
00311
00312
00313 void VldTimeStamp::Set()
00314 {
00315
00316
00317
00318
00319
00320
00321 #ifdef R__WIN32
00322 ULARGE_INTEGER time;
00323 GetSystemTimeAsFileTime((FILETIME *)&time);
00324
00325
00326
00327 fNanoSec = Int_t((time.QuadPart * (unsigned __int64) 100) %
00328 (unsigned __int64) 1000000000);
00329 time.QuadPart -=
00330 (unsigned __int64) (1000*1000*10)
00331 * (unsigned __int64) (60 * 60 * 24)
00332 * (unsigned __int64) (134774);
00333
00334 fSec = Int_t(time.QuadPart/(unsigned __int64) (1000*1000*10));
00335 #else
00336
00337
00338 struct timeval now;
00339 if (!gettimeofday(&now,0)) {
00340 fSec = now.tv_sec;
00341 fNanoSec = now.tv_usec * 1000;
00342 }
00343 else {
00344 time_t nowtime;
00345 time(&nowtime);
00346 fSec = nowtime;
00347 fNanoSec = 0;
00348 }
00349 #endif
00350 static Int_t sec = 0, nsec = 0, fake_ns = 0;
00351
00352 if (fSec == sec && fNanoSec == nsec)
00353 fNanoSec += ++fake_ns;
00354 else {
00355 fake_ns = 0;
00356 sec = fSec;
00357 nsec = fNanoSec;
00358 }
00359
00360 }
00361
00362
00363 void VldTimeStamp::Set(Int_t year, Int_t month, Int_t day,
00364 Int_t hour, Int_t min, Int_t sec,
00365 Int_t nsec, Bool_t isUTC, Int_t secOffset)
00366 {
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 if (year <= 37) year += 2000;
00383 if (year >= 70 && year <= 137) year += 1900;
00384
00385 if (year >= 1900) year -= 1900;
00386
00387 struct tm tmstruct;
00388 tmstruct.tm_year = year;
00389 tmstruct.tm_mon = month-1;
00390 tmstruct.tm_mday = day;
00391 tmstruct.tm_hour = hour;
00392 tmstruct.tm_min = min;
00393 tmstruct.tm_sec = sec + secOffset;
00394 tmstruct.tm_isdst = -1;
00395
00396 const time_t bad_time_t = (time_t) -1;
00397
00398
00399
00400
00401 time_t utc_sec = (isUTC) ? MktimeFromUTC(&tmstruct) : mktime(&tmstruct);
00402
00403
00404
00405 if (utc_sec == bad_time_t)
00406 MSG("Vld",Msg::kInfo)
00407 << "VldTimeStamp::Set mktime returned -1" << endl;
00408
00409 fSec = utc_sec;
00410 fNanoSec = nsec;
00411
00412 NormalizeNanoSec();
00413 }
00414
00415
00416 void VldTimeStamp::Set(Int_t date, Int_t time, Int_t nsec,
00417 Bool_t isUTC, Int_t secOffset)
00418 {
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434 Int_t year = date/10000;
00435 Int_t month = (date-year*10000)/100;
00436 Int_t day = date%100;
00437
00438
00439 const Int_t 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_t hour = time/10000;
00449 Int_t min = (time-hour*10000)/100;
00450 Int_t sec = time%100;
00451
00452 Set(year, month, day, hour, min, sec, nsec, isUTC, secOffset);
00453
00454 }
00455
00456
00457 void VldTimeStamp::NormalizeNanoSec()
00458 {
00459
00460
00461
00462 while (fNanoSec < 0) {
00463 fNanoSec += kNsPerSec;
00464 fSec -= 1;
00465 }
00466
00467 while (fNanoSec >= kNsPerSec) {
00468 fNanoSec -= kNsPerSec;
00469 fSec += 1;
00470 }
00471 }
00472
00473 time_t VldTimeStamp::MktimeFromUTC(tm_t *tmstruct)
00474 {
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 const Int_t days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00487 const Int_t daysLeap[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00488
00489 Int_t year = tmstruct->tm_year + 1900;
00490 Bool_t isleap = VldTimeStamp::IsLeapYear(year);
00491
00492 const Int_t *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_t 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_t 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_t VldTimeStamp::IsLeapYear(Int_t 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 VldTimeStamp::DumpTMStruct(const tm_t &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
00592
00593 printf(",\n tm_gmtoff %7ld, tm_zone \"%s\"",
00594 #ifdef __USE_BSD
00595 tmstruct.tm_gmtoff,tmstruct.tm_zone);
00596 #else
00597 tmstruct.__tm_gmtoff,tmstruct.__tm_zone);
00598 #endif
00599 #endif
00600 printf("}\n");
00601 }
00602