Re: timestamps

From: Fons Rademakers <Fons.Rademakers_at_cern.ch>
Date: Mon, 3 Mar 2008 14:19:33 +0100


Hi Robert,

   I think I've fixed the problem after your analysis. I've left for the time being the special !isUTC case only for dosDate. This at least sanitizes the 99% of non-dosDate cases.

Also applied the DumpTMStruct() fix for Mac OS X.

Cheers, Fons.

Robert Hatcher wrote:
> As the original author of TTimeStamp let me give this a try:
> (I hope this makes it to "roottalk" as well as directly ... last attempt
> to send to "roottalk" fell into a black hole).
>
> On Feb 15, 2008, at 4:51 PM, Chiara Zampolli wrote:
>

>>    I have some (probably trivial) doubts concerning how to retrieve 
>> timestamps from a given local time. My local time is CET, so what I do 
>> to get the timestamp according to GMT is:

>
> CET = UTC + 1 hour -- just checking.
>
>> [pcalishuttle01] /home/shuttle/Chiara > date
>> Fri Feb 15 23:28:16 CET 2008
>> [pcalishuttle01] /home/shuttle/Chiara > date +%s
>> 1203114501

>
> A check of the man page of "date" says to check strftime(3):
> %s is replaced by the number of seconds since the Epoch,
> UTC (see mktime(3)).
>
>> [pcalishuttle01] /home/shuttle/Chiara > root -l
>> *** DISPLAY not set, setting it to pcalice134.cern.ch:0.0
>> root [0] TTimeStamp tmp(2008,2,15,23,28,00,0,kFALSE)

>
> The constuctor you used here is:
>
> // construction from bits and pieces
> TTimeStamp(UInt_t year, UInt_t month,
> UInt_t day, UInt_t hour,
> UInt_t min, UInt_t sec,
> UInt_t nsec = 0, Bool_t isUTC = kTRUE, Int_t secOffset = 0);
>
> And since you're setting from the components given in local time (CET)
> then supplying kFALSE is the correct thing to do. You did drop a
> few seconds by typing "00" for the seconds field. Internally
> TTimeStamp fSec values are supposed to be time_t values (and thus in UTC),
> so indeed GetSec() should give the same value as "date +%s" in this case.
>
>> root [1] tmp.GetSec()
>> (const time_t)(1203114480)
>>
>> The slight difference between 1203114501 and 1203114480 should be of 
>> course due to the delay in time while typing...

>
> Yes, that would be 21 seconds ... between your two "date" commands,
> modulo the typo (which would take your typing down to 5 seconds).
>
>> BTW, I'm not completely sure that the timestamp I get in this way, 
>> specifying kFALSE which means "this is my local time" corresponds to 
>> the GMT time, also because I'm comparing it with the return of date, 
>> but I'm not sure that "date" returns the timestamp corresponding to GMT.

>
> Huh? I'm not sure I can parse that.
> $ date <== time in local zone (for you CET as shown)
> $ date +%s <== sec since epoch UTC
> [] TTimeStamp::GetSec() <== sec since epoch UTC
>
>> Moreover:
>>
>> root[2] TTimeStamp tmp1(1203114480)

>
> I'm not sure this is the ctor you think it is ....
> There was originally no ctor for a single int -- I think the one
> you're trying for is the the one that looks like:
> // construction from time_t and separate nsec
> TTimeStamp(time_t t, Int_t nsec) :
> fSec(t), fNanoSec(nsec) { NormalizeNanoSec(); }
>
> This is because time_t values are meant to be "seconds since epoch UTC".
>
>> root [3] tmp1.Print()
>> Date/Time = Fri, 15 Feb 2008 23:28:00 +0000 (GMT) +        0 nsec

>
> When I supply a second argument of zero nanoseconds I get:
> root [0] TTimeStamp tmp1(1203114480,0);
> root [1] tmp1.Print();
> Date/Time = Fri, 15 Feb 2008 22:28:00 UTC + 0 nsec
>
> Which is what I think you expect.
>
> I think what you're calling is:
>
> // compatability with time() and DOS date
> TTimeStamp(UInt_t tloc, Bool_t isUTC = kTRUE, Int_t secOffset = 0,
> Bool_t dosDate = kFALSE);
>
> This ctor was added after I turned the code over to the ROOT team.
> Looking at the interface, I would have thought that one would get
> the same result in the two cases.
>
> Looking at the code though... at least for the isUTC=true case, it's
> jumping through lots of unnecessary hoops. Breaking what the code
> does down, I see the steps:
>
> root [0] time_t t = 1203114480;
> root [1] struct tm *tp = localtime(&t);
> root [2] TTimeStamp::MktimeFromUTC(tp)
> (time_t)(1203092880)
>
> But this last step is illogical. You passed in a UTC time_t value, it
> converts it into a "struct tm" via localtime() which breaks things
> out into pieces. And then it uses, because of the defaulted 2nd
> argument isUTC=kTRUE, TTimeStamp::MktimeFromUTC()
> to attempt to get back at UTC time_t ... but that doesn't make any
> sense since localtime has filled the tm struct with local info and
> thus we should be using mktime() to convert back to UTC time_t.
> Using a MktimeFromUTC() on a local tm struct violates the premise:
>
> time_t TTimeStamp::MktimeFromUTC(tm_t *tmstruct)
> {
> // Equivalent of standard routine "mktime" but
> // using the assumption that tm struct is filled with UTC,
> // not local, time.
> [...]
> }
>
> It should be calling:
> root [3] mktime(tp)
> (const time_t)(1203114480)
>
> Getting one back to where you started.
>
> I suspect that it doesn't do the right thing in the case of dosDate=kFALSE
> no matter what isUTC is. For if isUTC is kFALSE then calling
> localtime() on a time that is not a true time_t (UTC) will apply timezone
> offsets to something that already has an offset. Neither localtime()
> not gmtime() expects to take an int that is "local time" so I'm not
> sure how to fix this case.
>
> I think it may do the right thing for dosDate=kTRUE.
>
> It's late and I'm not sure I can write this code correctly at the
> moment. In the mean time I'd suggest if you have a true time_t
> (UTC) that you use the 2 arg ctor.
>
>> as if it was 23:28 in Greenwich (GMT!!!) and not here in Geneva (CET 
>> time zone)!!, and
>>
>> root[4] TTimeStamp tmp2(2008,2,15,23,28,00,0,kTRUE, -3600)
>> root [5] tmp2.GetSec()
>> (const time_t)(1203114480)
>>
>> Probably what I would better do is:
>>
>> root [0] TTimeStamp tmp2(2008,2,15,23,28,00,0,kFALSE)      root [1] 
>> tmp2.GetSec()+TTimeStamp::GetZoneOffset()
>> (const time_t)(1203110880)
>>
>> which is 3600 s = 1 h less then the timestamp I got before, and so 
>> could be related to the Greenwich time:
>>
>> root [2] TTimeStamp tmp3(1203110880)
>> root [3] tmp3.Print()
>> Date/Time = Fri, 15 Feb 2008 22:28:00 +0000 (GMT) +        0 nsec

>
> Better to use the intended ctor that takes two args: time_t and nanosec.
> It looks to me like the single int + defaults ctor is, ah, broken.
>
>> So, as far as I have understood, the timestamps should be universal, 
>> in the sense that each of them corresponds to only one time in GMT, 
>> but to many times if we consider many local time zones. But I'm 
>> getting confused in what I should set, kTRUE/kFALSE, an offset or not, 
>> and in how to retrieve the correct timestamp. In other words, if I'm 
>> looking for something that was stored with its timestamp, which is its 
>> identified and was computed according to GMT, but I'm starting from a 
>> CET time, what should I do?
>>
>> Thanks in advance for any clarification.
>> Regards,
>>       chiara

>
> To the ROOT team I think you can also change DumpTMStruct() to
> handle MACOSX a bit more:
>
> #if (defined(linux) && !defined(R__WINGCC) ) || defined(R__MACOSX)
> printf(",\n tm_gmtoff %7ld, tm_zone \"%s\"",
> #if defined(__USE_BSD) || defined(R__MACOSX)
> tmstruct.tm_gmtoff,tmstruct.tm_zone);
> #else
> tmstruct.__tm_gmtoff,tmstruct.__tm_zone);
> #endif
> #endif
>
> (When I wrote it I didn't have Mac to try this on).
>
> -robert
>
> Robert W. Hatcher | rhatcher_at_fnal.gov 630-840-3102
> FNAL CD/REX (MINOS) | MS 220, PO Box 500, Batavia IL 60510
>
>
>
>
-- 
Org:    CERN, European Laboratory for Particle Physics.
Mail:   1211 Geneve 23, Switzerland
E-Mail: Fons.Rademakers_at_cern.ch              Phone: +41 22 7679248
WWW:    http://fons.rademakers.org           Fax:   +41 22 7669640
Received on Mon Mar 03 2008 - 14:18:10 CET

This archive was generated by hypermail 2.2.0 : Mon Mar 03 2008 - 17:50:01 CET