1 | // |
---|
2 | // DateTime.cpp |
---|
3 | // |
---|
4 | // $Id: //poco/1.3/Foundation/src/DateTime.cpp#4 $ |
---|
5 | // |
---|
6 | // Library: Foundation |
---|
7 | // Package: DateTime |
---|
8 | // Module: DateTime |
---|
9 | // |
---|
10 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
---|
11 | // and Contributors. |
---|
12 | // |
---|
13 | // Permission is hereby granted, free of charge, to any person or organization |
---|
14 | // obtaining a copy of the software and accompanying documentation covered by |
---|
15 | // this license (the "Software") to use, reproduce, display, distribute, |
---|
16 | // execute, and transmit the Software, and to prepare derivative works of the |
---|
17 | // Software, and to permit third-parties to whom the Software is furnished to |
---|
18 | // do so, all subject to the following: |
---|
19 | // |
---|
20 | // The copyright notices in the Software and this entire statement, including |
---|
21 | // the above license grant, this restriction and the following disclaimer, |
---|
22 | // must be included in all copies of the Software, in whole or in part, and |
---|
23 | // all derivative works of the Software, unless such copies or derivative |
---|
24 | // works are solely in the form of machine-executable object code generated by |
---|
25 | // a source language processor. |
---|
26 | // |
---|
27 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
---|
28 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
---|
29 | // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT |
---|
30 | // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE |
---|
31 | // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, |
---|
32 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
---|
33 | // DEALINGS IN THE SOFTWARE. |
---|
34 | // |
---|
35 | |
---|
36 | |
---|
37 | #include "Poco/DateTime.h" |
---|
38 | #include "Poco/Timespan.h" |
---|
39 | #include <algorithm> |
---|
40 | #include <cmath> |
---|
41 | |
---|
42 | |
---|
43 | namespace Poco { |
---|
44 | |
---|
45 | |
---|
46 | inline double DateTime::toJulianDay(Timestamp::UtcTimeVal utcTime) |
---|
47 | { |
---|
48 | double utcDays = double(utcTime)/864000000000.0; |
---|
49 | return utcDays + 2299160.5; // first day of Gregorian reform (Oct 15 1582) |
---|
50 | } |
---|
51 | |
---|
52 | |
---|
53 | inline Timestamp::UtcTimeVal DateTime::toUtcTime(double julianDay) |
---|
54 | { |
---|
55 | return Timestamp::UtcTimeVal((julianDay - 2299160.5)*864000000000.0); |
---|
56 | } |
---|
57 | |
---|
58 | |
---|
59 | DateTime::DateTime() |
---|
60 | { |
---|
61 | Timestamp now; |
---|
62 | _utcTime = now.utcTime(); |
---|
63 | computeGregorian(julianDay()); |
---|
64 | computeDaytime(); |
---|
65 | } |
---|
66 | |
---|
67 | |
---|
68 | DateTime::DateTime(const Timestamp& timestamp): |
---|
69 | _utcTime(timestamp.utcTime()) |
---|
70 | { |
---|
71 | computeGregorian(julianDay()); |
---|
72 | computeDaytime(); |
---|
73 | } |
---|
74 | |
---|
75 | |
---|
76 | DateTime::DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond): |
---|
77 | _year(year), |
---|
78 | _month(month), |
---|
79 | _day(day), |
---|
80 | _hour(hour), |
---|
81 | _minute(minute), |
---|
82 | _second(second), |
---|
83 | _millisecond(millisecond), |
---|
84 | _microsecond(microsecond) |
---|
85 | { |
---|
86 | poco_assert (year >= 0 && year <= 9999); |
---|
87 | poco_assert (month >= 1 && month <= 12); |
---|
88 | poco_assert (day >= 1 && day <= daysOfMonth(year, month)); |
---|
89 | poco_assert (hour >= 0 && hour <= 23); |
---|
90 | poco_assert (minute >= 0 && minute <= 59); |
---|
91 | poco_assert (second >= 0 && second <= 59); |
---|
92 | poco_assert (millisecond >= 0 && millisecond <= 999); |
---|
93 | poco_assert (microsecond >= 0 && microsecond <= 999); |
---|
94 | |
---|
95 | _utcTime = toUtcTime(toJulianDay(year, month, day)) + 10*(hour*Timespan::HOURS + minute*Timespan::MINUTES + second*Timespan::SECONDS + millisecond*Timespan::MILLISECONDS + microsecond); |
---|
96 | } |
---|
97 | |
---|
98 | |
---|
99 | DateTime::DateTime(double julianDay): |
---|
100 | _utcTime(toUtcTime(julianDay)) |
---|
101 | { |
---|
102 | computeGregorian(julianDay); |
---|
103 | } |
---|
104 | |
---|
105 | |
---|
106 | DateTime::DateTime(Timestamp::UtcTimeVal utcTime, Timestamp::TimeDiff diff): |
---|
107 | _utcTime(utcTime + diff*10) |
---|
108 | { |
---|
109 | computeGregorian(julianDay()); |
---|
110 | computeDaytime(); |
---|
111 | } |
---|
112 | |
---|
113 | |
---|
114 | DateTime::DateTime(const DateTime& dateTime): |
---|
115 | _utcTime(dateTime._utcTime), |
---|
116 | _year(dateTime._year), |
---|
117 | _month(dateTime._month), |
---|
118 | _day(dateTime._day), |
---|
119 | _hour(dateTime._hour), |
---|
120 | _minute(dateTime._minute), |
---|
121 | _second(dateTime._second), |
---|
122 | _millisecond(dateTime._millisecond), |
---|
123 | _microsecond(dateTime._microsecond) |
---|
124 | { |
---|
125 | } |
---|
126 | |
---|
127 | |
---|
128 | DateTime::~DateTime() |
---|
129 | { |
---|
130 | } |
---|
131 | |
---|
132 | |
---|
133 | DateTime& DateTime::operator = (const DateTime& dateTime) |
---|
134 | { |
---|
135 | if (&dateTime != this) |
---|
136 | { |
---|
137 | _utcTime = dateTime._utcTime; |
---|
138 | _year = dateTime._year; |
---|
139 | _month = dateTime._month; |
---|
140 | _day = dateTime._day; |
---|
141 | _hour = dateTime._hour; |
---|
142 | _minute = dateTime._minute; |
---|
143 | _second = dateTime._second; |
---|
144 | _millisecond = dateTime._millisecond; |
---|
145 | _microsecond = dateTime._microsecond; |
---|
146 | } |
---|
147 | return *this; |
---|
148 | } |
---|
149 | |
---|
150 | |
---|
151 | DateTime& DateTime::operator = (const Timestamp& timestamp) |
---|
152 | { |
---|
153 | _utcTime = timestamp.utcTime(); |
---|
154 | computeGregorian(julianDay()); |
---|
155 | computeDaytime(); |
---|
156 | return *this; |
---|
157 | } |
---|
158 | |
---|
159 | |
---|
160 | DateTime& DateTime::operator = (double julianDay) |
---|
161 | { |
---|
162 | _utcTime = toUtcTime(julianDay); |
---|
163 | computeGregorian(julianDay); |
---|
164 | return *this; |
---|
165 | } |
---|
166 | |
---|
167 | |
---|
168 | DateTime& DateTime::assign(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond) |
---|
169 | { |
---|
170 | poco_assert (year >= 0 && year <= 9999); |
---|
171 | poco_assert (month >= 1 && month <= 12); |
---|
172 | poco_assert (day >= 1 && day <= daysOfMonth(year, month)); |
---|
173 | poco_assert (hour >= 0 && hour <= 23); |
---|
174 | poco_assert (minute >= 0 && minute <= 59); |
---|
175 | poco_assert (second >= 0 && second <= 59); |
---|
176 | poco_assert (millisecond >= 0 && millisecond <= 999); |
---|
177 | poco_assert (microsecond >= 0 && microsecond <= 999); |
---|
178 | |
---|
179 | _utcTime = toUtcTime(toJulianDay(year, month, day)) + 10*(hour*Timespan::HOURS + minute*Timespan::MINUTES + second*Timespan::SECONDS + millisecond*Timespan::MILLISECONDS + microsecond); |
---|
180 | _year = year; |
---|
181 | _month = month; |
---|
182 | _day = day; |
---|
183 | _hour = hour; |
---|
184 | _minute = minute; |
---|
185 | _second = second; |
---|
186 | _millisecond = millisecond; |
---|
187 | _microsecond = microsecond; |
---|
188 | |
---|
189 | return *this; |
---|
190 | } |
---|
191 | |
---|
192 | |
---|
193 | void DateTime::swap(DateTime& dateTime) |
---|
194 | { |
---|
195 | std::swap(_utcTime, dateTime._utcTime); |
---|
196 | std::swap(_year, dateTime._year); |
---|
197 | std::swap(_month, dateTime._month); |
---|
198 | std::swap(_day, dateTime._day); |
---|
199 | std::swap(_hour, dateTime._hour); |
---|
200 | std::swap(_minute, dateTime._minute); |
---|
201 | std::swap(_second, dateTime._second); |
---|
202 | std::swap(_millisecond, dateTime._millisecond); |
---|
203 | std::swap(_microsecond, dateTime._microsecond); |
---|
204 | } |
---|
205 | |
---|
206 | |
---|
207 | int DateTime::dayOfWeek() const |
---|
208 | { |
---|
209 | return int((std::floor(julianDay() + 1.5))) % 7; |
---|
210 | } |
---|
211 | |
---|
212 | |
---|
213 | int DateTime::dayOfYear() const |
---|
214 | { |
---|
215 | int doy = 0; |
---|
216 | for (int month = 1; month < _month; ++month) |
---|
217 | doy += daysOfMonth(_year, month); |
---|
218 | doy += _day; |
---|
219 | return doy; |
---|
220 | } |
---|
221 | |
---|
222 | |
---|
223 | int DateTime::daysOfMonth(int year, int month) |
---|
224 | { |
---|
225 | poco_assert (month >= 1 && month <= 12); |
---|
226 | |
---|
227 | static int daysOfMonthTable[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
---|
228 | |
---|
229 | if (month == 2 && isLeapYear(year)) |
---|
230 | return 29; |
---|
231 | else |
---|
232 | return daysOfMonthTable[month]; |
---|
233 | } |
---|
234 | |
---|
235 | |
---|
236 | bool DateTime::isValid(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond) |
---|
237 | { |
---|
238 | return |
---|
239 | (year >= 0 && year <= 9999) && |
---|
240 | (month >= 1 && month <= 12) && |
---|
241 | (day >= 1 && day <= daysOfMonth(year, month)) && |
---|
242 | (hour >= 0 && hour <= 23) && |
---|
243 | (minute >= 0 && minute <= 59) && |
---|
244 | (second >= 0 && second <= 59) && |
---|
245 | (millisecond >= 0 && millisecond <= 999) && |
---|
246 | (microsecond >= 0 && microsecond <= 999); |
---|
247 | } |
---|
248 | |
---|
249 | |
---|
250 | int DateTime::week(int firstDayOfWeek) const |
---|
251 | { |
---|
252 | poco_assert (firstDayOfWeek >= 0 && firstDayOfWeek <= 6); |
---|
253 | |
---|
254 | /// find the first firstDayOfWeek. |
---|
255 | int baseDay = 1; |
---|
256 | while (DateTime(_year, 1, baseDay).dayOfWeek() != firstDayOfWeek) ++baseDay; |
---|
257 | |
---|
258 | int doy = dayOfYear(); |
---|
259 | int offs = baseDay <= 4 ? 0 : 1; |
---|
260 | if (doy < baseDay) |
---|
261 | return offs; |
---|
262 | else |
---|
263 | return (doy - baseDay)/7 + 1 + offs; |
---|
264 | } |
---|
265 | |
---|
266 | |
---|
267 | double DateTime::julianDay() const |
---|
268 | { |
---|
269 | return toJulianDay(_utcTime); |
---|
270 | } |
---|
271 | |
---|
272 | |
---|
273 | DateTime DateTime::operator + (const Timespan& span) const |
---|
274 | { |
---|
275 | return DateTime(_utcTime, span.totalMicroseconds()); |
---|
276 | } |
---|
277 | |
---|
278 | |
---|
279 | DateTime DateTime::operator - (const Timespan& span) const |
---|
280 | { |
---|
281 | return DateTime(_utcTime, -span.totalMicroseconds()); |
---|
282 | } |
---|
283 | |
---|
284 | |
---|
285 | Timespan DateTime::operator - (const DateTime& dateTime) const |
---|
286 | { |
---|
287 | return Timespan((_utcTime - dateTime._utcTime)/10); |
---|
288 | } |
---|
289 | |
---|
290 | |
---|
291 | DateTime& DateTime::operator += (const Timespan& span) |
---|
292 | { |
---|
293 | _utcTime += span.totalMicroseconds()*10; |
---|
294 | computeGregorian(julianDay()); |
---|
295 | computeDaytime(); |
---|
296 | return *this; |
---|
297 | } |
---|
298 | |
---|
299 | |
---|
300 | DateTime& DateTime::operator -= (const Timespan& span) |
---|
301 | { |
---|
302 | _utcTime -= span.totalMicroseconds()*10; |
---|
303 | computeGregorian(julianDay()); |
---|
304 | computeDaytime(); |
---|
305 | return *this; |
---|
306 | } |
---|
307 | |
---|
308 | |
---|
309 | void DateTime::makeUTC(int tzd) |
---|
310 | { |
---|
311 | operator -= (Timespan(((Timestamp::TimeDiff) tzd)*Timespan::SECONDS)); |
---|
312 | } |
---|
313 | |
---|
314 | |
---|
315 | void DateTime::makeLocal(int tzd) |
---|
316 | { |
---|
317 | operator += (Timespan(((Timestamp::TimeDiff) tzd)*Timespan::SECONDS)); |
---|
318 | } |
---|
319 | |
---|
320 | |
---|
321 | double DateTime::toJulianDay(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond) |
---|
322 | { |
---|
323 | // lookup table for (153*month - 457)/5 - note that 3 <= month <= 14. |
---|
324 | static int lookup[] = {-91, -60, -30, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337}; |
---|
325 | |
---|
326 | // day to double |
---|
327 | double dday = double(day) + ((double((hour*60 + minute)*60 + second)*1000 + millisecond)*1000 + microsecond)/86400000000.0; |
---|
328 | if (month < 3) |
---|
329 | { |
---|
330 | month += 12; |
---|
331 | --year; |
---|
332 | } |
---|
333 | double dyear = double(year); |
---|
334 | return dday + lookup[month] + 365*year + std::floor(dyear/4) - std::floor(dyear/100) + std::floor(dyear/400) + 1721118.5; |
---|
335 | } |
---|
336 | |
---|
337 | |
---|
338 | void DateTime::checkLimit(short& lower, short& higher, short limit) |
---|
339 | { |
---|
340 | if (lower >= limit) |
---|
341 | { |
---|
342 | higher += short(lower / limit); |
---|
343 | lower = short(lower % limit); |
---|
344 | } |
---|
345 | } |
---|
346 | |
---|
347 | |
---|
348 | void DateTime::normalize() |
---|
349 | { |
---|
350 | checkLimit(_microsecond, _millisecond, 1000); |
---|
351 | checkLimit(_millisecond, _second, 1000); |
---|
352 | checkLimit(_second, _minute, 60); |
---|
353 | checkLimit(_minute, _hour, 60); |
---|
354 | checkLimit(_hour, _day, 24); |
---|
355 | |
---|
356 | if (_day > daysOfMonth(_year, _month)) |
---|
357 | { |
---|
358 | _day -= daysOfMonth(_year, _month); |
---|
359 | if (++_month > 12) |
---|
360 | { |
---|
361 | ++_year; |
---|
362 | _month -= 12; |
---|
363 | } |
---|
364 | } |
---|
365 | } |
---|
366 | |
---|
367 | |
---|
368 | void DateTime::computeGregorian(double julianDay) |
---|
369 | { |
---|
370 | double z = std::floor(julianDay - 1721118.5); |
---|
371 | double r = julianDay - 1721118.5 - z; |
---|
372 | double g = z - 0.25; |
---|
373 | double a = std::floor(g / 36524.25); |
---|
374 | double b = a - std::floor(a/4); |
---|
375 | _year = short(std::floor((b + g)/365.25)); |
---|
376 | double c = b + z - std::floor(365.25*_year); |
---|
377 | _month = short(std::floor((5*c + 456)/153)); |
---|
378 | double dday = c - std::floor((153.0*_month - 457)/5) + r; |
---|
379 | _day = short(dday); |
---|
380 | if (_month > 12) |
---|
381 | { |
---|
382 | ++_year; |
---|
383 | _month -= 12; |
---|
384 | } |
---|
385 | r *= 24; |
---|
386 | _hour = short(std::floor(r)); |
---|
387 | r -= std::floor(r); |
---|
388 | r *= 60; |
---|
389 | _minute = short(std::floor(r)); |
---|
390 | r -= std::floor(r); |
---|
391 | r *= 60; |
---|
392 | _second = short(std::floor(r)); |
---|
393 | r -= std::floor(r); |
---|
394 | r *= 1000; |
---|
395 | _millisecond = short(std::floor(r)); |
---|
396 | r -= std::floor(r); |
---|
397 | r *= 1000; |
---|
398 | _microsecond = short(r + 0.5); |
---|
399 | |
---|
400 | normalize(); |
---|
401 | |
---|
402 | poco_assert_dbg (_month >= 1 && _month <= 12); |
---|
403 | poco_assert_dbg (_day >= 1 && _day <= daysOfMonth(_year, _month)); |
---|
404 | poco_assert_dbg (_hour >= 0 && _hour <= 23); |
---|
405 | poco_assert_dbg (_minute >= 0 && _minute <= 59); |
---|
406 | poco_assert_dbg (_second >= 0 && _second <= 59); |
---|
407 | poco_assert_dbg (_millisecond >= 0 && _millisecond <= 999); |
---|
408 | poco_assert_dbg (_microsecond >= 0 && _microsecond <= 999); |
---|
409 | } |
---|
410 | |
---|
411 | |
---|
412 | void DateTime::computeDaytime() |
---|
413 | { |
---|
414 | Timespan span(_utcTime/10); |
---|
415 | _hour = span.hours(); |
---|
416 | _minute = span.minutes(); |
---|
417 | _second = span.seconds(); |
---|
418 | _millisecond = span.milliseconds(); |
---|
419 | _microsecond = span.microseconds(); |
---|
420 | } |
---|
421 | |
---|
422 | |
---|
423 | } // namespace Poco |
---|