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
26namespace Poco {
27
28
29LocalDateTime::LocalDateTime()
30{
31 determineTzd(true);
32}
33
34
35LocalDateTime::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
42LocalDateTime::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
49LocalDateTime::LocalDateTime(double otherJulianDay):
50 _dateTime(otherJulianDay)
51{
52 determineTzd(true);
53}
54
55
56LocalDateTime::LocalDateTime(int otherTzd, double otherJulianDay):
57 _dateTime(otherJulianDay),
58 _tzd(otherTzd)
59{
60 adjustForTzd();
61}
62
63
64LocalDateTime::LocalDateTime(const DateTime& dateTime):
65 _dateTime(dateTime)
66{
67 determineTzd(true);
68}
69
70
71LocalDateTime::LocalDateTime(int otherTzd, const DateTime& otherDateTime):
72 _dateTime(otherDateTime),
73 _tzd(otherTzd)
74{
75 adjustForTzd();
76}
77
78
79LocalDateTime::LocalDateTime(int otherTzd, const DateTime& otherDateTime, bool adjust):
80 _dateTime(otherDateTime),
81 _tzd(otherTzd)
82{
83 if (adjust)
84 adjustForTzd();
85}
86
87
88LocalDateTime::LocalDateTime(const LocalDateTime& dateTime):
89 _dateTime(dateTime._dateTime),
90 _tzd(dateTime._tzd)
91{
92}
93
94
95LocalDateTime::LocalDateTime(Timestamp::UtcTimeVal utcTimeVal, Timestamp::TimeDiff diff, int otherTzd):
96 _dateTime(utcTimeVal, diff),
97 _tzd(otherTzd)
98{
99 adjustForTzd();
100}
101
102
103LocalDateTime::~LocalDateTime()
104{
105}
106
107
108LocalDateTime& 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
119LocalDateTime& LocalDateTime::operator = (const Timestamp& otherTimestamp)
120{
121 if (otherTimestamp != timestamp())
122 {
123 _dateTime = otherTimestamp;
124 determineTzd(true);
125 }
126 return *this;
127}
128
129
130LocalDateTime& LocalDateTime::operator = (double otherJulianDay)
131{
132 _dateTime = otherJulianDay;
133 determineTzd(true);
134 return *this;
135}
136
137
138LocalDateTime& 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
146LocalDateTime& 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
154LocalDateTime& LocalDateTime::assign(int otherTzd, double otherJulianDay)
155{
156 _tzd = otherTzd;
157 _dateTime = otherJulianDay;
158 adjustForTzd();
159 return *this;
160}
161
162
163void LocalDateTime::swap(LocalDateTime& dateTime)
164{
165 _dateTime.swap(dateTime._dateTime);
166 std::swap(_tzd, dateTime._tzd);
167}
168
169
170DateTime LocalDateTime::utc() const
171{
172 return DateTime(_dateTime.utcTime(), -((Timestamp::TimeDiff) _tzd)*Timespan::SECONDS);
173}
174
175
176bool LocalDateTime::operator == (const LocalDateTime& dateTime) const
177{
178 return utcTime() == dateTime.utcTime();
179}
180
181
182bool LocalDateTime::operator != (const LocalDateTime& dateTime) const
183{
184 return utcTime() != dateTime.utcTime();
185}
186
187
188bool LocalDateTime::operator < (const LocalDateTime& dateTime) const
189{
190 return utcTime() < dateTime.utcTime();
191}
192
193
194bool LocalDateTime::operator <= (const LocalDateTime& dateTime) const
195{
196 return utcTime() <= dateTime.utcTime();
197}
198
199
200bool LocalDateTime::operator > (const LocalDateTime& dateTime) const
201{
202 return utcTime() > dateTime.utcTime();
203}
204
205
206bool LocalDateTime::operator >= (const LocalDateTime& dateTime) const
207{
208 return utcTime() >= dateTime.utcTime();
209}
210
211
212LocalDateTime 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
221LocalDateTime 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
230Timespan LocalDateTime::operator - (const LocalDateTime& dateTime) const
231{
232 return Timespan((utcTime() - dateTime.utcTime())/10);
233}
234
235
236LocalDateTime& 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
247LocalDateTime& 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
258void 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
293std::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