source: trunk/Mars/mbase/MTime.cc @ 19273

Last change on this file since 19273 was 18592, checked in by tbretz, 3 years ago
Newer compilers need an explicit cast here.
File size: 32.1 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18!   Author(s): Thomas Bretz  12/2000 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20!   Copyright: MAGIC Software Development, 2000-2008
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MTime
28//
29// A generalized MARS time stamp.
30//
31//
32// We do not use floating point values here, because of several reasons:
33//  - having the times stored in integers only is more accurate and
34//    more reliable in comparison conditions
35//  - storing only integers gives similar bit-pattern for similar times
36//    which makes compression (eg gzip algorithm in TFile) more
37//    successfull
38//
39// Note, that there are many conversion function converting the day time
40// into a readable string. Also a direct interface to SQL time strings
41// is available.
42//
43// If you are using MTime containers as axis lables in root histograms
44// use GetAxisTime(). Make sure that you use the correct TimeFormat
45// on your TAxis (see GetAxisTime())
46//
47//
48// WARNING: Be carefull changing this class. It is also used in the
49//          MAGIC drive software cosy as VERY IMPORTANT stuff!
50//
51// Remarke: If you encounter strange behaviour, check the casting.
52//          Note, that on Linux machines ULong_t and UInt_t is the same.
53//
54//
55// Version 1:
56// ----------
57//  - first version
58//
59// Version 2:
60// ----------
61//  - removed fTimeStamp[2]
62//
63// Version 3:
64// ----------
65//  - removed fDurtaion - we may put it back when it is needed
66//  - complete rewrite of the data members (old ones completely replaced)
67//
68/////////////////////////////////////////////////////////////////////////////
69#include "MTime.h"
70
71#include <iomanip>
72
73#ifndef __USE_XOPEN
74#define __USE_XOPEN // on some systems needed for strptime
75#endif
76
77#include <time.h>     // struct tm
78#include <sys/time.h> // struct timeval
79
80#include <TTime.h>
81
82#include "MLog.h"
83#include "MLogManip.h"
84
85#include "MAstro.h"
86#include "MString.h"
87
88ClassImp(MTime);
89
90using namespace std;
91
92const UInt_t MTime::kHour   = 3600000;         // [ms] one hour
93const UInt_t MTime::kDay    = MTime::kHour*24; // [ms] one day
94const UInt_t MTime::kDaySec = 3600*24;         // [s] one day
95
96// --------------------------------------------------------------------------
97//
98// Constructor. Calls SetMjd(d) for d>0 in all other cases the time
99// is set to the current UTC time.
100//
101MTime::MTime(Double_t d)
102{
103    Init(0, 0);
104    if (d<=0)
105        Now();
106    else
107        d>2400000 ? SetJD(d) : SetMjd(d);
108}
109
110// --------------------------------------------------------------------------
111//
112// Constructor. Calls Set(y, m, d, h, min, s, ms, ns).
113// To check validity test for (*this)==MTime()
114//
115MTime::MTime(UShort_t y, Byte_t m, Byte_t d, Byte_t h, Byte_t min, Byte_t s, UShort_t ms, UInt_t ns)
116{
117    Set(y, m, d, h, min, s, ms, ns);
118}
119
120// --------------------------------------------------------------------------
121//
122// Return date as year(y), month(m), day(d)
123//
124void MTime::GetDate(UShort_t &y, Byte_t &m, Byte_t &d) const
125{
126    MAstro::Mjd2Ymd((Long_t)fTime<0?fMjd-1:fMjd, y, m, d);
127}
128
129// --------------------------------------------------------------------------
130//
131// Return date as year(y), month(m), day(d). If the time is afternoon
132// (>=13:00:00) the date of the next day is returned.
133//
134void MTime::GetDateOfSunrise(UShort_t &y, Byte_t &m, Byte_t &d) const
135{
136    MAstro::Mjd2Ymd(fMjd, y, m, d);
137}
138
139// --------------------------------------------------------------------------
140//
141// Return date as year(y), month(m), day(d). If the time is afternoon
142// (>=13:00:00) the date of the next day is returned.
143//
144MTime MTime::GetDateOfSunrise() const
145{
146    UShort_t y;
147    Byte_t m;
148    Byte_t d;
149
150    MAstro::Mjd2Ymd(fMjd, y, m, d);
151
152    return MTime(y, m, d);
153}
154
155// --------------------------------------------------------------------------
156//
157// GetMoonPhase - calculate phase of moon as a fraction:
158//  Returns -1 if calculation failed
159//
160//  see MAstro::GetMoonPhase
161//
162Double_t MTime::GetMoonPhase() const
163{
164    return MAstro::GetMoonPhase(GetMjd());
165}
166
167// --------------------------------------------------------------------------
168//
169// Calculate the Period to which the time belongs to. The Period is defined
170// as the number of synodic months ellapsed since the first full moon
171// after Jan 1st 1980 (which was @ MJD=44240.37917)
172//
173//   see MAstro::GetMoonPeriod
174//
175Double_t MTime::GetMoonPeriod() const
176{
177    return MAstro::GetMoonPeriod(GetMjd());
178}
179
180// --------------------------------------------------------------------------
181//
182// Set the time corresponding to the moon period.
183//
184//   see MTime::GetMoonPeriod and MAstro::GetMoonPeriod
185//
186void MTime::SetMoonPeriod(Double_t p)
187{
188    SetMjd(MAstro::GetMoonPeriodMjd(p));
189}
190
191// --------------------------------------------------------------------------
192//
193// To get the moon period as defined for MAGIC observation we take the
194// nearest integer mjd, eg:
195//   53257.8 --> 53258
196//   53258.3 --> 53258
197 // Which is the time between 13h and 12:59h of the following day. To
198// this day-period we assign the moon-period at midnight. To get
199// the MAGIC definition we now substract 284.
200//
201// For MAGIC observation period do eg:
202//   GetMagicPeriod(53257.91042)
203// or
204//   MTime t;
205//   t.SetMjd(53257.91042);
206//   GetMagicPeriod(t.GetMjd());
207// or
208//   MTime t;
209//   t.Set(2004, 1, 1, 12, 32, 11);
210//   GetMagicPeriod(t.GetMjd());
211//
212// To get a floating point magic period use
213//   GetMoonPeriod()-284
214//
215//  see MAstro::GetMagicPeriod
216//
217Int_t MTime::GetMagicPeriod() const
218{
219    return MAstro::GetMagicPeriod(GetMjd());
220}
221
222// --------------------------------------------------------------------------
223//
224// Set the start time (noon) of a MAGIC period
225//
226//   see MTime::GetMagicPeriod and MAstro::GetMagicPeriod
227//
228void MTime::SetMagicPeriodStart(Int_t p)
229{
230    SetMjd(MAstro::GetMagicPeriodStart(p));
231}
232
233UInt_t MTime::GetNightAsInt() const
234{
235    UShort_t y;
236    Byte_t m, d;
237
238    MAstro::Mjd2Ymd(fMjd+0.5, y, m, d);
239
240    return UInt_t(y)*10000 + UInt_t(m)*100 + d;
241}
242
243// --------------------------------------------------------------------------
244//
245// Return the time in the range [0h, 24h) = [0h0m0.000s - 23h59m59.999s]
246//
247void MTime::GetTime(Byte_t &h, Byte_t &m, Byte_t &s, UShort_t &ms) const
248{
249    Long_t tm = GetTime24();
250    ms  = tm%1000;            // [ms]
251    tm /= 1000;               // [s]
252    s   = tm%60;              // [s]
253    tm /= 60;                 // [m]
254    m   = tm%60;              // [m]
255    tm /= 60;                 // [h]
256    h   = tm;                 // [h]
257}
258
259// --------------------------------------------------------------------------
260//
261//  Return time as MJD (=JD-24000000.5)
262//
263Double_t MTime::GetMjd() const
264{
265    return fMjd+(Double_t)(fNanoSec/1e6+(Long_t)fTime)/kDay;
266}
267
268// --------------------------------------------------------------------------
269//
270// Return a time which is expressed in milliseconds since 01/01/1995 0:00h
271// This is compatible with root's definition used in gSystem->Now()
272// and TTime.
273// Note, gSystem->Now() returns local time, such that it may differ
274// from GetRootTime() (if you previously called MTime::Now())
275//
276TTime MTime::GetRootTime() const
277{
278    return (ULong_t)((GetMjd()-49718)*kDay);
279}
280
281// --------------------------------------------------------------------------
282//
283// Return a time which is expressed in seconds since 01/01/1970 0:00h
284// This is compatible with root's definition used in the constructor of
285// TDatime.
286//
287TDatime MTime::GetRootDatime() const
288{
289    return TDatime((UInt_t)((GetMjd()-40587)*kDaySec));
290}
291
292// --------------------------------------------------------------------------
293//
294// Return a time which is expressed in seconds since 01/01/1995 0:00h
295// This is compatible with root's definition used in TAxis.
296// Note, a TAxis always displayes (automatically) given times in
297// local time (while here we return UTC) such, that you may encounter
298// strange offsets. You can get rid of this by calling:
299//    TAxis::SetTimeFormat("[your-format] %F1995-01-01 00:00:00 GMT");
300// Note that an offset of 1970-01-01 does NOT work, because root
301// assumes that this is local time, tries to convert that to UTC,
302// which gives a negative unix time stamp in Europe, and ignores it.
303//
304Double_t MTime::GetAxisTime() const
305{
306    return (GetMjd()-49718)*kDaySec;
307}
308
309// --------------------------------------------------------------------------
310//
311// Counterpart of GetAxisTime
312//
313void MTime::SetAxisTime(Double_t time)
314{
315    SetMjd(time/kDaySec+49718);
316}
317
318// --------------------------------------------------------------------------
319//
320// Set unix time (seconds since epoche 1970-01-01 00:00)
321//
322void MTime::SetUnixTime(Long64_t sec, ULong64_t usec)
323{
324    const Long64_t totsec = sec + usec/1000000;
325    const UInt_t   mjd    = totsec/kDaySec + 40587;
326
327    const UInt_t   ms     = totsec%kDaySec*1000 + (usec/1000)%1000;
328    const UInt_t   us     = usec%1000;
329
330    SetMjd(mjd, ms, us*1000);
331}
332
333// --------------------------------------------------------------------------
334//
335// Set MTime to time expressed in a 'struct timeval'
336//
337void MTime::Set(const struct timeval &tv)
338{
339    SetUnixTime(tv.tv_sec, tv.tv_usec);
340}
341
342// --------------------------------------------------------------------------
343//
344// Set this to the date of easter corresponding to the given year.
345// If calculation was not possible it is set to MTime()
346//
347// The date corresponding to the year of MTime(-1) is returned
348// if year<0
349//
350// The date corresponding to the Year() is returned if year==0.
351//
352//  for more information see: GetEaster and MAstro::GetEasterOffset()
353//
354void MTime::SetEaster(Short_t year)
355{
356    *this = GetEaster(year==0 ? Year() : year);
357}
358
359// --------------------------------------------------------------------------
360//
361// Set a time expressed in MJD, Time of Day (eg. 23:12.779h expressed
362// in milliseconds) and a nanosecond part.
363//
364Bool_t MTime::SetMjd(UInt_t mjd, ULong_t ms, UInt_t ns)
365{
366    // [d]  mjd  (eg. 52320)
367    // [ms] time (eg. 17h expressed in ms)
368    // [ns] time (ns part of time)
369
370    if (ms>kDay-1 || ns>999999)
371        return kFALSE;
372
373    const Bool_t am = ms<kHour*13; // day of sunrise?
374
375    fMjd     = am ? mjd : mjd + 1;
376    fTime    = (Long_t)(am ? ms  : ms-kDay);
377    fNanoSec = ns;
378
379    return kTRUE;
380}
381
382// --------------------------------------------------------------------------
383//
384// Set MTime to given MJD (eg. 52080.0915449892)
385//
386void MTime::SetMjd(Double_t m)
387{
388    const UInt_t   mjd  = (UInt_t)TMath::Floor(m);
389    const Double_t frac = fmod(m, 1)*kDay; // [ms] Fraction of day
390    const UInt_t   ns   = (UInt_t)fmod(frac*1e6, 1000000);
391
392    SetMjd(mjd, (ULong_t)TMath::Floor(frac), ns);
393}
394
395// --------------------------------------------------------------------------
396//
397// Set MTime to given time and date
398//
399Bool_t MTime::Set(UShort_t y, Byte_t m, Byte_t d, Byte_t h, Byte_t min, Byte_t s, UShort_t ms, UInt_t ns)
400{
401    if (h>23 || min>59 || s>59 || ms>999 || ns>999999)
402        return kFALSE;
403
404    const Int_t mjd = MAstro::Ymd2Mjd(y, m, d);
405    if (mjd<0)
406        return kFALSE;
407
408    const ULong_t tm = ((((h*60+min)*60)+s)*1000)+ms;
409
410    return SetMjd(mjd, tm, ns);
411}
412
413// --------------------------------------------------------------------------
414//
415// Return contents as a TString of the form:
416//   "dd.mm.yyyy hh:mm:ss.fff"
417//
418Bool_t MTime::SetString(const char *str)
419{
420    if (!str)
421        return kFALSE;
422
423    UInt_t y, mon, d, h, m, s, ms;
424    const Int_t n = sscanf(str, "%02u.%02u.%04u %02u:%02u:%02u.%03u",
425                           &d, &mon, &y, &h, &m, &s, &ms);
426
427    return n==7 ? Set(y, mon, d, h, m, s, ms) : kFALSE;
428}
429
430// --------------------------------------------------------------------------
431//
432// Return contents as a TString of the form:
433//   "yyyy-mm-dd hh:mm:ss"
434//
435Bool_t MTime::SetSqlDateTime(TString str)
436{
437    if (str.IsNull())
438        return kFALSE;
439
440    str.ReplaceAll("T", "");
441
442    if (str.Contains('.'))
443        str += "000";
444
445    UInt_t  y, mon, d, h, m, s, ms;
446
447    if (7==sscanf(str, "%04u-%02u-%02u %02u:%02u:%02u.%03u", &y, &mon, &d, &h, &m, &s, &ms))
448        return Set(y, mon, d, h, m, s, ms);
449
450    if (6==sscanf(str, "%04u-%02u-%02u %02u:%02u:%02u", &y, &mon, &d, &h, &m, &s))
451        return Set(y, mon, d, h, m, s);
452
453    if (5==sscanf(str, "%04u-%02u-%02u %02u:%02u", &y, &mon, &d, &h, &m))
454        return Set(y, mon, d, h, m);
455
456    if (4==sscanf(str, "%04u-%02u-%02u %02u", &y, &mon, &d, &h))
457        return Set(y, mon, d, h);
458
459    if (3==sscanf(str, "%04u-%02u-%02u", &y, &mon, &d))
460        return Set(y, mon, d);
461
462    return kFALSE;
463}
464
465// --------------------------------------------------------------------------
466//
467// Return contents as a TString of the form:
468//   "yyyymmddhhmmss"
469//
470Bool_t MTime::SetSqlTimeStamp(const char *str)
471{
472    if (!str)
473        return kFALSE;
474
475    UInt_t y, mon, d, h, m, s;
476    const Int_t n = sscanf(str, "%04u%02u%02u%02u%02u%02u",
477                           &y, &mon, &d, &h, &m, &s);
478
479    return n==6 ? Set(y, mon, d, h, m, s) : kFALSE;
480}
481
482// --------------------------------------------------------------------------
483//
484// Set MTime to time expressed as in CT1 PreProc files
485//
486void MTime::SetCT1Time(UInt_t mjd, UInt_t t1, UInt_t t0)
487{
488    // int   isecs_since_midday; // seconds passed since midday before sunset (JD of run start)
489    // int   isecfrac_200ns;     // fractional part of isecs_since_midday
490    // fTime->SetTime(isecfrac_200ns, isecs_since_midday);
491    fNanoSec         = (200*t1)%1000000;
492    const ULong_t ms = (200*t1)/1000000 + t0+12*kHour;
493
494    fTime = (Long_t)(ms<13*kHour ? ms : ms-kDay);
495
496    fMjd = mjd+1;
497}
498
499// --------------------------------------------------------------------------
500//
501// Set MTime to time expressed as float (yymmdd.ffff)
502//  for details see MAstro::Yymmdd2Mjd
503//
504void MTime::SetCorsikaTime(Float_t t)
505{
506    const UInt_t   yymmdd = (UInt_t)TMath::Floor(t);
507    const UInt_t   mjd    = MAstro::Yymmdd2Mjd(yymmdd);
508    const Double_t frac   = fmod(t, 1)*kDay; // [ms] Fraction of day
509    const UInt_t   ns     = (UInt_t)fmod(frac*1e6, 1000000);
510
511    SetMjd(mjd, (ULong_t)TMath::Floor(frac), ns);
512}
513
514// --------------------------------------------------------------------------
515//
516// Update the magic time. Make sure, that the MJD is set correctly.
517// It must be the MJD of the corresponding night. You can set it
518// by Set(2003, 12, 24);
519//
520// It is highly important, that the time correspoding to the night is
521// between 13:00:00.0 (day of dawning) and 12:59:59.999 (day of sunrise)
522//
523Bool_t MTime::UpdMagicTime(Byte_t h, Byte_t m, Byte_t s, UInt_t ns)
524{
525    if (h>23 || m>59 || s>59 || ns>999999999)
526         return kFALSE;
527
528    const ULong_t tm = ((((h*60+m)*60)+s)*1000)+ns/1000000;
529
530    fTime = (Long_t)(tm<kHour*13 ? tm  : tm-kDay); // day of sunrise?
531    fNanoSec = ns%1000000;
532
533    return kTRUE;
534}
535
536// --------------------------------------------------------------------------
537//
538//  Conversion from Universal Time to Greenwich mean sidereal time,
539//  with rounding errors minimized.
540//
541//  The result is the Greenwich Mean Sidereal Time (radians)
542//
543//  There is no restriction on how the UT is apportioned between the
544//  date and ut1 arguments.  Either of the two arguments could, for
545//  example, be zero and the entire date+time supplied in the other.
546//  However, the routine is designed to deliver maximum accuracy when
547//  the date argument is a whole number and the ut argument lies in
548//  the range 0 to 1, or vice versa.
549//
550//  The algorithm is based on the IAU 1982 expression (see page S15 of
551//  the 1984 Astronomical Almanac).  This is always described as giving
552//  the GMST at 0 hours UT1.  In fact, it gives the difference between
553//  the GMST and the UT, the steady 4-minutes-per-day drawing-ahead of
554//  ST with respect to UT.  When whole days are ignored, the expression
555//  happens to equal the GMST at 0 hours UT1 each day.
556//
557//  In this routine, the entire UT1 (the sum of the two arguments date
558//  and ut) is used directly as the argument for the standard formula.
559//  The UT1 is then added, but omitting whole days to conserve accuracy.
560//
561//  The extra numerical precision delivered by the present routine is
562//  unlikely to be important in an absolute sense, but may be useful
563//  when critically comparing algorithms and in applications where two
564//  sidereal times close together are differenced.
565//
566Double_t MTime::GetGmst() const
567{
568    const Double_t ut = (Double_t)(fNanoSec/1e6+(Long_t)fTime)/kDay;
569
570    // Julian centuries since J2000.
571    const Double_t t = (ut -(51544.5-fMjd)) / 36525.0;
572
573    // GMST at this UT1
574    const Double_t r1 = 24110.54841+(8640184.812866+(0.093104-6.2e-6*t)*t)*t;
575    const Double_t r2 = 86400.0*ut;
576
577    const Double_t sum = (r1+r2)/kDaySec;
578
579    return fmod(sum, 1)*TMath::TwoPi();//+TMath::TwoPi();
580}
581
582// --------------------------------------------------------------------------
583//
584// Return Day of the week: Sun=0, Mon=1, ..., Sat=6
585//
586Byte_t MTime::WeekDay() const
587{
588    return TMath::FloorNint(GetMjd()+3)%7;
589} 
590
591// --------------------------------------------------------------------------
592//
593// Get the day of the year represented by day, month and year.
594// Valid return values range between 1 and 366, where January 1 = 1.
595//
596UInt_t MTime::DayOfYear() const
597{
598    MTime jan1st;
599    jan1st.Set(Year(), 1, 1);
600
601    const Double_t newyear = TMath::Floor(jan1st.GetMjd());
602    const Double_t mjd     = TMath::Floor(GetMjd());
603
604    return TMath::Nint(mjd-newyear)+1;
605}
606
607// --------------------------------------------------------------------------
608//
609// Return Mjd of the first day (a monday) which belongs to week 1 of
610// the year give as argument. The returned Mjd might be a date in the
611// year before.
612//
613//  see also MTime::Week()
614//
615Int_t MTime::GetMjdWeek1(Short_t year)
616{
617    MTime t;
618    t.Set(year, 1, 4);
619
620    return (Int_t)t.GetMjd() + t.WeekDay() - 6;
621}
622
623// --------------------------------------------------------------------------
624//
625// Get the week of the year. Valid week values are between 1 and 53.
626// If for a january date a week number above 50 is returned the
627// week belongs to the previous year. If for a december data 1 is
628// returned the week already belongs to the next year.
629//
630// The year to which the week belongs is returned in year.
631//
632// Die Kalenderwochen werden für Jahre ab 1976 berechnet, da mit
633// Geltung vom 1. Januar 1976 der Wochenbeginn auf Montag festgelegt
634// wurde. Die erste Woche ist definiert als die Woche, in der
635// mindestens 4 der ersten 7 Januartage fallen (also die Woche, in der
636// der 4. Januar liegt). Beides wurde damals festgelegt in der DIN 1355
637// (1974). Inhaltlich gleich regelt das die Internationale Norm
638// ISO 8601 (1988), die von der Europäischen Union als EN 28601 (1992)
639// übernommen und in Deutschland als DIN EN 28601 (1993) umgesetzt
640// wurde.
641//
642Int_t MTime::Week(Short_t &year) const
643{
644    // Possibilities for Week 1:
645    //
646    //    Mo 4.Jan:   Mo  4. - So 10.    -0   6-6
647    //    Di 4.Jan:   Mo  3. - So  9.    -1   6-5
648    //    Mi 4.Jan:   Mo  2. - So  8.    -2   6-4
649    //    Do 4.Jan:   Mo  1. - So  7.    -3   6-3
650    //    Fr 4.Jan:   Mo 31. - So  6.    -4   6-2
651    //    Sa 4.Jan:   Mo 30. - So  5.    -5   6-1
652    //    So 4.Jan:   Mo 29. - So  4.    -6   6-0
653    //
654    const Int_t mjd2 = GetMjdWeek1(Year()-1);
655    const Int_t mjd0 = GetMjdWeek1(Year());
656    const Int_t mjd3 = GetMjdWeek1(Year()+1);
657
658    // Today
659    const Int_t mjd = (Int_t)GetMjd();
660
661    // Week belongs to last year, return week of last year
662    if (mjd<mjd0)
663    {
664        year = Year()-1;
665        return (mjd-mjd2)/7 + 1;
666    }
667
668    // Check if Week belongs to next year (can only be week 1)
669    if ((mjd3-mjd)/7==1)
670    {
671        year = Year()+1;
672        return 1;
673    }
674
675    // Return calculated Week
676    year = Year();
677    return (mjd-mjd0)/7 + 1;
678}
679
680// --------------------------------------------------------------------------
681//
682// Is the given year a leap year.
683// The calendar year is 365 days long, unless the year is exactly divisible
684// by 4, in which case an extra day is added to February to make the year
685// 366 days long. If the year is the last year of a century, eg. 1700, 1800,
686// 1900, 2000, then it is only a leap year if it is exactly divisible by
687// 400. Therefore, 1900 wasn't a leap year but 2000 was. The reason for
688// these rules is to bring the average length of the calendar year into
689// line with the length of the Earth's orbit around the Sun, so that the
690// seasons always occur during the same months each year.
691//
692Bool_t MTime::IsLeapYear() const
693{
694    const UInt_t y = Year();
695    return (y%4==0) && !((y%100==0) && (y%400>0));
696}
697
698// --------------------------------------------------------------------------
699//
700// Set the time to the current system time. The timezone is ignored.
701// If everything is set correctly you'll get UTC.
702//
703void MTime::Now()
704{
705#ifdef __LINUX__
706    struct timeval tv;
707    if (gettimeofday(&tv, NULL)<0)
708        Clear();
709    else
710        Set(tv);
711#else
712#error __LINUX__ not set
713#endif
714}
715
716// --------------------------------------------------------------------------
717//
718// Return contents as a TString of the form:
719//   "dd.mm.yyyy hh:mm:ss.fff"
720//
721TString MTime::GetString() const
722{
723    UShort_t y, ms;
724    Byte_t mon, d, h, m, s;
725
726    GetDate(y, mon, d);
727    GetTime(h, m, s, ms);
728
729    return MString::Format("%02d.%02d.%04d %02d:%02d:%02d.%03d", d, mon, y, h, m, s, ms);
730}
731
732// --------------------------------------------------------------------------
733//
734// Return contents as a string format'd with strftime:
735// Here is a short summary of the most important formats. For more
736// information see the man page (or any other description) of
737// strftime...
738//
739//  %a  The abbreviated weekday name according to the current locale.
740//  %A  The full weekday name according to the current locale.
741//  %b  The abbreviated month name according to the current locale.
742//  %B  The full month name according to the current locale.
743//  %c  The preferred date and time representation for the current locale.
744//  %d  The day of the month as a decimal number (range  01 to 31).
745//  %e  Like %d, the day of the month as a decimal number,
746//      but a leading zero is replaced by a space.
747//  %H  The hour as a decimal number using a 24-hour clock (range 00 to 23)
748//  %k  The hour (24-hour clock) as a decimal number (range 0 to 23);
749//      single digits are preceded by a blank.
750//  %m  The month as a decimal number (range 01 to 12).
751//  %M  The minute as a decimal number (range 00 to 59).
752//  %R  The time in 24-hour notation (%H:%M).  For a
753//      version including the seconds, see %T below.
754//  %S  The second as a decimal number (range 00 to 61).
755//  %T  The time in 24-hour notation (%H:%M:%S).
756//  %x  The preferred date representation for the current
757//      locale without the time.
758//  %X  The preferred time representation for the current
759//      locale without the date.
760//  %y  The year as a decimal number without a century (range 00 to 99).
761//  %Y  The year as a decimal number including the century.
762//  %+  The date and time in date(1) format.
763//
764// The default is: Tuesday 16.February 2004 12:17:22
765//
766// The maximum size of the return string is 128 (incl. NULL)
767//
768// For dates before 1. 1.1902  a null string is returned
769// For dates after 31.12.2037 a null string is returned
770//
771// To change the localization use loc, eg loc = "da_DK", "de_DE".
772// Leaving the argument empty will just take the default localization.
773//
774// If loc is "", each part of the locale that should be modified is set
775// according  to the environment variables. The details are implementation
776// dependent.  For glibc, first (regardless of category), the  environment
777// variable  LC_ALL  is  inspected, next the environment variable with the
778// same name as the category (LC_COLLATE, LC_CTYPE, LC_MESSAGES,  LC_MONE?
779// TARY,  LC_NUMERIC,  LC_TIME) and finally the environment variable LANG.
780// The first existing environment variable is used.
781//
782// A  locale  name  is  typically  of the form language[_territory][.code?
783// set][@modifier], where language is an ISO 639 language code,  territory
784// is an ISO 3166 country code, and codeset is a character set or encoding
785// identifier like ISO-8859-1 or UTF-8.   For  a  list  of  all  supported
786// locales, try "locale -a", cf. locale(1).
787//
788TString MTime::GetStringFmt(const char *fmt, const char *loc) const
789{
790    if (!fmt)
791        fmt = "%A %e.%B %Y %H:%M:%S";
792
793    UShort_t y, ms;
794    Byte_t mon, d, h, m, s;
795
796    GetDate(y, mon, d);
797    GetTime(h, m, s, ms);
798
799    // If date<1902 strftime crahses on my (tbretz) laptop
800    // it doesn't crash in the DC.
801    //    if (y<1902 || y>2037)
802    //        return "";
803
804    struct tm time;
805    time.tm_sec   = s;
806    time.tm_min   = m;
807    time.tm_hour  = h;
808    time.tm_mday  = d;
809    time.tm_mon   = mon-1;
810    time.tm_year  = y-1900;
811    time.tm_isdst = -1;
812
813    // -1: If dst, isdst is set to 1 but hour is not changed
814    //  0: If dst, hour is changed
815
816    // Get old local
817    const TString locale = setlocale(LC_TIME, 0);
818
819    // Set new local (e.g. Montag instead of Monday)
820    setlocale(LC_TIME, loc);
821
822    // recalculate tm_yday and tm_wday
823    mktime(&time);
824
825    // We get errors for example for 1910-01-01
826    //    if (mktime(&time)<0)
827    //        return "";
828
829    char ret[128];
830    const size_t rc = strftime(ret, 127, fmt, &time);
831
832    setlocale(LC_TIME, locale);
833
834    return rc ? ret : "";
835}
836
837// --------------------------------------------------------------------------
838//
839// Set the time according to the format fmt.
840// Default is "%A %e.%B %Y %H:%M:%S"
841//
842// For more information see GetStringFmt
843//
844Bool_t MTime::SetStringFmt(const char *time, const char *fmt, const char *loc)
845{
846    if (!fmt)
847        fmt = "%A %e.%B %Y %H:%M:%S";
848
849    struct tm t;
850    memset(&t, 0, sizeof(struct tm));
851
852    const TString locale = setlocale(LC_TIME, 0);
853
854    setlocale(LC_TIME, loc);
855    strptime(time, fmt, &t);
856    setlocale(LC_TIME, locale);
857
858    return Set(t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
859}
860
861// --------------------------------------------------------------------------
862//
863// Return contents as a TString of the form:
864//   "yyyy-mm-dd hh:mm:ss"
865//
866TString MTime::GetSqlDateTime() const
867{
868    return GetStringFmt("%Y-%m-%d %H:%M:%S");
869}
870
871// --------------------------------------------------------------------------
872//
873// Return contents as a TString of the form:
874//   "yyyymmddhhmmss"
875//
876TString MTime::GetSqlTimeStamp() const
877{
878    return GetStringFmt("%Y%m%d%H%M%S");
879}
880
881// --------------------------------------------------------------------------
882//
883// Return contents as a TString of the form:
884//   "yyyymmdd_hhmmss"
885//
886TString MTime::GetFileName() const
887{
888    return GetStringFmt("%Y%m%d_%H%M%S");
889}
890
891// --------------------------------------------------------------------------
892//
893// Print MTime as string
894//
895void MTime::Print(Option_t *) const
896{
897    UShort_t yea, ms;
898    Byte_t mon, day, h, m, s;
899
900    GetDate(yea, mon, day);
901    GetTime(h, m, s, ms);
902
903    *fLog << all << GetDescriptor() << ": ";
904    *fLog << GetString() << MString::Format(" (+%dns)", fNanoSec) << endl;
905} 
906
907// --------------------------------------------------------------------------
908//
909// Calls Set(t[0], t[1], t[2], t[3], t[4], t[5], 0)
910//
911Bool_t MTime::SetBinary(const UInt_t t[6])
912{
913    return Set(t[0], t[1], t[2], t[3], t[4], t[5], 0);
914}
915
916// --------------------------------------------------------------------------
917//
918// Assign:
919//    t[0] = year;
920//    t[1] = month;
921//    t[2] = day;
922//    t[3] = hour;
923//    t[4] = minute;
924//    t[5] = second;
925//
926void MTime::GetBinary(UInt_t t[6]) const
927{
928    UShort_t yea, ms;
929    Byte_t mon, day, h, m, s;
930
931    GetDate(yea, mon, day);
932    GetTime(h, m, s, ms);
933
934    t[0] = yea;
935    t[1] = mon;
936    t[2] = day;
937    t[3] = h;
938    t[4] = m;
939    t[5] = s;
940}
941
942// --------------------------------------------------------------------------
943//
944// Read seven bytes representing y, m, d, h, m, s
945//
946istream &MTime::ReadBinary(istream &fin)
947{
948    UShort_t y;
949    Byte_t mon, d, h, m, s;
950
951    fin.read((char*)&y,   2);
952    fin.read((char*)&mon, 1);
953    fin.read((char*)&d,   1);
954    fin.read((char*)&h,   1);
955    fin.read((char*)&m,   1);
956    fin.read((char*)&s,   1); // Total=7
957
958    Set(y, mon, d, h, m, s, 0);
959
960    return fin;
961}
962
963// --------------------------------------------------------------------------
964//
965// Write seven bytes representing y, m, d, h, m, s
966//
967ostream &MTime::WriteBinary(ostream &out) const
968{
969    UShort_t y, ms;
970    Byte_t mon, d, h, m, s;
971
972    GetDate(y, mon, d);
973    GetTime(h, m, s, ms);
974
975    out.write((char*)&y,   2);
976    out.write((char*)&mon, 1);
977    out.write((char*)&d,   1);
978    out.write((char*)&h,   1);
979    out.write((char*)&m,   1);
980    out.write((char*)&s,   1); // Total=7
981
982    return out;
983}
984
985void MTime::AddMilliSeconds(UInt_t ms)
986{
987    fTime += ms;
988
989    fTime += 11*kHour;
990    fMjd  += (Long_t)fTime/kDay;
991    fTime  = (Long_t)fTime%kDay;
992    fTime -= 11*kHour;
993}
994
995void MTime::Plus1ns()
996{
997    fNanoSec++;
998
999    if (fNanoSec<1000000)
1000        return;
1001
1002    fNanoSec = 0;
1003    fTime += 1;
1004
1005    if ((Long_t)fTime<(Long_t)kDay*13)
1006        return;
1007
1008    fTime = 11*kDay;
1009    fMjd++;
1010}   
1011
1012void MTime::Minus1ns()
1013{
1014    if (fNanoSec>0)
1015    {
1016        fNanoSec--;
1017        return;
1018    }
1019
1020    fTime -= 1;
1021    fNanoSec = 999999;
1022
1023    if ((Long_t)fTime>=-(Long_t)kDay*11)
1024        return;
1025
1026    fTime = 13*kDay-1;
1027    fMjd--;
1028}   
1029
1030/*
1031MTime MTime::operator-(const MTime &tm1)
1032{
1033    const MTime &tm0 = *this;
1034
1035    MTime t0 = tm0>tm1 ? tm0 : tm1;
1036    const MTime &t1 = tm0>tm1 ? tm1 : tm0;
1037
1038    if (t0.fNanoSec<t1.fNanoSec)
1039    {
1040        t0.fNanoSec += 1000000;
1041        t0.fTime -= 1;
1042    }
1043
1044    t0.fNanoSec -= t1.fNanoSec;
1045    t0.fTime    -= t1.fTime;
1046
1047    if ((Long_t)t0.fTime<-(Long_t)kHour*11)
1048    {
1049        t0.fTime += kDay;
1050        t0.fMjd--;
1051    }
1052
1053    t0.fMjd -= t1.fMjd;
1054
1055    return t0;
1056}
1057
1058void MTime::operator-=(const MTime &t)
1059{
1060    *this = *this-t;
1061}
1062
1063MTime MTime::operator+(const MTime &t1)
1064{
1065    MTime t0 = *this;
1066
1067    t0.fNanoSec += t1.fNanoSec;
1068
1069    if (t0.fNanoSec>999999)
1070    {
1071        t0.fNanoSec -= 1000000;
1072        t0.fTime += kDay;
1073    }
1074
1075    t0.fTime += t1.fTime;
1076
1077    if ((Long_t)t0.fTime>=(Long_t)kHour*13)
1078    {
1079        t0.fTime -= kDay;
1080        t0.fMjd++;
1081    }
1082
1083    t0.fMjd += t1.fMjd;
1084
1085    return t0;
1086}
1087
1088void MTime::operator+=(const MTime &t)
1089{
1090    *this = *this+t;
1091}
1092*/
1093
1094void MTime::SetMean(const MTime &t0, const MTime &t1)
1095{
1096    // This could be an operator+
1097    *this = t0;
1098
1099    fNanoSec += t1.fNanoSec;
1100
1101    if (fNanoSec>999999)
1102    {
1103        fNanoSec -= 1000000;
1104        fTime += kDay;
1105    }
1106
1107    fTime += t1.fTime;
1108
1109    if ((Long_t)fTime>=(Long_t)kHour*13)
1110    {
1111        fTime -= kDay;
1112        fMjd++;
1113    }
1114
1115    fMjd += t1.fMjd;
1116
1117    // This could be an operator/
1118    if ((Long_t)fTime<0)
1119    {
1120        fTime += kDay;
1121        fMjd--;
1122    }
1123
1124    Int_t reminder = fMjd%2;
1125    fMjd /= 2;
1126
1127    fTime += reminder*kDay;
1128    reminder = (Long_t)fTime%2;
1129    fTime /= 2;
1130
1131    fNanoSec += reminder*1000000;
1132    fNanoSec /= 2;
1133
1134    fTime += 11*kHour;
1135    fMjd  += (Long_t)fTime/kDay;
1136    fTime  = (Long_t)fTime%kDay;
1137    fTime -= 11*kHour;
1138}
1139
1140void MTime::SetMean(Double_t t0, Double_t t1)
1141{
1142    const Double_t mean = (t0+t1)*(0.5/kDaySec);
1143    SetMjd(mean);
1144}
1145
1146void MTime::AsciiRead(istream &fin)
1147{
1148    fin >> *this;
1149}
1150
1151Bool_t MTime::AsciiWrite(ostream &out) const
1152{
1153    out << *this;
1154    return bool(out);
1155}
1156
1157// --------------------------------------------------------------------------
1158//
1159// Calculate the day of easter for the given year.
1160// MTime() is returned if this was not possible.
1161//
1162// In case of the default argument or the year less than zero
1163// the date of eastern of the current year (the year corresponding to
1164// MTime(-1)) is returned.
1165//
1166//  for more information see: MAstro::GetDayOfEaster()
1167//
1168MTime MTime::GetEaster(Short_t year)
1169{
1170    if (year<0)
1171        year = MTime(-1).Year();
1172
1173    const Int_t day = MAstro::GetEasterOffset(year);
1174    if (day<0)
1175        return MTime();
1176
1177    MTime t;
1178    t.Set(year, 3, 1);
1179    t.SetMjd(t.GetMjd() + day);
1180
1181    return t;
1182}
Note: See TracBrowser for help on using the repository browser.