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

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