1//
2// Timestamp.cpp
3//
4// Library: Foundation
5// Package: DateTime
6// Module: Timestamp
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/Timestamp.h"
16#include "Poco/Timespan.h"
17#include "Poco/Exception.h"
18#if defined(POCO_OS_FAMILY_WINDOWS)
19#include "Poco/UnWindows.h"
20#if defined(_WIN32_WCE)
21#include <cmath>
22#endif
23#endif
24#include <algorithm>
25#undef min
26#undef max
27#include <limits>
28#include <chrono>
29
30
31#ifndef POCO_HAVE_CLOCK_GETTIME
32 #if (defined(_POSIX_TIMERS) && defined(CLOCK_REALTIME)) || defined(POCO_VXWORKS) || defined(__QNX__)
33 #ifndef __APPLE__ // See GitHub issue #1453 - not available before Mac OS 10.12/iOS 10
34 #define POCO_HAVE_CLOCK_GETTIME
35 #endif
36 #endif
37#endif
38
39
40#if defined(_WIN32_WCE) && defined(POCO_WINCE_TIMESTAMP_HACK)
41
42
43//
44// See <http://community.opennetcf.com/articles/cf/archive/2007/11/20/getting-a-millisecond-resolution-datetime-under-windows-ce.aspx>
45// for an explanation of the following code.
46//
47// In short: Windows CE system time in most cases only has a resolution of one second.
48// But we want millisecond resolution.
49//
50
51
52namespace {
53
54
55class TickOffset
56{
57public:
58 TickOffset()
59 {
60 SYSTEMTIME st1, st2;
61 std::memset(&st1, 0, sizeof(SYSTEMTIME));
62 std::memset(&st2, 0, sizeof(SYSTEMTIME));
63 GetSystemTime(&st1);
64 while (true)
65 {
66 GetSystemTime(&st2);
67
68 // wait for a rollover
69 if (st1.wSecond != st2.wSecond)
70 {
71 _offset = GetTickCount() % 1000;
72 break;
73 }
74 }
75 }
76
77 void calibrate(int seconds)
78 {
79 SYSTEMTIME st1, st2;
80 systemTime(&st1);
81
82 WORD s = st1.wSecond;
83 int sum = 0;
84 int remaining = seconds;
85 while (remaining > 0)
86 {
87 systemTime(&st2);
88 WORD s2 = st2.wSecond;
89
90 if (s != s2)
91 {
92 remaining--;
93 // store the offset from zero
94 sum += (st2.wMilliseconds > 500) ? (st2.wMilliseconds - 1000) : st2.wMilliseconds;
95 s = st2.wSecond;
96 }
97 }
98
99 // adjust the offset by the average deviation from zero (round to the integer farthest from zero)
100 if (sum < 0)
101 _offset += (int) std::floor(sum / (float)seconds);
102 else
103 _offset += (int) std::ceil(sum / (float)seconds);
104 }
105
106 void systemTime(SYSTEMTIME* pST)
107 {
108 std::memset(pST, 0, sizeof(SYSTEMTIME));
109
110 WORD tick = GetTickCount() % 1000;
111 GetSystemTime(pST);
112 WORD ms = (tick >= _offset) ? (tick - _offset) : (1000 - (_offset - tick));
113 pST->wMilliseconds = ms;
114 }
115
116 void systemTimeAsFileTime(FILETIME* pFT)
117 {
118 SYSTEMTIME st;
119 systemTime(&st);
120 SystemTimeToFileTime(&st, pFT);
121 }
122
123private:
124 WORD _offset;
125};
126
127
128static TickOffset offset;
129
130
131void GetSystemTimeAsFileTimeWithMillisecondResolution(FILETIME* pFT)
132{
133 offset.systemTimeAsFileTime(pFT);
134}
135
136
137} // namespace
138
139
140#endif // defined(_WIN32_WCE) && defined(POCO_WINCE_TIMESTAMP_HACK)
141
142
143namespace Poco {
144
145
146const Timestamp::TimeVal Timestamp::TIMEVAL_MIN = std::numeric_limits<Timestamp::TimeVal>::min();
147const Timestamp::TimeVal Timestamp::TIMEVAL_MAX = std::numeric_limits<Timestamp::TimeVal>::max();
148
149
150Timestamp::Timestamp()
151{
152 update();
153}
154
155
156Timestamp::Timestamp(TimeVal tv)
157{
158 _ts = tv;
159}
160
161
162Timestamp::Timestamp(const Timestamp& other)
163{
164 _ts = other._ts;
165}
166
167
168Timestamp::~Timestamp()
169{
170}
171
172
173Timestamp& Timestamp::operator = (const Timestamp& other)
174{
175 _ts = other._ts;
176 return *this;
177}
178
179
180Timestamp& Timestamp::operator = (TimeVal tv)
181{
182 _ts = tv;
183 return *this;
184}
185
186
187void Timestamp::swap(Timestamp& timestamp)
188{
189 std::swap(_ts, timestamp._ts);
190}
191
192
193Timestamp Timestamp::fromEpochTime(std::time_t t)
194{
195 return Timestamp(TimeVal(t)*resolution());
196}
197
198
199Timestamp Timestamp::fromUtcTime(UtcTimeVal val)
200{
201 val -= (TimeDiff(0x01b21dd2) << 32) + 0x13814000;
202 val /= 10;
203 return Timestamp(val);
204}
205
206
207void Timestamp::update()
208{
209 _ts = std::chrono::duration_cast<std::chrono::microseconds>
210 (std::chrono::system_clock::now().time_since_epoch()).count();
211}
212
213
214Timestamp Timestamp::operator + (const Timespan& span) const
215{
216 return *this + span.totalMicroseconds();
217}
218
219
220Timestamp Timestamp::operator - (const Timespan& span) const
221{
222 return *this - span.totalMicroseconds();
223}
224
225
226Timestamp& Timestamp::operator += (const Timespan& span)
227{
228 return *this += span.totalMicroseconds();
229}
230
231
232Timestamp& Timestamp::operator -= (const Timespan& span)
233{
234 return *this -= span.totalMicroseconds();
235}
236
237
238#if defined(_WIN32)
239
240
241Timestamp Timestamp::fromFileTimeNP(UInt32 fileTimeLow, UInt32 fileTimeHigh)
242{
243 ULARGE_INTEGER epoch; // UNIX epoch (1970-01-01 00:00:00) expressed in Windows NT FILETIME
244 epoch.LowPart = 0xD53E8000;
245 epoch.HighPart = 0x019DB1DE;
246
247 ULARGE_INTEGER ts;
248 ts.LowPart = fileTimeLow;
249 ts.HighPart = fileTimeHigh;
250 ts.QuadPart -= epoch.QuadPart;
251
252 return Timestamp(ts.QuadPart/10);
253}
254
255
256void Timestamp::toFileTimeNP(UInt32& fileTimeLow, UInt32& fileTimeHigh) const
257{
258 ULARGE_INTEGER epoch; // UNIX epoch (1970-01-01 00:00:00) expressed in Windows NT FILETIME
259 epoch.LowPart = 0xD53E8000;
260 epoch.HighPart = 0x019DB1DE;
261
262 ULARGE_INTEGER ts;
263 ts.QuadPart = _ts*10;
264 ts.QuadPart += epoch.QuadPart;
265 fileTimeLow = ts.LowPart;
266 fileTimeHigh = ts.HighPart;
267}
268
269
270#endif
271
272
273} // namespace Poco
274