Coverage Report

Created: 2023-10-14 06:19

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