TTimeStamp.cxx

Go to the documentation of this file.
00001 // @(#)root/base:$Id: TTimeStamp.cxx 30229 2009-09-17 14:48:03Z rdm $
00002 // Author: R. Hatcher   30/9/2001
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //
00014 // The TTimeStamp encapsulates seconds and ns since EPOCH
00015 //
00016 // This extends (and isolates) struct timespec
00017 //    struct timespec
00018 //       {
00019 //          time_t   tv_sec;   /* seconds */
00020 //          long     tv_nsec;  /* nanoseconds */
00021 //       }
00022 //    time_t seconds is relative to Jan 1, 1970 00:00:00 UTC
00023 //
00024 // No accounting of leap seconds is made.
00025 //
00026 // Due to ROOT/CINT limitations TTimeStamp does not explicitly
00027 // hold a timespec struct; attempting to do so means the Streamer
00028 // must be hand written.  Instead we have chosen to simply contain
00029 // similar fields within the private area of this class.
00030 //
00031 // NOTE: the use of time_t (and its default implementation as a 32 int)
00032 //       implies overflow conditions occurs somewhere around
00033 //       Jan 18, 19:14:07, 2038.
00034 //       If this experiment is still going when it becomes significant
00035 //       someone will have to deal with it.
00036 //
00037 //////////////////////////////////////////////////////////////////////////
00038 
00039 #include "TTimeStamp.h"
00040 #include "TString.h"
00041 #include "TError.h"
00042 #include "Riostream.h"
00043 #ifdef R__WIN32
00044 #include "Windows4Root.h"
00045 #else
00046 #include <unistd.h>
00047 #include <sys/time.h>
00048 #endif
00049 #include "TVirtualMutex.h"
00050 
00051 ClassImp(TTimeStamp);
00052 
00053 
00054 TVirtualMutex *gTimeMutex = 0; // local mutex
00055 
00056 //______________________________________________________________________________
00057 ostream& operator<<(ostream& os, const TTimeStamp& ts)
00058 {
00059    // Write time stamp to ostream.
00060 
00061    if (os.good()) {
00062       if (os.tie()) os.tie()->flush(); // instead of opfx
00063       os << ts.AsString("c");
00064    }
00065    // instead of os.osfx()
00066    if (os.flags() & ios::unitbuf) os.flush();
00067    return os;
00068 }
00069 
00070 //______________________________________________________________________________
00071 TBuffer &operator>>(TBuffer &buf, TTimeStamp &ts)
00072 {
00073    // Read time stamp from TBuffer.
00074 
00075    ts.Streamer(buf);
00076    return buf;
00077 }
00078 
00079 //______________________________________________________________________________
00080 TBuffer &operator<<(TBuffer &buf, const TTimeStamp &ts)
00081 {
00082    // Write time stamp to TBuffer.
00083 
00084    ((TTimeStamp&)ts).Streamer(buf);
00085    return buf;
00086 }
00087 
00088 //______________________________________________________________________________
00089 TTimeStamp::TTimeStamp()
00090 {
00091    // Default ctor. Create a TTimeStamp and set it to the current time
00092    // (as best possible). The nanosecond part is faked so that subsequenct
00093    // calls simply add 1 to ensure that sequential calls are distinct
00094    // (and sortable).
00095 
00096    Set();
00097 }
00098 
00099 //______________________________________________________________________________
00100 TTimeStamp::TTimeStamp(UInt_t year, UInt_t month,
00101                        UInt_t day,  UInt_t hour,
00102                        UInt_t min,  UInt_t sec,
00103                        UInt_t nsec,
00104                        Bool_t isUTC, Int_t secOffset)
00105 {
00106    // Create a TTimeStamp and set it to the specified year, month,
00107    // day, time, hour, minute, second and nanosec.
00108    // If !isUTC then it is assumed to be the standard local time zone.
00109    //
00110    // If local time is PST then one can use
00111    //    TTimeStamp(year,month,day,hour,min,sec,nsec,kFALSE,0);
00112    // or
00113    //    Int_t secOffset = 8*60*60;
00114    //    TTimeStamp(year,month,day,hour,min,sec,nsec,kTRUE,8*60*60);
00115 
00116    Set(year, month, day, hour, min, sec, nsec, isUTC, secOffset);
00117 }
00118 
00119 //______________________________________________________________________________
00120 TTimeStamp::TTimeStamp(UInt_t date, UInt_t time,
00121                        UInt_t nsec,
00122                        Bool_t isUTC, Int_t secOffset)
00123 {
00124    // Create a TTimeStamp and set it to the specified date, time, nanosec.
00125    // If !isUTC then it is assumed to be the standard local time zone.
00126 
00127    Set(date, time, nsec, isUTC, secOffset);
00128 }
00129 
00130 //______________________________________________________________________________
00131 TTimeStamp::TTimeStamp(UInt_t tloc, Bool_t isUTC, Int_t secOffset, Bool_t dosDate)
00132 {
00133    // Create a TTimeStamp and set it to tloc which must be a time_t value
00134    // returned by time(). This value is the number of seconds since the EPOCH
00135    // (i.e. 00:00:00 on Jan 1m 1970). If dosDate is true then the input
00136    // is a dosDate value.
00137 
00138    Set(tloc, isUTC, secOffset, dosDate);
00139 }
00140 
00141 //______________________________________________________________________________
00142 const Char_t *TTimeStamp::AsString(Option_t *option) const
00143 {
00144    // Return the date & time as a string.
00145    //
00146    // Result is pointer to a statically allocated string.
00147    // User should copy this into their own buffer before calling
00148    // this method again.
00149    //
00150    // Option "l" returns it in local zone format
00151    // (can be applied to default or compact format).
00152    //
00153    // Default format is RFC822 compliant:
00154    //   "Mon, 02 Jan 2001 18:11:12 +0000 (GMT) +999999999 nsec"
00155    //   "Mon, 02 Jan 2001 10:11:12 -0800 (PST) +999999999 nsec"
00156    //
00157    // Option "c" compact is (almost) ISO 8601 compliant:
00158    //   "2001-01-02 18:11:12.9999999999Z"
00159    //   "2001-01-02 10:11:12.9999999999-0800"  if PST
00160    //      * uses "-" as date separator as specified in ISO 8601
00161    //      * uses "." rather than preferred "," for decimal separator
00162    //      * -HHMM is the difference between local and UTC (if behind, + if ahead).
00163    //   The "-HHMM" is replaced with "Z" if given as UTC.
00164    //   To be strictly conforming it should use "T" instead of the
00165    //   blank separating the date and time.
00166    //
00167    // Option "2" returns as {sec,nsec} integers.
00168    //
00169    // Option "s" returns "2001-01-02 18:11:12" with an implied UTC,
00170    // overrides "l" option.
00171    //
00172    // Internally uses a circular list of buffers to avoid problems
00173    // using AsString multiple times in a single statement.
00174 
00175    const Int_t nbuffers = 8;     // # of buffers
00176 
00177    static Char_t formatted[nbuffers][64];  // strftime fields substituted
00178    static Char_t formatted2[nbuffers][64]; // nanosec field substituted
00179 
00180    static Int_t ibuffer = nbuffers;
00181 
00182    R__LOCKGUARD2(gTimeMutex);
00183 
00184    ibuffer = (ibuffer+1)%nbuffers; // each call moves to next buffer
00185 
00186    TString opt = option;
00187    opt.ToLower();
00188 
00189    if (opt.Contains("2")) {
00190       // return string formatted as integer {sec,nsec}
00191       sprintf(formatted[ibuffer], "{%d,%d}", fSec, fNanoSec);
00192       return formatted[ibuffer];
00193    }
00194 
00195 #ifdef R__LINUX
00196    // under linux %z is the hour offset and %Z is the timezone name
00197    const Char_t *kRFC822   = "%a, %d %b %Y %H:%M:%S %z (%Z) +#9ld nsec";
00198    const Char_t *kISO8601  = "%Y-%m-%d %H:%M:%S.#9.9ld%z";
00199    const Char_t *kISO8601Z = "%Y-%m-%d %H:%M:%S.#9.9ldZ";
00200 #else
00201    // otherwise only %Z is guarenteed to be defind
00202    const Char_t *kRFC822   = "%a, %d %b %Y %H:%M:%S %Z +#9ld nsec";
00203    const Char_t *kISO8601  = "%Y-%m-%d %H:%M:%S.#9.9ld%Z";
00204    const Char_t *kISO8601Z = "%Y-%m-%d %H:%M:%S.#9.9ldZ";
00205 #endif
00206    const Char_t *kSQL = "%Y-%m-%d %H:%M:%S";
00207 
00208    Bool_t asLocal = opt.Contains("l");
00209    Bool_t asSQL   = opt.Contains("s");
00210    if (asSQL) asLocal = kFALSE;
00211 
00212    const Char_t *format = kRFC822;
00213    if (opt.Contains("c")) {
00214       format = kISO8601;
00215       if (!asLocal) format = kISO8601Z;
00216    }
00217    if (asSQL) format = kSQL;
00218 
00219    // get the components into a tm struct
00220    time_t seconds = (time_t) fSec;
00221 #ifdef _REENTRANT
00222    struct tm buf;
00223    struct tm *ptm = (asLocal) ? localtime_r(&seconds, &buf) : gmtime_r(&seconds, &buf);
00224 #else
00225    struct tm *ptm = (asLocal) ? localtime(&seconds) : gmtime(&seconds);
00226 #endif
00227 
00228    // format all but the nsec field
00229    // size_t length =
00230    strftime(formatted[ibuffer], sizeof(formatted[ibuffer]), format, ptm);
00231 
00232    if (asSQL) return formatted[ibuffer];
00233 
00234    // hack in the nsec part
00235    Char_t *ptr = strrchr(formatted[ibuffer], '#');
00236    if (ptr) *ptr = '%';    // substitute % for #
00237    sprintf(formatted2[ibuffer], formatted[ibuffer], fNanoSec);
00238 
00239    return formatted2[ibuffer];
00240 }
00241 
00242 //______________________________________________________________________________
00243 void TTimeStamp::Copy(TTimeStamp &ts) const
00244 {
00245    // Copy this to ts.
00246 
00247    ts.fSec     = fSec;
00248    ts.fNanoSec = fNanoSec;
00249 }
00250 
00251 //______________________________________________________________________________
00252 UInt_t TTimeStamp::GetDate(Bool_t inUTC, Int_t secOffset,
00253                            UInt_t *year, UInt_t *month, UInt_t *day) const
00254 {
00255    // Return date in form of 19971224 (i.e. 24/12/1997),
00256    // if non-zero pointers supplied for year, month, day fill those as well.
00257 
00258    time_t atime = fSec + secOffset;
00259 #ifdef _REENTRANT
00260    struct tm buf;
00261    struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
00262 #else
00263    struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
00264 #endif
00265 
00266    if (day)   *day   = ptm->tm_mday;
00267    if (month) *month = ptm->tm_mon + 1;
00268    if (year)  *year  = ptm->tm_year + 1900;
00269 
00270    return (1900+ptm->tm_year)*10000 + (1+ptm->tm_mon)*100 + ptm->tm_mday;
00271 }
00272 
00273 //______________________________________________________________________________
00274 UInt_t TTimeStamp::GetTime(Bool_t inUTC, Int_t secOffset,
00275                            UInt_t *hour, UInt_t *min, UInt_t *sec) const
00276 {
00277    // Return time in form of 123623 (i.e. 12:36:23),
00278    // if non-zero pointers supplied for hour, min, sec fill those as well.
00279 
00280    time_t atime = fSec + secOffset;
00281 #ifdef _REENTRANT
00282    struct tm buf;
00283    struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
00284 #else
00285    struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
00286 #endif
00287 
00288    if (hour) *hour = ptm->tm_hour;
00289    if (min)  *min  = ptm->tm_min;
00290    if (sec)  *sec  = ptm->tm_sec;
00291 
00292    return ptm->tm_hour*10000 + ptm->tm_min*100 + ptm->tm_sec;
00293 }
00294 
00295 //______________________________________________________________________________
00296 Int_t TTimeStamp::GetDayOfYear(Bool_t inUTC, Int_t secOffset) const
00297 {
00298    // Get the day of the year represented by this time stamp value.
00299    // Valid return values range between 1 and 366, where January 1 = 1.
00300 
00301    time_t atime = fSec + secOffset;
00302 #ifdef _REENTRANT
00303    struct tm buf;
00304    struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
00305 #else
00306    struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
00307 #endif
00308 
00309    Int_t day   = ptm->tm_mday;
00310    Int_t month = ptm->tm_mon + 1;
00311    Int_t year  = ptm->tm_year + 1900;
00312 
00313    return GetDayOfYear(day, month, year);
00314 }
00315 
00316 //______________________________________________________________________________
00317 Int_t TTimeStamp::GetDayOfWeek(Bool_t inUTC, Int_t secOffset) const
00318 {
00319    // Method is using Zeller's formula for calculating the day number.
00320    // Valid return values range between 1 and 7, where Monday = 1.
00321 
00322    time_t atime = fSec + secOffset;
00323 #ifdef _REENTRANT
00324    struct tm buf;
00325    struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
00326 #else
00327    struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
00328 #endif
00329 
00330    Int_t day   = ptm->tm_mday;
00331    Int_t month = ptm->tm_mon + 1;
00332    Int_t year  = ptm->tm_year + 1900;
00333 
00334    return GetDayOfWeek(day, month, year);
00335 }
00336 
00337 //______________________________________________________________________________
00338 Int_t TTimeStamp::GetMonth(Bool_t inUTC, Int_t secOffset) const
00339 {
00340    // Get the month of the year. Valid return values are between 1 and 12.
00341 
00342    time_t atime = fSec + secOffset;
00343 #ifdef _REENTRANT
00344    struct tm buf;
00345    struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
00346 #else
00347    struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
00348 #endif
00349 
00350    return ptm->tm_mon + 1;
00351 }
00352 
00353 //______________________________________________________________________________
00354 Int_t TTimeStamp::GetWeek(Bool_t inUTC, Int_t secOffset) const
00355 {
00356    // Get the week of the year. Valid week values are between 1 and 53.
00357    // The return value is the year*100+week (1 Jan may be in the last
00358    // week of the previous year so the year must be returned too).
00359 
00360    time_t atime = fSec + secOffset;
00361 #ifdef _REENTRANT
00362    struct tm buf;
00363    struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
00364 #else
00365    struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
00366 #endif
00367 
00368    Int_t day   = ptm->tm_mday;
00369    Int_t month = ptm->tm_mon + 1;
00370    Int_t year  = ptm->tm_year + 1900;
00371 
00372    return GetWeek(day, month, year);
00373 }
00374 
00375 //______________________________________________________________________________
00376 Bool_t TTimeStamp::IsLeapYear(Bool_t inUTC, Int_t secOffset) const
00377 {
00378    // Is the year a leap year.
00379    // The calendar year is 365 days long, unless the year is exactly divisible
00380    // by 4, in which case an extra day is added to February to make the year
00381    // 366 days long. If the year is the last year of a century, eg. 1700, 1800,
00382    // 1900, 2000, then it is only a leap year if it is exactly divisible by
00383    // 400. Therefore, 1900 wasn't a leap year but 2000 was. The reason for
00384    // these rules is to bring the average length of the calendar year into
00385    // line with the length of the Earth's orbit around the Sun, so that the
00386    // seasons always occur during the same months each year.
00387 
00388    time_t atime = fSec + secOffset;
00389 #ifdef _REENTRANT
00390    struct tm buf;
00391    struct tm *ptm = (inUTC) ? gmtime_r(&atime, &buf) : localtime_r(&atime, &buf);
00392 #else
00393    struct tm *ptm = (inUTC) ? gmtime(&atime) : localtime(&atime);
00394 #endif
00395 
00396    Int_t year = ptm->tm_year + 1900;
00397 
00398    return IsLeapYear(year);
00399 }
00400 
00401 //______________________________________________________________________________
00402 Int_t TTimeStamp::GetZoneOffset()
00403 {
00404    // Static method returning local (current) time zone offset from UTC.
00405    // This is the value in seconds one must add to the local time to arrive at
00406    // Coordinated Universal Time, so it is negative east of the Prime Meridian.
00407 
00408    // ?? should tzset (_tzset) be called?
00409 #ifndef R__WIN32
00410    tzset();
00411 #if defined(R__WINGCC)
00412    return _timezone;
00413 #else
00414 #if !defined(R__MACOSX) && !defined(R__FBSD) && !defined(R__OBSD)
00415    return  timezone;   // unix has extern long int
00416 #else
00417    time_t tp = 0;
00418    time(&tp);
00419 #ifdef _REENTRANT
00420    struct tm buf;
00421    return -localtime_r(&tp, &buf)->tm_gmtoff;
00422 #else
00423    return -localtime(&tp)->tm_gmtoff;
00424 #endif
00425 #endif
00426 #endif
00427 #else
00428    _tzset();
00429    return _timezone;   // Win32 prepends "_"
00430 #endif
00431 }
00432 
00433 //______________________________________________________________________________
00434 void TTimeStamp::Add(const TTimeStamp &offset)
00435 {
00436    // Add "offset" as a delta time.
00437 
00438    fSec     += offset.fSec;
00439    fNanoSec += offset.fNanoSec;
00440    NormalizeNanoSec();
00441 }
00442 
00443 //______________________________________________________________________________
00444 void TTimeStamp::Print(Option_t *option) const
00445 {
00446    // Print date and time.
00447 
00448    printf("Date/Time = %s\n", AsString(option));
00449 }
00450 
00451 //______________________________________________________________________________
00452 void TTimeStamp::Set()
00453 {
00454    // Set Date/Time to current time as reported by the system.
00455    // No accounting for nanoseconds with std ANSI functions,
00456    // ns part faked so that subsequent calls simply add 1 to it
00457    // this ensures that calls within the same second come back
00458    // distinct (and sortable). Time is since Jan 1, 1970.
00459 
00460 #ifdef R__WIN32
00461    ULARGE_INTEGER time;
00462    GetSystemTimeAsFileTime((FILETIME *)&time);
00463    // NT keeps time in FILETIME format which is 100ns ticks since
00464    // Jan 1, 1601. TTimeStamp uses time in 100ns ticks since Jan 1, 1970,
00465    // the difference is 134774 days.
00466    fNanoSec = Int_t((time.QuadPart * (unsigned __int64) 100) %
00467                     (unsigned __int64) 1000000000);
00468    time.QuadPart -=
00469             (unsigned __int64) (1000*1000*10)       // seconds
00470           * (unsigned __int64) (60 * 60 * 24)       // days
00471           * (unsigned __int64) (134774);            // # of days
00472 
00473    fSec     = Int_t(time.QuadPart/(unsigned __int64) (1000*1000*10));
00474 #else
00475    struct timeval tp;
00476    gettimeofday(&tp, 0);
00477    fSec     = tp.tv_sec;
00478    fNanoSec = tp.tv_usec*1000;
00479 #endif
00480 
00481    static Int_t sec = 0, nsec = 0, fake_ns = 0;
00482 
00483    R__LOCKGUARD2(gTimeMutex);
00484 
00485    if (fSec == sec && fNanoSec == nsec)
00486       fNanoSec += ++fake_ns;
00487    else {
00488       fake_ns = 0;
00489       sec     = fSec;
00490       nsec    = fNanoSec;
00491    }
00492 }
00493 
00494 //______________________________________________________________________________
00495 void TTimeStamp::Set(Int_t year, Int_t month, Int_t day,
00496                      Int_t hour, Int_t min, Int_t sec,
00497                      Int_t nsec, Bool_t isUTC, Int_t secOffset)
00498 {
00499    // Set Date/Time from components.
00500    //
00501    // Month & day both use normal 1..12 and 1..31 counting,
00502    // hours, min, sec run from 0 to 23, 59, 59 respectively,
00503    // secOffset provides method for adjusting for alternative timezones
00504    //
00505    // "year"  |    0    1 ... 37 | 38...69   |   70 .. 100  101 ..  137
00506    // true    | 2000 2001   2037 | undefined | 1970   2000 2001 .. 2037
00507    //
00508    // "year"  | 138...1969 | 1970 .. 2037 | ...
00509    // true    | undefined  | 1970 .. 2037 | undefined
00510    //
00511 
00512    // deal with special formats of year
00513    if (year <= 37)                year += 2000;
00514    if (year >= 70 && year <= 137) year += 1900;
00515    // tm.tm_year is years since 1900
00516    if (year >= 1900)              year -= 1900;
00517 
00518    struct tm tmstruct;
00519    tmstruct.tm_year  = year;    // years since 1900
00520    tmstruct.tm_mon   = month-1; // months since Jan [0,11]
00521    tmstruct.tm_mday  = day;     // day of the month [1,31]
00522    tmstruct.tm_hour  = hour;    // hours since midnight [0,23]
00523    tmstruct.tm_min   = min;     // minutes after the hour [0,59]
00524    tmstruct.tm_sec   = sec + secOffset;  // seconds after the minute [0,59]
00525    tmstruct.tm_isdst = -1;     // let "mktime" determine DST setting
00526 
00527    const time_t bad_time_t = (time_t) -1;
00528    // convert tm struct to time_t, if values are given in UTC then
00529    // no standard routine exists and we'll have to use our homegrown routine,
00530    // if values are given in local time then use "mktime"
00531    // which also normalizes the tm struct as a byproduct
00532    time_t utc_sec = (isUTC) ? MktimeFromUTC(&tmstruct) : mktime(&tmstruct);
00533 
00534    if (utc_sec == bad_time_t)
00535       Error("TTimeStamp::Set","mktime returned -1");
00536 
00537    fSec     = utc_sec;
00538    fNanoSec = nsec;
00539 
00540    NormalizeNanoSec();
00541 }
00542 
00543 //______________________________________________________________________________
00544 void TTimeStamp::Set(Int_t date, Int_t time, Int_t nsec,
00545                      Bool_t isUTC, Int_t secOffset)
00546 {
00547    // Set date/time from integers of the form [yy]YYMMDD and HHMMSS,
00548    // assume UTC (UTC) components:
00549    //
00550    //  MM: 01=January .. 12=December
00551    //  DD: 01 .. 31
00552    //
00553    //  HH: 00=midnight .. 23
00554    //  MM: 00 .. 59
00555    //  SS: 00 .. 69
00556    //
00557    // Date must be in format 980418 or 19980418
00558    //                       1001127 or 20001127  (i.e. year 100 = 2000),
00559    // time must be in format 224512 (second precision),
00560    // date must be >= 700101.
00561 
00562    Int_t year  = date/10000;
00563    Int_t month = (date-year*10000)/100;
00564    Int_t day   = date%100;
00565 
00566    // protect against odd attempts at time offsets
00567    const Int_t oneday = 240000;
00568    while (time < 0) {
00569       time += oneday;
00570       day  -= 1;
00571    }
00572    while (time > oneday) {
00573       time -= oneday;
00574       day  += 1;
00575    }
00576    Int_t hour  = time/10000;
00577    Int_t min   = (time-hour*10000)/100;
00578    Int_t sec   = time%100;
00579 
00580    Set(year, month, day, hour, min, sec, nsec, isUTC, secOffset);
00581 }
00582 
00583 //______________________________________________________________________________
00584 void TTimeStamp::Set(UInt_t tloc, Bool_t isUTC, Int_t secOffset, Bool_t dosDate)
00585 {
00586    // The input arg is a time_t value returned by time() or a value
00587    // returned by Convert(). This value is the number of seconds since
00588    // the EPOCH (i.e. 00:00:00 on Jan 1m 1970). If dosDate is true then
00589    // the input is a dosDate value.
00590 
00591    struct tm localtm;
00592    memset (&localtm, 0, sizeof (localtm));
00593 
00594    if (dosDate) {
00595       localtm.tm_year  = ((tloc >> 25) & 0x7f) + 80;
00596       localtm.tm_mon   = ((tloc >> 21) & 0xf);
00597       localtm.tm_mday  = (tloc >> 16) & 0x1f;
00598       localtm.tm_hour  = (tloc >> 11) & 0x1f;
00599       localtm.tm_min   = (tloc >> 5) & 0x3f;
00600       localtm.tm_sec   = (tloc & 0x1f) * 2 + secOffset;
00601       localtm.tm_isdst = -1;
00602    } else {
00603       time_t t = (time_t) tloc;
00604 #ifdef _REENTRANT
00605       struct tm tpa;
00606       struct tm *tp = localtime_r(&t, &tpa);
00607 #else
00608       struct tm *tp = localtime(&t);
00609 #endif
00610       localtm.tm_year  = tp->tm_year;
00611       localtm.tm_mon   = tp->tm_mon;
00612       localtm.tm_mday  = tp->tm_mday;
00613       localtm.tm_hour  = tp->tm_hour;
00614       localtm.tm_min   = tp->tm_min;
00615       localtm.tm_sec   = tp->tm_sec + secOffset;
00616       localtm.tm_isdst = -1;
00617    }
00618 
00619    const time_t bad_time_t = (time_t) -1;
00620    // convert tm struct to time_t, if values are given in UTC then
00621    // no standard routine exists and we'll have to use our homegrown routine,
00622    // if values are given in local time then use "mktime"
00623    // which also normalizes the tm struct as a byproduct
00624    time_t utc_sec = (isUTC && dosDate) ? MktimeFromUTC(&localtm) : mktime(&localtm);
00625 
00626    if (utc_sec == bad_time_t)
00627       Error("TTimeStamp::Set","mktime returned -1");
00628 
00629    fSec     = utc_sec;
00630    fNanoSec = 0;  //nsec;
00631 
00632    NormalizeNanoSec();
00633 }
00634 
00635 //______________________________________________________________________________
00636 void TTimeStamp::NormalizeNanoSec()
00637 {
00638    // Ensure that the fNanoSec field is in range [0,99999999].
00639 
00640    const Int_t kNsPerSec = 1000000000;
00641    // deal with negative values
00642    while (fNanoSec < 0) {
00643       fNanoSec += kNsPerSec;
00644       fSec -= 1;
00645    }
00646 
00647    // deal with values inf fNanoSec greater than one sec
00648    while (fNanoSec >= kNsPerSec) {
00649       fNanoSec -= kNsPerSec;
00650       fSec += 1;
00651    }
00652 }
00653 
00654 //______________________________________________________________________________
00655 time_t TTimeStamp::MktimeFromUTC(tm_t *tmstruct)
00656 {
00657    // Equivalent of standard routine "mktime" but
00658    // using the assumption that tm struct is filled with UTC, not local, time.
00659    //
00660    // This version *ISN'T* configured to handle every possible
00661    // weirdness of out-of-range values in the case of normalizing
00662    // the tm struct.
00663    //
00664    // This version *DOESN'T* correctly handle values that can't be
00665    // fit into a time_t (i.e. beyond year 2038-01-18 19:14:07, or
00666    // before the start of Epoch).
00667 
00668    Int_t daysInMonth[] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00669    Int_t year = tmstruct->tm_year + 1900;
00670    daysInMonth[1] = IsLeapYear(year) ? 29 : 28;
00671 
00672    // fill in tmstruct->tm_yday
00673 
00674    Int_t &ref_tm_mon = tmstruct->tm_mon;
00675    Int_t &ref_tm_mday = tmstruct->tm_mday;
00676    // count days in months past
00677    tmstruct->tm_yday = 0;
00678    for (Int_t imonth = 0; imonth < ref_tm_mon; imonth++) {
00679       tmstruct->tm_yday += daysInMonth[imonth];
00680    }
00681    tmstruct->tm_yday += ref_tm_mday - 1;  // day [1-31] but yday [0-365]
00682 
00683    // adjust if day in this month is more than the month has
00684    while (ref_tm_mday > daysInMonth[ref_tm_mon]) {
00685       ref_tm_mday -= daysInMonth[ref_tm_mon];
00686       ref_tm_mon++;
00687    }
00688 
00689    // *should* calculate tm_wday (0-6) here ...
00690 
00691    // UTC is never DST
00692    tmstruct->tm_isdst = 0;
00693 
00694    // Calculate seconds since the Epoch based on formula in
00695    // POSIX  IEEEE Std 1003.1b-1993 pg 22
00696 
00697    Int_t utc_sec = tmstruct->tm_sec +
00698                    tmstruct->tm_min*60 +
00699                    tmstruct->tm_hour*3600 +
00700                    tmstruct->tm_yday*86400 +
00701                    (tmstruct->tm_year-70)*31536000 +
00702                    ((tmstruct->tm_year-69)/4)*86400;
00703 
00704    return utc_sec;
00705 }
00706 
00707 //______________________________________________________________________________
00708 Int_t TTimeStamp::GetDayOfYear(Int_t day, Int_t month, Int_t year)
00709 {
00710    // Get the day of the year represented by day, month and year.
00711    // Valid return values range between 1 and 366, where January 1 = 1.
00712 
00713    Int_t dayOfYear = 0;
00714    Int_t daysInMonth[] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00715    daysInMonth[1] = IsLeapYear(year) ? 29 : 28;
00716 
00717    for (Int_t i = 0; i < (month - 1); i++)
00718       dayOfYear += daysInMonth[i];
00719    dayOfYear += day;
00720 
00721    return dayOfYear;
00722 }
00723 
00724 //______________________________________________________________________________
00725 Int_t TTimeStamp::GetDayOfWeek(Int_t day, Int_t month, Int_t year)
00726 {
00727    // Method is using Zeller's formula for calculating the day number.
00728    // Valid return values range between 1 and 7, where Monday = 1.
00729 
00730    Int_t dayno;
00731 
00732    if (month < 3) {
00733       year--;
00734       month += 12;
00735    }
00736 
00737    dayno = 1 + day + 2*month + 3*(month + 1)/5 + year + year/4 - year/100 + year/400;
00738    dayno %= 7;
00739 
00740    // make monday first day of week
00741    return ((dayno == 0) ? 7 : dayno);
00742 }
00743 
00744 //______________________________________________________________________________
00745 Int_t TTimeStamp::GetWeek(Int_t day, Int_t month, Int_t year)
00746 {
00747    // Get the week of the year. Valid week values are between 1 and 53.
00748    // The return value is the year*100+week (1 Jan may be in the last
00749    // week of the previous year so the year must be returned too).
00750 
00751    Int_t dayOfYear = GetDayOfYear(day, month, year);
00752    Int_t dayJan1st = GetDayOfWeek(1, 1, year);
00753    Int_t week = (dayOfYear + dayJan1st - 2) / 7 + 1;
00754 
00755    if (dayJan1st > 4)
00756       week--;
00757 
00758    if (week == 53) {
00759       Int_t dayNextJan1st = GetDayOfWeek(1, 1, year + 1);
00760       if (dayNextJan1st > 1 && dayNextJan1st < 5) {
00761          year++;
00762          week = 1;
00763       }
00764    } else if (week == 0) {
00765       Int_t dayPrevJan1st = GetDayOfWeek(1, 1, year - 1);
00766       week = (dayPrevJan1st < 5 && dayJan1st > 4) ? 53 : 52;
00767       year--;
00768    }
00769    return year * 100 + week;
00770 }
00771 
00772 //______________________________________________________________________________
00773 Bool_t TTimeStamp::IsLeapYear(Int_t year)
00774 {
00775    // Is the given year a leap year.
00776    // The calendar year is 365 days long, unless the year is exactly divisible
00777    // by 4, in which case an extra day is added to February to make the year
00778    // 366 days long. If the year is the last year of a century, eg. 1700, 1800,
00779    // 1900, 2000, then it is only a leap year if it is exactly divisible by
00780    // 400. Therefore, 1900 wasn't a leap year but 2000 was. The reason for
00781    // these rules is to bring the average length of the calendar year into
00782    // line with the length of the Earth's orbit around the Sun, so that the
00783    // seasons always occur during the same months each year.
00784 
00785    return (year % 4 == 0) && !((year % 100 == 0) && (year % 400 > 0));
00786 }
00787 
00788 //______________________________________________________________________________
00789 void TTimeStamp::DumpTMStruct(const tm_t &tmstruct)
00790 {
00791    // Print out the "tm" structure:
00792    // tmstruct.tm_year = year;    // years since 1900
00793    // tmstruct.tm_mon  = month-1; // months since Jan [0,11]
00794    // tmstruct.tm_mday = day;     // day of the month [1,31]
00795    // tmstruct.tm_hour = hour;    // hours since midnight [0,23]
00796    // tmstruct.tm_min  = min;     // minutes after the hour [0,59]
00797    // tmstruct.tm_sec  = sec;     // seconds after the minute [0,59]
00798    // tmstruct.tm_wday            // day of week [0,6]
00799    // tmstruct.tm_yday            // days in year [0,365]
00800    // tmstruct.tm_isdst           // DST [-1/0/1]  (unknown,false,true)
00801 
00802    printf(" tm { year %4d, mon   %2d, day   %2d,\n",
00803           tmstruct.tm_year,
00804           tmstruct.tm_mon,
00805           tmstruct.tm_mday);
00806    printf("      hour   %2d, min   %2d, sec   %2d,\n",
00807           tmstruct.tm_hour,
00808           tmstruct.tm_min,
00809           tmstruct.tm_sec);
00810    printf("      wday   %2d, yday %3d, isdst %2d",
00811           tmstruct.tm_wday,
00812           tmstruct.tm_yday,
00813           tmstruct.tm_isdst);
00814 #if (defined(linux) && !defined(R__WINGCC)) || defined(R__MACOSX)
00815    printf(",\n      tm_gmtoff %6ld, tm_zone \"%s\"",
00816 #if defined(__USE_BSD) || defined(R__MACOSX)
00817    tmstruct.tm_gmtoff, tmstruct.tm_zone);
00818 #else
00819    tmstruct.__tm_gmtoff, tmstruct.__tm_zone);
00820 #endif
00821 #endif
00822    printf(" }\n");
00823 }

Generated on Tue Jul 5 14:11:24 2011 for ROOT_528-00b_version by  doxygen 1.5.1