00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "BaBar/BaBar.hh"
00023
00024
00025
00026
00027 #include "BdbTime/BdbTime.hh"
00028
00029
00030
00031
00032 #include <assert.h>
00033 #include <errno.h>
00034 #include <strings.h>
00035 #include <iomanip>
00036
00037
00038
00039
00040 #include "BdbTime/BdbTimeInput.hh"
00041 #include "BbrStdUtils/Tokenize.hh"
00042 using std::ostream;
00043
00044
00045
00046
00047 const BdbTime BdbTime::minusInfinity = BdbTime( BdbTimeConst::minusInfinity );
00048 const BdbTime BdbTime::plusInfinity = BdbTime( BdbTimeConst::plusInfinity );
00049
00050
00051
00052
00053 static const char rcsid[] = "$Id: BdbTime.cc,v 1.24 2004/09/09 04:41:01 gowdy Exp $";
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 static inline d_ULong POSIXto1901( time_t t )
00067 {
00068 return ( t >= 0
00069
00070 ? ( BdbTimeConst::seconds_1901_to_1970 + d_ULong(t) )
00071
00072 : ( BdbTimeConst::seconds_1901_to_1970 - d_ULong(-t) ) );
00073 }
00074
00075
00076
00077 static const d_ULong fix1901_offset = ( 6*365 + 1 ) * 24 * 60 * 60;
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 static bool TMto1901( struct tm& stm, BdbTime::Zone zone, d_ULong& t1901 )
00093 {
00094 const bool fix1901 = ( stm.tm_year == 1 );
00095 if ( fix1901 ) {
00096 stm.tm_year = 7;
00097
00098 }
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 errno = 0;
00112 time_t t = mktime( &stm );
00113
00114
00115
00116 assert( errno == 0 );
00117 if ( errno != 0 ) {
00118 return false;
00119 }
00120
00121
00122
00123
00124 #ifdef __APPLE_CC__
00125 d_Long timezone=0;
00126 errno = 0;
00127 time_t otherT = timegm( &stm );
00128 if ( errno != 0 ) return false;
00129 timezone = t - otherT;
00130 #endif
00131
00132
00133
00134
00135 d_ULong ut = POSIXto1901( t );
00136
00137
00138
00139 if ( fix1901 ) {
00140 assert( ut >= fix1901_offset );
00141 ut -= fix1901_offset;
00142 stm.tm_year = 1;
00143 }
00144
00145
00146
00147 if ( BdbTime::UTC == zone ) {
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 ut -= timezone;
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 assert( 0 <= stm.tm_isdst );
00174 if ( 0 < stm.tm_isdst ) ut += ( 60*60 );
00175 else if ( 0 > stm.tm_isdst ) {
00176
00177 return false;
00178 }
00179 }
00180
00181 t1901 = ut;
00182 return true;
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 BdbTime::BdbTime( )
00195 : _gmtSec(0), _gmtNsec(0)
00196 {
00197 struct timespec ts;
00198 int gettimeStatus = clock_gettime( CLOCK_REALTIME, &ts );
00199
00200 assert( 0 == gettimeStatus );
00201 if ( 0 == gettimeStatus ) {
00202 _gmtSec = POSIXto1901( ts.tv_sec );
00203
00204
00205
00206
00207
00208
00209 }
00210 }
00211
00212 BdbTime::BdbTime( const BdbTime& t )
00213 : _gmtSec(t._gmtSec), _gmtNsec(t._gmtNsec)
00214 {
00215 }
00216
00217 BdbTime::BdbTime( d_ULong sec, d_ULong nsec )
00218 : _gmtSec(sec), _gmtNsec(nsec)
00219 {
00220 renormalizeNanoseconds();
00221 }
00222
00223 BdbTime::BdbTime( d_ULong year,
00224 d_ULong month,
00225 d_ULong day,
00226 d_ULong hour,
00227 d_ULong minute,
00228 d_ULong second,
00229 d_ULong nanosecond,
00230 BdbTime::Zone zone )
00231 : _gmtSec(0), _gmtNsec(nanosecond)
00232 {
00233
00234
00235
00236
00237 struct tm stm;
00238 stm.tm_year = year - 1900;
00239 stm.tm_mon = month - 1;
00240 stm.tm_mday = day;
00241 stm.tm_hour = hour;
00242 stm.tm_min = minute;
00243 stm.tm_sec = second;
00244
00245 stm.tm_isdst = -1;
00246
00247 d_ULong ut = 0;
00248 bool ok = TMto1901( stm, zone, ut );
00249
00250 if ( ok ) {
00251 _gmtSec = ut;
00252 renormalizeNanoseconds();
00253 }
00254 else {
00255
00256 _gmtNsec = 0;
00257 }
00258 }
00259
00260
00261 BdbTime::BdbTime( const std::string& sdate, const std::string& stime,
00262 Zone zone ) :
00263 _gmtSec( 0 ), _gmtNsec( 0 )
00264 {
00265
00266
00267 BdbTime t( 0, 0 );
00268
00269 bool status = parseTime( sdate, stime, zone, t );
00270
00271 if ( status ) {
00272 _gmtSec = t.getGmtSec();
00273 _gmtNsec = t.getGmtNsec();
00274 }
00275
00276 }
00277
00278
00279 BdbTime::BdbTime( const std::string& sdatetime, Zone bzone ) :
00280 _gmtSec( 0 ), _gmtNsec( 0 )
00281 {
00282
00283
00284 BdbTime t( 0, 0 );
00285
00286 bool status = parseTime( sdatetime, bzone, t );
00287
00288 if ( status ) {
00289 _gmtSec = t.getGmtSec();
00290 _gmtNsec = t.getGmtNsec();
00291 }
00292
00293 }
00294
00295 BdbTime::BdbTime( struct tm& stm, Zone zone )
00296 : _gmtSec(0), _gmtNsec(0)
00297 {
00298 d_ULong ut = 0;
00299 bool ok = TMto1901( stm, zone, ut );
00300
00301 if ( ok ) {
00302 _gmtSec = ut;
00303 }
00304
00305 }
00306
00307
00308 BdbTime::BdbTime( const struct timespec& ts )
00309
00310 : _gmtSec(POSIXto1901(ts.tv_sec)), _gmtNsec(ts.tv_nsec)
00311 {
00312 renormalizeNanoseconds();
00313 }
00314
00315 int
00316 BdbTime::timeSpec( struct timespec* ts ) const
00317 {
00318
00319
00320 const d_ULong maxSigned = 0x7fffffff;
00321 assert( BdbTimeConst::seconds_1901_to_1970 > maxSigned );
00322 const d_ULong minPOSIX = BdbTimeConst::seconds_1901_to_1970 - maxSigned;
00323
00324 if ( _gmtSec < minPOSIX ) {
00325 return -1;
00326 }
00327
00328
00329
00330
00331 if ( _gmtSec < BdbTimeConst::seconds_1901_to_1970 ) {
00332 d_ULong diff = BdbTimeConst::seconds_1901_to_1970 - _gmtSec;
00333 ts->tv_sec = -( (time_t) diff );
00334 }
00335 else {
00336 ts->tv_sec = (time_t) ( _gmtSec - BdbTimeConst::seconds_1901_to_1970 );
00337 }
00338 ts->tv_nsec = _gmtNsec;
00339
00340 return 0;
00341 }
00342
00343
00344 struct tm*
00345 BdbTime::tm( struct tm* stm, Zone zone ) const
00346 {
00347 if ( stm == 0 ) return 0;
00348
00349
00350
00351 const d_ULong maxSigned = 0x7fffffff;
00352 assert( BdbTimeConst::seconds_1901_to_1970 > maxSigned );
00353 const d_ULong minPOSIX = BdbTimeConst::seconds_1901_to_1970 - maxSigned;
00354
00355 const bool fix1901 = ( _gmtSec < minPOSIX );
00356
00357 d_ULong fixedSec = _gmtSec;
00358
00359
00360 if ( fix1901 ) fixedSec += fix1901_offset;
00361
00362
00363 time_t posixt = ( fixedSec >= BdbTimeConst::seconds_1901_to_1970
00364 ? ( fixedSec - BdbTimeConst::seconds_1901_to_1970 )
00365 : -(time_t)( BdbTimeConst::seconds_1901_to_1970 - fixedSec ) );
00366
00367 struct tm* stmout = 0;
00368 if ( zone == UTC ) {
00369 stmout = gmtime_r( &posixt, stm );
00370 }
00371 else {
00372 stmout = localtime_r( &posixt, stm );
00373 }
00374
00375
00376 assert( stmout == stm || stmout == 0 );
00377
00378 if ( fix1901 && stmout != 0 ) {
00379
00380 stmout->tm_year -= 6;
00381
00382
00383
00384
00385 assert( stmout->tm_year == 1
00386 || ( zone != UTC
00387 && stmout->tm_year == 0
00388 && stmout->tm_mon == 11 && stmout->tm_mday == 31 ) );
00389 }
00390
00391 return stmout;
00392 }
00393
00394
00395 std::string
00396 BdbTime::asString( const char* fmt, Zone zone ) const
00397 {
00398
00399
00400 struct tm stm;
00401 struct tm* pstm = tm( &stm, zone );
00402
00403 if ( pstm != &stm ) {
00404 return std::string( "(time conversion failed)" );
00405 }
00406
00407
00408
00409
00410 char buffer[1024];
00411 size_t nstr = strftime( buffer, sizeof(buffer), fmt, &stm );
00412
00413 if ( nstr >= sizeof(buffer) || ( nstr == 0 && strlen(fmt) != 0 ) ) {
00414 return std::string( "(time conversion failed)" );
00415 }
00416
00417 return std::string( buffer );
00418 }
00419
00420
00421
00422
00423
00424
00425 BdbTime& BdbTime::operator=( const BdbTime& t1 )
00426 {
00427 if ( this == &t1 ) return *this;
00428
00429 _gmtSec = t1._gmtSec;
00430 _gmtNsec = t1._gmtNsec;
00431
00432 return *this;
00433 }
00434
00435
00436 BdbDuration BdbTime::operator-( const BdbTime& t1 ) const
00437 {
00438
00439
00440 d_ULong t2Sec;
00441 d_ULong t2Nsec;
00442 d_ULong t1Sec;
00443 d_ULong t1Nsec;
00444
00445 if ( *this > t1 )
00446 {
00447 t2Sec = _gmtSec;
00448 t2Nsec = _gmtNsec;
00449 t1Sec = t1._gmtSec;
00450 t1Nsec = t1._gmtNsec;
00451 }
00452 else
00453 {
00454 t2Sec = t1._gmtSec;
00455 t2Nsec = t1._gmtNsec;
00456 t1Sec = _gmtSec;
00457 t1Nsec = _gmtNsec;
00458 }
00459
00460 if ( t2Nsec < t1Nsec )
00461 {
00462
00463 t2Nsec += BdbTimeConst::nsecInASec;
00464 t2Sec--;
00465 }
00466
00467 d_ULong sec = t2Sec - t1Sec;
00468 d_ULong nsec = t2Nsec - t1Nsec;
00469
00470 BdbDuration diff( sec, nsec );
00471
00472 return diff;
00473 }
00474
00475
00476 BdbTime BdbTime::operator-( const BdbDuration& d ) const
00477 {
00478 return BdbTime(*this) -= d;
00479 }
00480
00481
00482 BdbTime& BdbTime::operator-=( const BdbDuration& d )
00483 {
00484
00485 if ( ( _gmtSec < d.getSec() ) ||
00486 ( _gmtSec == d.getSec() && _gmtNsec < d.getNsec() ) ) {
00487 _gmtSec = 0;
00488 _gmtNsec = 0;
00489 }
00490 else {
00491 d_ULong tempSec = _gmtSec;
00492 d_ULong tempNsec = _gmtNsec;
00493
00494 if ( tempNsec < d.getNsec() ) {
00495
00496 tempNsec += BdbTimeConst::nsecInASec;
00497 tempSec--;
00498 }
00499
00500 _gmtSec = tempSec - d.getSec();
00501 _gmtNsec = tempNsec - d.getNsec();
00502 }
00503
00504 return *this;
00505 }
00506
00507
00508 BdbTime BdbTime::operator+( const BdbDuration& d ) const
00509 {
00510 return BdbTime(*this) += d;
00511 }
00512
00513
00514 BdbTime& BdbTime::operator+=( const BdbDuration& d )
00515 {
00516 d_ULong totalSec = _gmtSec + d.getSec();
00517 d_ULong totalNsec = _gmtNsec + d.getNsec();
00518
00519 if ( totalNsec >= BdbTimeConst::nsecInASec ) {
00520
00521 d_ULong extraSec = totalNsec / BdbTimeConst::nsecInASec;
00522 d_ULong remainNsec = totalNsec % BdbTimeConst::nsecInASec;
00523 totalSec += extraSec;
00524 totalNsec = remainNsec;
00525 }
00526
00527 _gmtSec = totalSec;
00528 _gmtNsec = totalNsec;
00529
00530 return *this;
00531 }
00532
00533
00534
00535
00536
00537 BdbTime
00538 BdbTime::now( )
00539 {
00540 struct timespec ts;
00541 int gettimeStatus = clock_gettime( CLOCK_REALTIME, &ts );
00542
00543 assert( 0 == gettimeStatus );
00544 if ( 0 != gettimeStatus ) {
00545 return BdbTime(0,0);
00546 }
00547
00548
00549 return BdbTime( POSIXto1901( ts.tv_sec ), ts.tv_nsec );
00550 }
00551
00552
00553 bool
00554 BdbTime::parseTime( const std::string& sdate, const std::string& stime,
00555 Zone zone,
00556 BdbTime& time )
00557 {
00558 bool status = false;
00559
00560 if ( strcasecmp( sdate.c_str(), "-Infinity" ) == 0 ) {
00561 time = minusInfinity;
00562 status = true;
00563 }
00564 else if ( strcasecmp( sdate.c_str(), "+Infinity" ) == 0 ) {
00565 time = plusInfinity;
00566 status = true;
00567 }
00568 else {
00569 struct tm stm;
00570 memset( &stm, 0, sizeof(stm) );
00571 stm.tm_isdst = -1;
00572
00573 BdbTimeInput::Status s;
00574 s = BdbTimeInput::parseDate( sdate.c_str(), stm );
00575 if ( s == BdbTimeInput::Success ) {
00576 s = BdbTimeInput::parseTime( stime.c_str(), stm );
00577 if ( s == BdbTimeInput::Success ) {
00578 d_ULong ut = 0;
00579 bool ok = TMto1901( stm, zone, ut );
00580 if ( ok ) {
00581 status = true;
00582 time = BdbTime( ut, 0 );
00583 }
00584 }
00585 }
00586 }
00587
00588 return status;
00589 }
00590
00591 bool
00592 BdbTime::parseTime( const std::string& sdatetime,
00593 Zone zone,
00594 BdbTime& time )
00595 {
00596 bool status = false;
00597
00598 if ( strcasecmp( sdatetime.c_str(), "-Infinity" ) == 0 ) {
00599 time = minusInfinity;
00600 status = true;
00601 }
00602 else if ( strcasecmp( sdatetime.c_str(), "+Infinity" ) == 0 ) {
00603 time = plusInfinity;
00604 status = true;
00605 }
00606 else {
00607 babar::String::Tokenize tokens( sdatetime );
00608
00609 std::string sdate = tokens();
00610 std::string stime = tokens();
00611
00612 status = parseTime( sdate, stime, zone, time );
00613 }
00614
00615 return status;
00616 }
00617
00618
00619
00620
00621
00622
00623
00624
00625 BdbTime operator+( const BdbDuration& d, const BdbTime& t1 )
00626 {
00627 return t1 + d;
00628 }
00629
00630 ostream & operator <<( ostream& os, const BdbTime& t )
00631 {
00632 if ( t == BdbTime::minusInfinity )
00633 os << "-Infinity";
00634 else if ( t == BdbTime::plusInfinity )
00635 os << "+Infinity";
00636 else
00637 {
00638 os << t.asString( "%c", BdbTime::Local ) << " (local time) "
00639 << t.getGmtNsec( ) << " ns";
00640 }
00641 return os;
00642 }