Time Shield Library
C++ library for working with time
Loading...
Searching...
No Matches
time_utils.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2#pragma once
3#ifndef _TIME_SHIELD_TIME_UTILS_HPP_INCLUDED
4#define _TIME_SHIELD_TIME_UTILS_HPP_INCLUDED
5
10
11#include "config.hpp"
12#include "types.hpp"
13#include "constants.hpp"
14
15#include <chrono>
16#include <limits> // For std::numeric_limits
17#include <ctime> // For clock_t and timespec (POSIX)
18#include <time.h> // For clock(), times(), etc.
19#include <mutex> // For std::once_flag
20
21#if TIME_SHIELD_PLATFORM_WINDOWS
22# ifndef WIN32_LEAN_AND_MEAN
23# define WIN32_LEAN_AND_MEAN
24# endif
25# include <Windows.h>
26#elif TIME_SHIELD_PLATFORM_UNIX
27# include <unistd.h>
28# include <sys/resource.h>
29# include <sys/times.h>
30# include <time.h>
31#else
32# error "Unsupported platform for get_cpu_time()"
33#endif
34
35namespace time_shield {
36
40 inline struct timespec get_timespec_impl() noexcept {
41 // https://en.cppreference.com/w/c/chrono/timespec_get
42 struct timespec ts;
43# if defined(CLOCK_REALTIME)
44 clock_gettime(CLOCK_REALTIME, &ts); // Версия для POSIX
45# else
46 timespec_get(&ts, TIME_UTC);
47# endif
48 return ts;
49 }
50
61 inline int64_t now_realtime_us() {
62# if TIME_SHIELD_PLATFORM_WINDOWS
63 static std::once_flag init_flag;
64 static int64_t s_perf_freq = 0;
65 static int64_t s_anchor_perf = 0;
66 static int64_t s_anchor_realtime_us = 0;
67
68 std::call_once(init_flag, []() {
69 LARGE_INTEGER freq = {};
70 LARGE_INTEGER counter = {};
71 ::QueryPerformanceFrequency(&freq);
72 ::QueryPerformanceCounter(&counter);
73
74 s_perf_freq = static_cast<int64_t>(freq.QuadPart);
75 s_anchor_perf = static_cast<int64_t>(counter.QuadPart);
76
77 FILETIME ft;
78 ::GetSystemTimeAsFileTime(&ft);
79
80 ULARGE_INTEGER uli;
81 uli.LowPart = ft.dwLowDateTime;
82 uli.HighPart = ft.dwHighDateTime;
83
84 // 100ns ticks since 1601-01-01 to 1970-01-01 (signed constant!)
85 const int64_t k_epoch_diff_100ns = 116444736000000000LL;
86
87 const int64_t filetime_100ns = static_cast<int64_t>(uli.QuadPart);
88 // Convert 100ns since 1601 -> us since 1970
89 s_anchor_realtime_us = (filetime_100ns - k_epoch_diff_100ns) / 10;
90 });
91
92 LARGE_INTEGER now = {};
93 ::QueryPerformanceCounter(&now);
94
95 const int64_t now_ticks = static_cast<int64_t>(now.QuadPart);
96 const int64_t delta_ticks = now_ticks - s_anchor_perf;
97
98 // Avoid overflow of (delta_ticks * 1000000)
99 const int64_t q = delta_ticks / s_perf_freq;
100 const int64_t r = delta_ticks % s_perf_freq;
101
102 const int64_t delta_us =
103 q * 1000000LL + (r * 1000000LL) / s_perf_freq;
104
105 return s_anchor_realtime_us + delta_us;
106# else
107 static std::once_flag init_flag;
108 static int64_t s_anchor_realtime_us = 0;
109 static int64_t s_anchor_mono_ns = 0;
110
111 std::call_once(init_flag, []() {
112 struct timespec realtime_ts{};
113 struct timespec mono_ts{};
114
115# if defined(CLOCK_MONOTONIC_RAW)
116 clock_gettime(CLOCK_MONOTONIC_RAW, &mono_ts);
117# else
118 clock_gettime(CLOCK_MONOTONIC, &mono_ts);
119# endif
120 clock_gettime(CLOCK_REALTIME, &realtime_ts);
121
122 s_anchor_realtime_us = static_cast<int64_t>(realtime_ts.tv_sec) * 1000000LL
123 + realtime_ts.tv_nsec / 1000;
124 s_anchor_mono_ns = static_cast<int64_t>(mono_ts.tv_sec) * 1000000000LL
125 + mono_ts.tv_nsec;
126 });
127
128 struct timespec mono_now_ts{};
129# if defined(CLOCK_MONOTONIC_RAW)
130 clock_gettime(CLOCK_MONOTONIC_RAW, &mono_now_ts);
131# else
132 clock_gettime(CLOCK_MONOTONIC, &mono_now_ts);
133# endif
134
135 const int64_t mono_now_ns = static_cast<int64_t>(mono_now_ts.tv_sec) * 1000000000LL
136 + mono_now_ts.tv_nsec;
137 const int64_t delta_ns = mono_now_ns - s_anchor_mono_ns;
138 return s_anchor_realtime_us + delta_ns / 1000;
139# endif
140 }
141
149 inline ts_t monotonic_sec() noexcept {
150 const auto ticks = std::chrono::steady_clock::now().time_since_epoch();
151 return static_cast<ts_t>(std::chrono::duration_cast<std::chrono::seconds>(ticks).count());
152 }
153
161 inline ts_ms_t monotonic_ms() noexcept {
162 const auto ticks = std::chrono::steady_clock::now().time_since_epoch();
163 return static_cast<ts_ms_t>(std::chrono::duration_cast<std::chrono::milliseconds>(ticks).count());
164 }
165
173 inline ts_us_t monotonic_us() noexcept {
174 const auto ticks = std::chrono::steady_clock::now().time_since_epoch();
175 return static_cast<ts_us_t>(std::chrono::duration_cast<std::chrono::microseconds>(ticks).count());
176 }
177
182 template<class T = int>
183 inline T ns_of_sec() noexcept {
184 const struct timespec ts = get_timespec_impl();
185 return static_cast<T>(ts.tv_nsec);
186 }
187
192 template<class T = int>
193 inline T us_of_sec() noexcept {
194 const struct timespec ts = get_timespec_impl();
195 return static_cast<T>(ts.tv_nsec / NS_PER_US);
196 }
197
202 template<class T = int>
203 inline T ms_of_sec() noexcept {
204 const struct timespec ts = get_timespec_impl();
205 return static_cast<T>(ts.tv_nsec / NS_PER_MS);
206 }
207
210 inline ts_t ts() noexcept {
211 const struct timespec ts = get_timespec_impl();
212 return ts.tv_sec;
213 }
214
218 inline ts_t timestamp() noexcept {
219 const struct timespec ts = get_timespec_impl();
220 return ts.tv_sec;
221 }
222
226 inline fts_t fts() noexcept {
227 const struct timespec ts = get_timespec_impl();
228 return static_cast<fts_t>(ts.tv_sec) + static_cast<fts_t>(ts.tv_nsec) / static_cast<fts_t>(NS_PER_SEC);
229 }
230
234 inline fts_t ftimestamp() noexcept {
235 const struct timespec ts = get_timespec_impl();
236 return static_cast<fts_t>(ts.tv_sec) + static_cast<fts_t>(ts.tv_nsec) / static_cast<fts_t>(NS_PER_SEC);
237 }
238
242 inline ts_ms_t ts_ms() noexcept {
243 const struct timespec ts = get_timespec_impl();
244 return MS_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_MS;
245 }
246
250 inline ts_ms_t timestamp_ms() noexcept {
251 const struct timespec ts = get_timespec_impl();
252 return MS_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_MS;
253 }
254
258 inline ts_ms_t now() noexcept {
259 const struct timespec ts = get_timespec_impl();
260 return MS_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_MS;
261 }
262
266 inline ts_us_t ts_us() noexcept {
267 const struct timespec ts = get_timespec_impl();
268 return US_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_US;
269 }
270
274 inline ts_us_t timestamp_us() noexcept {
275 const struct timespec ts = get_timespec_impl();
276 return US_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_US;
277 }
278
284 inline double get_cpu_time() noexcept {
285# if TIME_SHIELD_PLATFORM_WINDOWS
286 FILETIME create_time{}, exit_time{}, kernel_time{}, user_time{};
287 if (GetProcessTimes(GetCurrentProcess(), &create_time, &exit_time, &kernel_time, &user_time)) {
288 ULARGE_INTEGER li{};
289 li.LowPart = user_time.dwLowDateTime;
290 li.HighPart = user_time.dwHighDateTime;
291 return static_cast<double>(li.QuadPart) / 10000000.0;
292 }
293# elif TIME_SHIELD_PLATFORM_UNIX
294 // AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris
295# if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
296 clockid_t id = (clockid_t)-1;
297# if defined(_POSIX_CPUTIME) && (_POSIX_CPUTIME > 0)
298 if (clock_getcpuclockid(0, &id) != 0) {
299# if defined(CLOCK_PROCESS_CPUTIME_ID)
300 id = CLOCK_PROCESS_CPUTIME_ID;
301# elif defined(CLOCK_VIRTUAL)
302 id = CLOCK_VIRTUAL;
303# endif
304 }
305# elif defined(CLOCK_PROCESS_CPUTIME_ID)
306 id = CLOCK_PROCESS_CPUTIME_ID;
307# elif defined(CLOCK_VIRTUAL)
308 id = CLOCK_VIRTUAL;
309# endif
310 if (id != (clockid_t)-1) {
311 struct timespec ts;
312 if (clock_gettime(id, &ts) == 0) {
313 return static_cast<double>(ts.tv_sec) + static_cast<double>(ts.tv_nsec) / 1e9;
314 }
315 }
316# endif
317
318# if defined(RUSAGE_SELF)
319 struct rusage usage{};
320 if (getrusage(RUSAGE_SELF, &usage) == 0) {
321 return static_cast<double>(usage.ru_utime.tv_sec) + static_cast<double>(usage.ru_utime.tv_usec) / 1e6;
322 }
323# endif
324
325# if defined(_SC_CLK_TCK)
326 struct tms t{};
327 if (times(&t) != (clock_t)-1) {
328 return static_cast<double>(t.tms_utime) / static_cast<double>(sysconf(_SC_CLK_TCK));
329 }
330# endif
331
332# if defined(CLOCKS_PER_SEC)
333 clock_t cl = clock();
334 if (cl != (clock_t)-1) {
335 return static_cast<double>(cl) / static_cast<double>(CLOCKS_PER_SEC);
336 }
337# endif
338# else
339# warning "get_cpu_time() may not work correctly: unsupported platform"
340# endif
341 return std::numeric_limits<double>::quiet_NaN();
342 }
343
344}; // namespace time_shield
345
346#endif // _TIME_SHIELD_TIME_UTILS_HPP_INCLUDED
Configuration macros for the library.
Header file with time-related constants.
constexpr int64_t NS_PER_US
Nanoseconds per microsecond.
Definition constants.hpp:71
constexpr int64_t NS_PER_MS
Nanoseconds per millisecond.
Definition constants.hpp:72
constexpr int64_t MS_PER_SEC
Milliseconds per second.
Definition constants.hpp:77
constexpr int64_t NS_PER_SEC
Nanoseconds per second.
Definition constants.hpp:73
constexpr int64_t US_PER_SEC
Microseconds per second.
Definition constants.hpp:76
TIME_SHIELD_CONSTEXPR ts_t ts(year_t year, int month, int day)
Alias for to_timestamp.
int64_t ts_t
Unix timestamp in seconds since 1970‑01‑01T00:00:00Z.
Definition types.hpp:49
int64_t ts_ms_t
Unix timestamp in milliseconds since epoch.
Definition types.hpp:50
double fts_t
Floating-point timestamp (fractional seconds since epoch).
Definition types.hpp:52
int64_t ts_us_t
Unix timestamp in microseconds since epoch.
Definition types.hpp:51
ts_us_t timestamp_us() noexcept
Get the current UTC timestamp in microseconds.
ts_us_t monotonic_us() noexcept
Return monotonic microseconds from a process-local reference.
ts_ms_t now() noexcept
Get the current UTC timestamp in milliseconds.
ts_t monotonic_sec() noexcept
Return monotonic seconds from a process-local reference.
T ns_of_sec() noexcept
Get the nanosecond part of the current second.
int64_t now_realtime_us()
Get current real time in microseconds using a platform-specific method.
ts_t ts() noexcept
Get the current UTC timestamp in seconds.
ts_t timestamp() noexcept
Get the current UTC timestamp in seconds.
fts_t ftimestamp() noexcept
Get the current UTC timestamp in floating-point seconds.
double get_cpu_time() noexcept
Get the CPU time used by the current process.
struct timespec get_timespec_impl() noexcept
Get the current timespec.
ts_us_t ts_us() noexcept
Get the current UTC timestamp in microseconds.
T ms_of_sec() noexcept
Get the millisecond part of the current second.
ts_ms_t monotonic_ms() noexcept
Return monotonic milliseconds from a process-local reference.
ts_ms_t ts_ms() noexcept
Get the current UTC timestamp in milliseconds.
T us_of_sec() noexcept
Get the microsecond part of the current second.
ts_ms_t timestamp_ms() noexcept
Get the current UTC timestamp in milliseconds.
fts_t fts() noexcept
Get the current UTC timestamp in floating-point seconds.
Main namespace for the Time Shield library.
Type definitions for time-related units and formats.