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