source: trunk/FACT++/src/Time.cc@ 15027

Last change on this file since 15027 was 15006, checked in by tbretz, 12 years ago
Added initializer from an ISO string, fixed the wrong ISO format description in Time::iso.
File size: 10.1 KB
Line 
1// **************************************************************************
2/** @class Time
3
4@brief Adds some functionality to boost::posix_time::ptime for our needs
5
6This is basically a wrapper around boost::posix_time::ptime which is made
7to adapt the functionality to our needs. Time can store the current
8data and time with a precision up to nanoseconds if provided by the
9undrlaying system, otherwise microsecond precision is used.
10
11It main purpose is to provide needed constructors and simplyfy the
12conversion of dates and times from and to a string/stream.
13
14Note that posix_time (as Posix times have) has a limited range. You cannot
15use it for example for very early years of the last century.
16
17@section Examples
18
19 - An example can be found in \ref time.cc
20
21@section References
22
23 - <A HREF="http://www.boost.org/doc/libs/1_45_0/doc/html/date_time.html">BOOST++ date_time (V1.45.0)</A>
24
25**/
26// **************************************************************************
27#include "Time.h"
28
29using namespace std;
30using namespace boost::posix_time;
31
32const boost::gregorian::date Time::fUnixOffset(1970, 1, 1);
33
34const Time Time::None(Time::none);
35
36// strftime
37const _time_format Time::reset = 0;
38const _time_format Time::def = "%c";
39const _time_format Time::std = "%x %X%F";
40const _time_format Time::sql = "%Y-%m-%d %H:%M:%S.%f";
41const _time_format Time::ssql = "%Y-%m-%d %H:%M:%S";
42const _time_format Time::iso = "%Y-%m-%dT%H:%M:%S%F%q";
43const _time_format Time::magic = "%Y %m %d %H %M %S %f";
44const _time_format Time::smagic = "%Y %m %d %H %M %S";
45
46// --------------------------------------------------------------------------
47//
48//! Construct a Time object with either UTC or local time, or without any
49//! particular time.
50//!
51//! @param typ
52//! enum as defined in Time::init_t
53//
54Time::Time(enum init_t typ)
55{
56 switch (typ)
57 {
58 case utc:
59 *this = microsec_clock::universal_time();
60 break;
61 case local:
62 *this = microsec_clock::local_time();
63 break;
64 case none:
65 break;
66 }
67}
68
69
70// --------------------------------------------------------------------------
71//
72//! Construct a Time object with a date_time::special_value, e.g.
73//!
74//! - neg_infin
75//! - pos_infin
76//! - not_a_date_time
77//! - max_date_time
78//! - min_date_time
79//!
80//!
81//! @param val
82//! date_time::special_value
83//
84Time::Time(const boost::date_time::special_values &val) : ptime(val)
85{
86}
87
88// --------------------------------------------------------------------------
89//
90//! Construct a Time object from seconds since 1970/1/1 and number of
91//! milliseconds, as for example returned by gettimeofday()
92//!
93//! @param tm
94//! seconds since 1970/1/1
95//!
96//! @param millisec
97//! number of milliseconds
98//
99Time::Time(const time_t &tm, const int &millisec)
100: ptime(fUnixOffset, time_duration(0, 0, tm, millisec))
101{
102}
103
104// --------------------------------------------------------------------------
105//
106//! Construct a Time from a date and time.
107//!
108//! @param year, month, day, hh, mm, ss, microsec
109//! A full date and time down to microsecond precision. From the end
110//! arguments can be omitted.
111//!
112Time::Time(short year, unsigned char month, unsigned char day,
113 unsigned char hh, unsigned char mm, unsigned char ss, unsigned int microsec)
114// Last argument is fractional_seconds ( correct with num_fractional_digits() )
115: ptime(boost::gregorian::date(year, month, day),
116 time_duration(hh, mm, ss, microsec*pow(10, time_of_day().num_fractional_digits()-6)))
117{
118}
119
120// --------------------------------------------------------------------------
121//
122//! Set the Time object to a given MJD. Note that this involves
123//! conversion from double. So converting forth and back many many
124//! times might results in drifts.
125//!
126//! @param mjd
127//! Modified Julian Date
128//!
129void Time::Mjd(double mjd)
130{
131 if (mjd > 2400000.5)
132 mjd -= 2400000.5;
133
134 // Convert MJD to seconds since offset
135 mjd -= 40587;
136 mjd *= 24*60*60;
137
138 const int exp = time_of_day().num_fractional_digits();
139 const double frac = fmod(mjd, 1)*pow(10, exp);
140
141 *this = ptime(fUnixOffset, time_duration(0, 0, mjd, frac));
142}
143
144// --------------------------------------------------------------------------
145//
146//! @returns the seconds of the day including the fractional seconds.
147//!
148double Time::SecondsOfDay() const
149{
150 const time_duration tod = time_of_day();
151
152 const int exp = tod.num_fractional_digits();
153
154 const double frac = tod.fractional_seconds()/pow(10, exp);
155 const double sec = tod.total_seconds()+frac;
156
157 return sec;
158}
159
160// --------------------------------------------------------------------------
161//
162//! Get the current MJD. Note that this involves
163//! conversion to double. So converting forth and back many many
164//! times might results in drifts.
165//!
166//! @returns
167//! Modified Julian Date
168//!
169double Time::Mjd() const
170{
171 return date().modjulian_day()+SecondsOfDay()/(24*60*60);
172
173 /*
174 const time_duration mjd = *this - ptime(fUnixOffset);
175 const double sec = mjd.total_seconds()+mjd.fractional_seconds()/1e6;
176 return sec/(24*60*60)+40587;
177 */
178}
179
180// --------------------------------------------------------------------------
181//
182// @returns seconds since 1970/1/1
183//
184double Time::UnixTime() const
185{
186 return (date().modjulian_day()-40587)*24*60*60 + SecondsOfDay();
187}
188
189// --------------------------------------------------------------------------
190//
191// @returns days since 1970/1/1
192//
193double Time::UnixDate() const
194{
195 return (date().modjulian_day()-40587) + SecondsOfDay()/(24*60*60);
196}
197
198// --------------------------------------------------------------------------
199//
200// @returns seconds since 1970/1/1
201//
202time_t Time::Time_t() const
203{
204 return (date().modjulian_day()-40587)*24*60*60 + time_of_day().total_seconds();
205}
206
207// --------------------------------------------------------------------------
208//
209//! @returns the time in a format needed for root's TAxis
210//!
211double Time::RootTime() const
212{
213 return (date().modjulian_day()-49718)*24*60*60 + SecondsOfDay();
214}
215
216// --------------------------------------------------------------------------
217//
218//! Returns a string with the contents of the Time object formated
219//! as defined in format.
220//!
221//! @param format
222//! format description of the string to be returned. For details
223//! see the boost documentation or the man page of strftime
224//!
225//! @returns
226//! A string with the time formatted as requested. Note some special
227//! strings might be returned in case the time is invalid.
228//
229string Time::GetAsStr(const char *format) const
230{
231 stringstream out;
232 out << Time::fmt(format) << *this;
233 return out.str();
234}
235
236// --------------------------------------------------------------------------
237//
238//! @returns
239//! a human readable string which complies with ISO 8601, in the
240//! "CCYY-MM-DDThh:mm:ss.f"
241//
242string Time::Iso() const
243{
244 stringstream out;
245 out << Time::iso << *this;
246 return out.str();
247}
248
249// --------------------------------------------------------------------------
250//
251//! Sets the time of the Time object to a time corresponding to
252//! the one given as argument. It is evaluated according to the given
253//! format.
254//!
255//! @param str
256//! The time as a string which should be converted to the Time object
257//!
258//! @param format
259//! format description of the string to be returned. For details
260//! see the boost documentation or the man page of strftime
261//!
262void Time::SetFromStr(const string &str, const char *format)
263{
264 // FIXME: exception handline
265 stringstream stream;
266 stream << str;
267 stream >> Time::fmt(format) >> *this;
268}
269
270string Time::MinutesTo(const Time &time) const
271{
272 ostringstream str;
273 if (time>*this)
274 str << time-*this;
275 else
276 str << *this-time;
277 return str.str().substr(0, 5);
278}
279
280string Time::SecondsTo(const Time &time) const
281{
282 ostringstream str;
283 if (time>*this)
284 str << time-*this;
285 else
286 str << *this-time;
287 return str.str().substr(str.str().substr(0, 3)=="00:" ? 3 : 0, 5);
288}
289
290// --------------------------------------------------------------------------
291//
292//! @returns
293//! an int corresponding to the stored time minus 12 hours of the form
294//! YYYYMMDD, e.g. 20111224 for Christmas eve 2011
295//
296int Time::NightAsInt() const
297{
298 const Time tm = *this - boost::posix_time::hours(12);
299 return tm.Y()*10000 + tm.M()*100 + tm.D();
300}
301
302// --------------------------------------------------------------------------
303//
304//! A stream manipulator which sets the streams Time output format
305//! as defined in the argument.
306//!
307//! @param format
308//! format description of the manipulator be returned. For details
309//! see the boost documentation or the man page of strftime
310//!
311//! @returns
312//! a stream manipulator for the given format
313//!
314const _time_format Time::fmt(const char *format)
315{
316 return format;
317}
318
319// --------------------------------------------------------------------------
320//
321//! Sets the locale discription of the stream (the way how a time is
322//! output) to the format defined by the given manipulator.
323//!
324//! Example:
325//! \code
326//! Time t();
327//! cout << Time::fmt("%Y:%m:%d %H:%M:%S.%f") << t << endl;
328//! \endcode
329//!
330//! @param out
331//! Reference to the stream
332//!
333//! @param f
334//! Time format described by a manipulator
335//!
336//! @returns
337//! A reference to the stream
338//!
339ostream &operator<<(ostream &out, const _time_format &f)
340{
341 const locale loc(locale::classic(),
342 f.ptr==0 ? 0 : new time_facet(f.ptr));
343
344 out.imbue(loc);
345
346 return out;
347}
348
349// --------------------------------------------------------------------------
350//
351//! Sets the locale discription of the stream (the way how a time is
352//! input) to the format defined by the given manipulator.
353//!
354//! Example:
355//! \code
356//! stringstream s;
357//! s << "09.09.1974 21:59";
358//!
359//! Time t;
360//! s >> Time::fmt("%d.%m.%Y %H:%M") >> t;
361//! \endcode
362//!
363//! @param in
364//! Reference to the stream
365//!
366//! @param f
367//! Time format described by a manipulator
368//!
369//! @returns
370//! A reference to the stream
371//!
372istream &operator>>(istream &in, const _time_format &f)
373{
374 const locale loc(locale::classic(),
375 f.ptr==0 ? 0 : new time_input_facet(f.ptr));
376
377 in.imbue(loc);
378
379 return in;
380}
381
Note: See TracBrowser for help on using the repository browser.