1 | // |
2 | // LocalDateTime.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: DateTime |
6 | // Module: LocalDateTime |
7 | // |
8 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/LocalDateTime.h" |
16 | #include "Poco/Timezone.h" |
17 | #include "Poco/Timespan.h" |
18 | #include "Poco/Exception.h" |
19 | #include <algorithm> |
20 | #include <time.h> |
21 | #if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 |
22 | #include "wce_time.h" |
23 | #endif |
24 | |
25 | |
26 | namespace Poco { |
27 | |
28 | |
29 | LocalDateTime::LocalDateTime() |
30 | { |
31 | determineTzd(true); |
32 | } |
33 | |
34 | |
35 | LocalDateTime::LocalDateTime(int otherYear, int otherMonth, int otherDay, int otherHour, int otherMinute, int otherSecond, int otherMillisecond, int otherMicrosecond): |
36 | _dateTime(otherYear, otherMonth, otherDay, otherHour, otherMinute, otherSecond, otherMillisecond, otherMicrosecond) |
37 | { |
38 | determineTzd(); |
39 | } |
40 | |
41 | |
42 | LocalDateTime::LocalDateTime(int otherTzd, int otherYear, int otherMonth, int otherDay, int otherHour, int otherMinute, int otherSecond, int otherMillisecond, int otherMicrosecond): |
43 | _dateTime(otherYear, otherMonth, otherDay, otherHour, otherMinute, otherSecond, otherMillisecond, otherMicrosecond), |
44 | _tzd(otherTzd) |
45 | { |
46 | } |
47 | |
48 | |
49 | LocalDateTime::LocalDateTime(double otherJulianDay): |
50 | _dateTime(otherJulianDay) |
51 | { |
52 | determineTzd(true); |
53 | } |
54 | |
55 | |
56 | LocalDateTime::LocalDateTime(int otherTzd, double otherJulianDay): |
57 | _dateTime(otherJulianDay), |
58 | _tzd(otherTzd) |
59 | { |
60 | adjustForTzd(); |
61 | } |
62 | |
63 | |
64 | LocalDateTime::LocalDateTime(const DateTime& dateTime): |
65 | _dateTime(dateTime) |
66 | { |
67 | determineTzd(true); |
68 | } |
69 | |
70 | |
71 | LocalDateTime::LocalDateTime(int otherTzd, const DateTime& otherDateTime): |
72 | _dateTime(otherDateTime), |
73 | _tzd(otherTzd) |
74 | { |
75 | adjustForTzd(); |
76 | } |
77 | |
78 | |
79 | LocalDateTime::LocalDateTime(int otherTzd, const DateTime& otherDateTime, bool adjust): |
80 | _dateTime(otherDateTime), |
81 | _tzd(otherTzd) |
82 | { |
83 | if (adjust) |
84 | adjustForTzd(); |
85 | } |
86 | |
87 | |
88 | LocalDateTime::LocalDateTime(const LocalDateTime& dateTime): |
89 | _dateTime(dateTime._dateTime), |
90 | _tzd(dateTime._tzd) |
91 | { |
92 | } |
93 | |
94 | |
95 | LocalDateTime::LocalDateTime(Timestamp::UtcTimeVal utcTimeVal, Timestamp::TimeDiff diff, int otherTzd): |
96 | _dateTime(utcTimeVal, diff), |
97 | _tzd(otherTzd) |
98 | { |
99 | adjustForTzd(); |
100 | } |
101 | |
102 | |
103 | LocalDateTime::~LocalDateTime() |
104 | { |
105 | } |
106 | |
107 | |
108 | LocalDateTime& LocalDateTime::operator = (const LocalDateTime& dateTime) |
109 | { |
110 | if (&dateTime != this) |
111 | { |
112 | _dateTime = dateTime._dateTime; |
113 | _tzd = dateTime._tzd; |
114 | } |
115 | return *this; |
116 | } |
117 | |
118 | |
119 | LocalDateTime& LocalDateTime::operator = (const Timestamp& otherTimestamp) |
120 | { |
121 | if (otherTimestamp != timestamp()) |
122 | { |
123 | _dateTime = otherTimestamp; |
124 | determineTzd(true); |
125 | } |
126 | return *this; |
127 | } |
128 | |
129 | |
130 | LocalDateTime& LocalDateTime::operator = (double otherJulianDay) |
131 | { |
132 | _dateTime = otherJulianDay; |
133 | determineTzd(true); |
134 | return *this; |
135 | } |
136 | |
137 | |
138 | LocalDateTime& LocalDateTime::assign(int otherYear, int otherMonth, int otherDay, int otherHour, int otherMinute, int otherSecond, int otherMillisecond, int otherMicroseconds) |
139 | { |
140 | _dateTime.assign(otherYear, otherMonth, otherDay, otherHour, otherMinute, otherSecond, otherMillisecond, otherMicroseconds); |
141 | determineTzd(false); |
142 | return *this; |
143 | } |
144 | |
145 | |
146 | LocalDateTime& LocalDateTime::assign(int otherTzd, int otherYear, int otherMonth, int otherDay, int otherHour, int otherMinute, int otherSecond, int otherMillisecond, int otherMicroseconds) |
147 | { |
148 | _dateTime.assign(otherYear, otherMonth, otherDay, otherHour, otherMinute, otherSecond, otherMillisecond, otherMicroseconds); |
149 | _tzd = otherTzd; |
150 | return *this; |
151 | } |
152 | |
153 | |
154 | LocalDateTime& LocalDateTime::assign(int otherTzd, double otherJulianDay) |
155 | { |
156 | _tzd = otherTzd; |
157 | _dateTime = otherJulianDay; |
158 | adjustForTzd(); |
159 | return *this; |
160 | } |
161 | |
162 | |
163 | void LocalDateTime::swap(LocalDateTime& dateTime) |
164 | { |
165 | _dateTime.swap(dateTime._dateTime); |
166 | std::swap(_tzd, dateTime._tzd); |
167 | } |
168 | |
169 | |
170 | DateTime LocalDateTime::utc() const |
171 | { |
172 | return DateTime(_dateTime.utcTime(), -((Timestamp::TimeDiff) _tzd)*Timespan::SECONDS); |
173 | } |
174 | |
175 | |
176 | bool LocalDateTime::operator == (const LocalDateTime& dateTime) const |
177 | { |
178 | return utcTime() == dateTime.utcTime(); |
179 | } |
180 | |
181 | |
182 | bool LocalDateTime::operator != (const LocalDateTime& dateTime) const |
183 | { |
184 | return utcTime() != dateTime.utcTime(); |
185 | } |
186 | |
187 | |
188 | bool LocalDateTime::operator < (const LocalDateTime& dateTime) const |
189 | { |
190 | return utcTime() < dateTime.utcTime(); |
191 | } |
192 | |
193 | |
194 | bool LocalDateTime::operator <= (const LocalDateTime& dateTime) const |
195 | { |
196 | return utcTime() <= dateTime.utcTime(); |
197 | } |
198 | |
199 | |
200 | bool LocalDateTime::operator > (const LocalDateTime& dateTime) const |
201 | { |
202 | return utcTime() > dateTime.utcTime(); |
203 | } |
204 | |
205 | |
206 | bool LocalDateTime::operator >= (const LocalDateTime& dateTime) const |
207 | { |
208 | return utcTime() >= dateTime.utcTime(); |
209 | } |
210 | |
211 | |
212 | LocalDateTime LocalDateTime::operator + (const Timespan& span) const |
213 | { |
214 | // First calculate the adjusted UTC time, then calculate the |
215 | // locally adjusted time by constructing a new LocalDateTime. |
216 | DateTime tmp(utcTime(), span.totalMicroseconds()); |
217 | return LocalDateTime(tmp); |
218 | } |
219 | |
220 | |
221 | LocalDateTime LocalDateTime::operator - (const Timespan& span) const |
222 | { |
223 | // First calculate the adjusted UTC time, then calculate the |
224 | // locally adjusted time by constructing a new LocalDateTime. |
225 | DateTime tmp(utcTime(), -span.totalMicroseconds()); |
226 | return LocalDateTime(tmp); |
227 | } |
228 | |
229 | |
230 | Timespan LocalDateTime::operator - (const LocalDateTime& dateTime) const |
231 | { |
232 | return Timespan((utcTime() - dateTime.utcTime())/10); |
233 | } |
234 | |
235 | |
236 | LocalDateTime& LocalDateTime::operator += (const Timespan& span) |
237 | { |
238 | // Use the same trick as in operator+. Create a UTC time, adjust |
239 | // it for the span, and convert back to LocalDateTime. This will |
240 | // recalculate the tzd correctly in the case where the addition |
241 | // crosses a DST boundary. |
242 | *this = DateTime(utcTime(), span.totalMicroseconds()); |
243 | return *this; |
244 | } |
245 | |
246 | |
247 | LocalDateTime& LocalDateTime::operator -= (const Timespan& span) |
248 | { |
249 | // Use the same trick as in operator-. Create a UTC time, adjust |
250 | // it for the span, and convert back to LocalDateTime. This will |
251 | // recalculate the tzd correctly in the case where the subtraction |
252 | // crosses a DST boundary. |
253 | *this = DateTime(utcTime(), -span.totalMicroseconds()); |
254 | return *this; |
255 | } |
256 | |
257 | |
258 | void LocalDateTime::determineTzd(bool adjust) |
259 | { |
260 | if (adjust) |
261 | { |
262 | std::time_t epochTime = _dateTime.timestamp().epochTime(); |
263 | #if defined(_WIN32) || defined(POCO_NO_POSIX_TSF) |
264 | #if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 |
265 | std::tm* broken = wceex_localtime(&epochTime); |
266 | #else |
267 | std::tm* broken = std::localtime(&epochTime); |
268 | #endif |
269 | if (!broken) throw Poco::SystemException("cannot get local time" ); |
270 | _tzd = (Timezone::utcOffset() + ((broken->tm_isdst == 1) ? 3600 : 0)); |
271 | #else |
272 | std::tm broken; |
273 | #if defined(POCO_VXWORKS) |
274 | if (localtime_r(&epochTime, &broken) != OK) |
275 | throw Poco::SystemException("cannot get local time" ); |
276 | #else |
277 | if (!localtime_r(&epochTime, &broken)) |
278 | throw Poco::SystemException("cannot get local time" ); |
279 | #endif |
280 | _tzd = (Timezone::utcOffset() + ((broken.tm_isdst == 1) ? 3600 : 0)); |
281 | #endif |
282 | adjustForTzd(); |
283 | } |
284 | else |
285 | { |
286 | int dst; |
287 | dstOffset(dst); |
288 | _tzd = (Timezone::utcOffset() + dst); |
289 | } |
290 | } |
291 | |
292 | |
293 | std::time_t LocalDateTime::dstOffset(int& rDstOffset) const |
294 | { |
295 | std::time_t local; |
296 | std::tm broken; |
297 | |
298 | broken.tm_year = (_dateTime.year() - 1900); |
299 | broken.tm_mon = (_dateTime.month() - 1); |
300 | broken.tm_mday = _dateTime.day(); |
301 | broken.tm_hour = _dateTime.hour(); |
302 | broken.tm_min = _dateTime.minute(); |
303 | broken.tm_sec = _dateTime.second(); |
304 | broken.tm_isdst = -1; |
305 | #if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 |
306 | local = wceex_mktime(&broken); |
307 | #else |
308 | local = std::mktime(&broken); |
309 | #endif |
310 | |
311 | rDstOffset = (broken.tm_isdst == 1) ? 3600 : 0; |
312 | return local; |
313 | } |
314 | |
315 | |
316 | } // namespace Poco |
317 | |
318 | |