1 | // |
2 | // DateTime.h |
3 | // |
4 | // Library: Foundation |
5 | // Package: DateTime |
6 | // Module: DateTime |
7 | // |
8 | // Definition of the DateTime class. |
9 | // |
10 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
11 | // and Contributors. |
12 | // |
13 | // SPDX-License-Identifier: BSL-1.0 |
14 | // |
15 | |
16 | |
17 | #ifndef Foundation_DateTime_INCLUDED |
18 | #define Foundation_DateTime_INCLUDED |
19 | |
20 | |
21 | #include "Poco/Foundation.h" |
22 | #include "Poco/Timestamp.h" |
23 | #include "Poco/Timespan.h" |
24 | |
25 | |
26 | struct tm; |
27 | |
28 | |
29 | namespace Poco { |
30 | |
31 | |
32 | class Foundation_API DateTime |
33 | /// This class represents an instant in time, expressed |
34 | /// in years, months, days, hours, minutes, seconds |
35 | /// and milliseconds based on the Gregorian calendar. |
36 | /// The class is mainly useful for conversions between |
37 | /// UTC, Julian day and Gregorian calendar dates. |
38 | /// |
39 | /// The date and time stored in a DateTime is always in UTC |
40 | /// (Coordinated Universal Time) and thus independent of the |
41 | /// timezone in effect on the system. |
42 | /// |
43 | /// Conversion calculations are based on algorithms |
44 | /// collected and described by Peter Baum at |
45 | /// http://vsg.cape.com/~pbaum/date/date0.htm |
46 | /// |
47 | /// Internally, this class stores a date/time in two |
48 | /// forms (UTC and broken down) for performance reasons. Only use |
49 | /// this class for conversions between date/time representations. |
50 | /// Use the Timestamp class for everything else. |
51 | /// |
52 | /// Notes: |
53 | /// * Zero is a valid year (in accordance with ISO 8601 and astronomical year numbering) |
54 | /// * Year zero (0) is a leap year |
55 | /// * Negative years (years preceding 1 BC) are not supported |
56 | /// |
57 | /// For more information, please see: |
58 | /// * http://en.wikipedia.org/wiki/Gregorian_Calendar |
59 | /// * http://en.wikipedia.org/wiki/Julian_day |
60 | /// * http://en.wikipedia.org/wiki/UTC |
61 | /// * http://en.wikipedia.org/wiki/ISO_8601 |
62 | { |
63 | public: |
64 | enum Months |
65 | /// Symbolic names for month numbers (1 to 12). |
66 | { |
67 | JANUARY = 1, |
68 | FEBRUARY, |
69 | MARCH, |
70 | APRIL, |
71 | MAY, |
72 | JUNE, |
73 | JULY, |
74 | AUGUST, |
75 | SEPTEMBER, |
76 | OCTOBER, |
77 | NOVEMBER, |
78 | DECEMBER |
79 | }; |
80 | |
81 | enum DaysOfWeek |
82 | /// Symbolic names for week day numbers (0 to 6). |
83 | { |
84 | SUNDAY = 0, |
85 | MONDAY, |
86 | TUESDAY, |
87 | WEDNESDAY, |
88 | THURSDAY, |
89 | FRIDAY, |
90 | SATURDAY |
91 | }; |
92 | |
93 | DateTime(); |
94 | /// Creates a DateTime for the current date and time. |
95 | |
96 | DateTime(const tm& tmStruct); |
97 | /// Creates a DateTime from tm struct. |
98 | |
99 | DateTime(const Timestamp& timestamp); |
100 | /// Creates a DateTime for the date and time given in |
101 | /// a Timestamp. |
102 | |
103 | DateTime(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); |
104 | /// Creates a DateTime for the given Gregorian date and time. |
105 | /// * year is from 0 to 9999. |
106 | /// * month is from 1 to 12. |
107 | /// * day is from 1 to 31. |
108 | /// * hour is from 0 to 23. |
109 | /// * minute is from 0 to 59. |
110 | /// * second is from 0 to 60. |
111 | /// * millisecond is from 0 to 999. |
112 | /// * microsecond is from 0 to 999. |
113 | /// Throws an InvalidArgumentException if an argument date is out of range. |
114 | |
115 | DateTime(double julianDay); |
116 | /// Creates a DateTime for the given Julian day. |
117 | |
118 | DateTime(Timestamp::UtcTimeVal utcTime, Timestamp::TimeDiff diff); |
119 | /// Creates a DateTime from an UtcTimeVal and a TimeDiff. |
120 | /// |
121 | /// Mainly used internally by DateTime and friends. |
122 | |
123 | DateTime(const DateTime& dateTime); |
124 | /// Copy constructor. Creates the DateTime from another one. |
125 | |
126 | ~DateTime(); |
127 | /// Destroys the DateTime. |
128 | |
129 | DateTime& operator = (const DateTime& dateTime); |
130 | /// Assigns another DateTime. |
131 | |
132 | DateTime& operator = (const Timestamp& timestamp); |
133 | /// Assigns a Timestamp. |
134 | |
135 | DateTime& operator = (double julianDay); |
136 | /// Assigns a Julian day. |
137 | |
138 | DateTime& assign(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microseconds = 0); |
139 | /// Assigns a Gregorian date and time. |
140 | /// * year is from 0 to 9999. |
141 | /// * month is from 1 to 12. |
142 | /// * day is from 1 to 31. |
143 | /// * hour is from 0 to 23. |
144 | /// * minute is from 0 to 59. |
145 | /// * second is from 0 to 60. |
146 | /// * millisecond is from 0 to 999. |
147 | /// * microsecond is from 0 to 999. |
148 | /// Throws an InvalidArgumentException if an argument date is out of range. |
149 | |
150 | void swap(DateTime& dateTime); |
151 | /// Swaps the DateTime with another one. |
152 | |
153 | int year() const; |
154 | /// Returns the year. |
155 | |
156 | int month() const; |
157 | /// Returns the month (1 to 12). |
158 | |
159 | int week(int firstDayOfWeek = MONDAY) const; |
160 | /// Returns the week number within the year. |
161 | /// FirstDayOfWeek should be either SUNDAY (0) or MONDAY (1). |
162 | /// The returned week number will be from 0 to 53. Week number 1 is the week |
163 | /// containing January 4. This is in accordance to ISO 8601. |
164 | /// |
165 | /// The following example assumes that firstDayOfWeek is MONDAY. For 2005, which started |
166 | /// on a Saturday, week 1 will be the week starting on Monday, January 3. |
167 | /// January 1 and 2 will fall within week 0 (or the last week of the previous year). |
168 | /// |
169 | /// For 2007, which starts on a Monday, week 1 will be the week starting on Monday, January 1. |
170 | /// There will be no week 0 in 2007. |
171 | |
172 | int day() const; |
173 | /// Returns the day within the month (1 to 31). |
174 | |
175 | int dayOfWeek() const; |
176 | /// Returns the weekday (0 to 6, where |
177 | /// 0 = Sunday, 1 = Monday, ..., 6 = Saturday). |
178 | |
179 | int dayOfYear() const; |
180 | /// Returns the number of the day in the year. |
181 | /// January 1 is 1, February 1 is 32, etc. |
182 | |
183 | int hour() const; |
184 | /// Returns the hour (0 to 23). |
185 | |
186 | int hourAMPM() const; |
187 | /// Returns the hour (0 to 12). |
188 | |
189 | bool isAM() const; |
190 | /// Returns true if hour < 12; |
191 | |
192 | bool isPM() const; |
193 | /// Returns true if hour >= 12. |
194 | |
195 | int minute() const; |
196 | /// Returns the minute (0 to 59). |
197 | |
198 | int second() const; |
199 | /// Returns the second (0 to 59). |
200 | |
201 | int millisecond() const; |
202 | /// Returns the millisecond (0 to 999) |
203 | |
204 | int microsecond() const; |
205 | /// Returns the microsecond (0 to 999) |
206 | |
207 | double julianDay() const; |
208 | /// Returns the julian day for the date and time. |
209 | |
210 | Timestamp timestamp() const; |
211 | /// Returns the date and time expressed as a Timestamp. |
212 | |
213 | Timestamp::UtcTimeVal utcTime() const; |
214 | /// Returns the date and time expressed in UTC-based |
215 | /// time. UTC base time is midnight, October 15, 1582. |
216 | /// Resolution is 100 nanoseconds. |
217 | |
218 | bool operator == (const DateTime& dateTime) const; |
219 | bool operator != (const DateTime& dateTime) const; |
220 | bool operator < (const DateTime& dateTime) const; |
221 | bool operator <= (const DateTime& dateTime) const; |
222 | bool operator > (const DateTime& dateTime) const; |
223 | bool operator >= (const DateTime& dateTime) const; |
224 | |
225 | DateTime operator + (const Timespan& span) const; |
226 | DateTime operator - (const Timespan& span) const; |
227 | Timespan operator - (const DateTime& dateTime) const; |
228 | DateTime& operator += (const Timespan& span); |
229 | DateTime& operator -= (const Timespan& span); |
230 | |
231 | tm makeTM() const; |
232 | /// Converts DateTime to tm struct. |
233 | |
234 | void makeUTC(int tzd); |
235 | /// Converts a local time into UTC, by applying the given time zone differential. |
236 | |
237 | void makeLocal(int tzd); |
238 | /// Converts a UTC time into a local time, by applying the given time zone differential. |
239 | |
240 | static bool isLeapYear(int year); |
241 | /// Returns true if the given year is a leap year; |
242 | /// false otherwise. |
243 | |
244 | static int daysOfMonth(int year, int month); |
245 | /// Returns the number of days in the given month |
246 | /// and year. Month is from 1 to 12. |
247 | |
248 | static bool isValid(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); |
249 | /// Checks if the given date and time is valid |
250 | /// (all arguments are within a proper range). |
251 | /// |
252 | /// Returns true if all arguments are valid, false otherwise. |
253 | |
254 | protected: |
255 | static double toJulianDay(Timestamp::UtcTimeVal utcTime); |
256 | /// Computes the Julian day for an UTC time. |
257 | |
258 | static double toJulianDay(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int millisecond = 0, int microsecond = 0); |
259 | /// Computes the Julian day for a Gregorian calendar date and time. |
260 | /// See <http://vsg.cape.com/~pbaum/date/jdimp.htm>, section 2.3.1 for the algorithm. |
261 | |
262 | static Timestamp::UtcTimeVal toUtcTime(double julianDay); |
263 | /// Computes the UTC time for a Julian day. |
264 | |
265 | void computeGregorian(double julianDay); |
266 | /// Computes the Gregorian date for the given Julian day. |
267 | /// See <http://vsg.cape.com/~pbaum/date/injdimp.htm>, section 3.3.1 for the algorithm. |
268 | |
269 | void computeDaytime(); |
270 | /// Extracts the daytime (hours, minutes, seconds, etc.) from the stored utcTime. |
271 | |
272 | private: |
273 | void (short& lower, short& higher, short limit); |
274 | void normalize(); |
275 | ///utility functions used to correct the overflow in computeGregorian |
276 | |
277 | Timestamp::UtcTimeVal _utcTime; |
278 | short _year; |
279 | short _month; |
280 | short _day; |
281 | short _hour; |
282 | short _minute; |
283 | short _second; |
284 | short _millisecond; |
285 | short _microsecond; |
286 | }; |
287 | |
288 | |
289 | // |
290 | // inlines |
291 | // |
292 | |
293 | |
294 | inline double DateTime::toJulianDay(Timestamp::UtcTimeVal utcTime) |
295 | { |
296 | double utcDays = double(utcTime)/864000000000.0; |
297 | return utcDays + 2299160.5; // first day of Gregorian reform (Oct 15 1582) |
298 | } |
299 | |
300 | |
301 | inline Timestamp::UtcTimeVal DateTime::toUtcTime(double julianDay) |
302 | { |
303 | return Timestamp::UtcTimeVal((julianDay - 2299160.5)*864000000000.0); |
304 | } |
305 | |
306 | |
307 | inline Timestamp DateTime::timestamp() const |
308 | { |
309 | return Timestamp::fromUtcTime(_utcTime); |
310 | } |
311 | |
312 | |
313 | inline Timestamp::UtcTimeVal DateTime::utcTime() const |
314 | { |
315 | return _utcTime; |
316 | } |
317 | |
318 | |
319 | inline int DateTime::year() const |
320 | { |
321 | return _year; |
322 | } |
323 | |
324 | |
325 | inline int DateTime::month() const |
326 | { |
327 | return _month; |
328 | } |
329 | |
330 | |
331 | inline int DateTime::day() const |
332 | { |
333 | return _day; |
334 | } |
335 | |
336 | |
337 | inline int DateTime::hour() const |
338 | { |
339 | return _hour; |
340 | } |
341 | |
342 | |
343 | inline int DateTime::hourAMPM() const |
344 | { |
345 | if (_hour < 1) |
346 | return 12; |
347 | else if (_hour > 12) |
348 | return _hour - 12; |
349 | else |
350 | return _hour; |
351 | } |
352 | |
353 | |
354 | inline bool DateTime::isAM() const |
355 | { |
356 | return _hour < 12; |
357 | } |
358 | |
359 | |
360 | inline bool DateTime::isPM() const |
361 | { |
362 | return _hour >= 12; |
363 | } |
364 | |
365 | |
366 | inline int DateTime::minute() const |
367 | { |
368 | return _minute; |
369 | } |
370 | |
371 | |
372 | inline int DateTime::second() const |
373 | { |
374 | return _second; |
375 | } |
376 | |
377 | |
378 | inline int DateTime::millisecond() const |
379 | { |
380 | return _millisecond; |
381 | } |
382 | |
383 | |
384 | inline int DateTime::microsecond() const |
385 | { |
386 | return _microsecond; |
387 | } |
388 | |
389 | |
390 | inline bool DateTime::operator == (const DateTime& dateTime) const |
391 | { |
392 | return _utcTime == dateTime._utcTime; |
393 | } |
394 | |
395 | |
396 | inline bool DateTime::operator != (const DateTime& dateTime) const |
397 | { |
398 | return _utcTime != dateTime._utcTime; |
399 | } |
400 | |
401 | |
402 | inline bool DateTime::operator < (const DateTime& dateTime) const |
403 | { |
404 | return _utcTime < dateTime._utcTime; |
405 | } |
406 | |
407 | |
408 | inline bool DateTime::operator <= (const DateTime& dateTime) const |
409 | { |
410 | return _utcTime <= dateTime._utcTime; |
411 | } |
412 | |
413 | |
414 | inline bool DateTime::operator > (const DateTime& dateTime) const |
415 | { |
416 | return _utcTime > dateTime._utcTime; |
417 | } |
418 | |
419 | |
420 | inline bool DateTime::operator >= (const DateTime& dateTime) const |
421 | { |
422 | return _utcTime >= dateTime._utcTime; |
423 | } |
424 | |
425 | |
426 | inline bool DateTime::isLeapYear(int year) |
427 | { |
428 | return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); |
429 | } |
430 | |
431 | |
432 | inline void swap(DateTime& d1, DateTime& d2) |
433 | { |
434 | d1.swap(d2); |
435 | } |
436 | |
437 | |
438 | } // namespace Poco |
439 | |
440 | |
441 | #endif // Foundation_DateTime_INCLUDED |
442 | |