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 <limits> // For std::numeric_limits
16#include <ctime> // For clock_t and timespec (POSIX)
17#include <time.h> // For clock(), times(), etc.
18#include <mutex> // For std::once_flag
19
20#if TIME_SHIELD_PLATFORM_WINDOWS
21# ifndef WIN32_LEAN_AND_MEAN
22# define WIN32_LEAN_AND_MEAN
23# endif
24# include <Windows.h>
25#elif TIME_SHIELD_PLATFORM_UNIX
26# include <unistd.h>
27# include <sys/resource.h>
28# include <sys/times.h>
29# include <time.h>
30#else
31# error "Unsupported platform for get_cpu_time()"
32#endif
33
34namespace time_shield {
35
39 inline struct timespec get_timespec_impl() noexcept {
40 // https://en.cppreference.com/w/c/chrono/timespec_get
41 struct timespec ts;
42# if defined(CLOCK_REALTIME)
43 clock_gettime(CLOCK_REALTIME, &ts); // Версия для POSIX
44# else
45 timespec_get(&ts, TIME_UTC);
46# endif
47 return ts;
48 }
49
60 inline int64_t now_realtime_us() {
61# if TIME_SHIELD_PLATFORM_WINDOWS
62 static std::once_flag init_flag;
63 static int64_t s_perf_freq = 0;
64 static int64_t s_anchor_perf = 0;
65 static int64_t s_anchor_realtime_us = 0;
66
67 std::call_once(init_flag, []() {
68 LARGE_INTEGER freq = {};
69 LARGE_INTEGER counter = {};
70 ::QueryPerformanceFrequency(&freq);
71 ::QueryPerformanceCounter(&counter);
72
73 s_perf_freq = static_cast<int64_t>(freq.QuadPart);
74 s_anchor_perf = static_cast<int64_t>(counter.QuadPart);
75
76 FILETIME ft;
77 ::GetSystemTimeAsFileTime(&ft);
78
79 ULARGE_INTEGER uli;
80 uli.LowPart = ft.dwLowDateTime;
81 uli.HighPart = ft.dwHighDateTime;
82
83 // 100ns ticks since 1601-01-01 to 1970-01-01 (signed constant!)
84 const int64_t k_epoch_diff_100ns = 116444736000000000LL;
85
86 const int64_t filetime_100ns = static_cast<int64_t>(uli.QuadPart);
87 // Convert 100ns since 1601 -> us since 1970
88 s_anchor_realtime_us = (filetime_100ns - k_epoch_diff_100ns) / 10;
89 });
90
91 LARGE_INTEGER now = {};
92 ::QueryPerformanceCounter(&now);
93
94 const int64_t now_ticks = static_cast<int64_t>(now.QuadPart);
95 const int64_t delta_ticks = now_ticks - s_anchor_perf;
96
97 // Avoid overflow of (delta_ticks * 1000000)
98 const int64_t q = delta_ticks / s_perf_freq;
99 const int64_t r = delta_ticks % s_perf_freq;
100
101 const int64_t delta_us =
102 q * 1000000LL + (r * 1000000LL) / s_perf_freq;
103
104 return s_anchor_realtime_us + delta_us;
105# else
106 static std::once_flag init_flag;
107 static int64_t s_anchor_realtime_us = 0;
108 static int64_t s_anchor_mono_ns = 0;
109
110 std::call_once(init_flag, []() {
111 struct timespec realtime_ts{};
112 struct timespec mono_ts{};
113
114# if defined(CLOCK_MONOTONIC_RAW)
115 clock_gettime(CLOCK_MONOTONIC_RAW, &mono_ts);
116# else
117 clock_gettime(CLOCK_MONOTONIC, &mono_ts);
118# endif
119 clock_gettime(CLOCK_REALTIME, &realtime_ts);
120
121 s_anchor_realtime_us = static_cast<int64_t>(realtime_ts.tv_sec) * 1000000LL
122 + realtime_ts.tv_nsec / 1000;
123 s_anchor_mono_ns = static_cast<int64_t>(mono_ts.tv_sec) * 1000000000LL
124 + mono_ts.tv_nsec;
125 });
126
127 struct timespec mono_now_ts{};
128# if defined(CLOCK_MONOTONIC_RAW)
129 clock_gettime(CLOCK_MONOTONIC_RAW, &mono_now_ts);
130# else
131 clock_gettime(CLOCK_MONOTONIC, &mono_now_ts);
132# endif
133
134 const int64_t mono_now_ns = static_cast<int64_t>(mono_now_ts.tv_sec) * 1000000000LL
135 + mono_now_ts.tv_nsec;
136 const int64_t delta_ns = mono_now_ns - s_anchor_mono_ns;
137 return s_anchor_realtime_us + delta_ns / 1000;
138# endif
139 }
140
145 template<class T = int>
146 inline T ns_of_sec() noexcept {
147 const struct timespec ts = get_timespec_impl();
148 return static_cast<T>(ts.tv_nsec);
149 }
150
155 template<class T = int>
156 inline T us_of_sec() noexcept {
157 const struct timespec ts = get_timespec_impl();
158 return ts.tv_nsec / NS_PER_US;
159 }
160
165 template<class T = int>
166 inline T ms_of_sec() noexcept {
167 const struct timespec ts = get_timespec_impl();
168 return ts.tv_nsec / NS_PER_MS;
169 }
170
173 inline ts_t ts() noexcept {
174 const struct timespec ts = get_timespec_impl();
175 return ts.tv_sec;
176 }
177
181 inline ts_t timestamp() noexcept {
182 const struct timespec ts = get_timespec_impl();
183 return ts.tv_sec;
184 }
185
189 inline fts_t fts() noexcept {
190 const struct timespec ts = get_timespec_impl();
191 return static_cast<fts_t>(ts.tv_sec) + static_cast<fts_t>(ts.tv_nsec) / static_cast<fts_t>(NS_PER_SEC);
192 }
193
197 inline fts_t ftimestamp() noexcept {
198 const struct timespec ts = get_timespec_impl();
199 return static_cast<fts_t>(ts.tv_sec) + static_cast<fts_t>(ts.tv_nsec) / static_cast<fts_t>(NS_PER_SEC);
200 }
201
205 inline ts_ms_t ts_ms() noexcept {
206 const struct timespec ts = get_timespec_impl();
207 return MS_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_MS;
208 }
209
213 inline ts_ms_t timestamp_ms() noexcept {
214 const struct timespec ts = get_timespec_impl();
215 return MS_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_MS;
216 }
217
221 inline ts_ms_t now() noexcept {
222 const struct timespec ts = get_timespec_impl();
223 return MS_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_MS;
224 }
225
229 inline ts_us_t ts_us() noexcept {
230 const struct timespec ts = get_timespec_impl();
231 return US_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_US;
232 }
233
237 inline ts_us_t timestamp_us() noexcept {
238 const struct timespec ts = get_timespec_impl();
239 return US_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_US;
240 }
241
247 inline double get_cpu_time() noexcept {
248# if TIME_SHIELD_PLATFORM_WINDOWS
249 FILETIME create_time{}, exit_time{}, kernel_time{}, user_time{};
250 if (GetProcessTimes(GetCurrentProcess(), &create_time, &exit_time, &kernel_time, &user_time)) {
251 ULARGE_INTEGER li{};
252 li.LowPart = user_time.dwLowDateTime;
253 li.HighPart = user_time.dwHighDateTime;
254 return static_cast<double>(li.QuadPart) / 10000000.0;
255 }
256# elif TIME_SHIELD_PLATFORM_UNIX
257 // AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris
258# if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
259 clockid_t id = (clockid_t)-1;
260# if defined(_POSIX_CPUTIME) && (_POSIX_CPUTIME > 0)
261 if (clock_getcpuclockid(0, &id) != 0) {
262# if defined(CLOCK_PROCESS_CPUTIME_ID)
263 id = CLOCK_PROCESS_CPUTIME_ID;
264# elif defined(CLOCK_VIRTUAL)
265 id = CLOCK_VIRTUAL;
266# endif
267 }
268# elif defined(CLOCK_PROCESS_CPUTIME_ID)
269 id = CLOCK_PROCESS_CPUTIME_ID;
270# elif defined(CLOCK_VIRTUAL)
271 id = CLOCK_VIRTUAL;
272# endif
273 if (id != (clockid_t)-1) {
274 struct timespec ts;
275 if (clock_gettime(id, &ts) == 0) {
276 return static_cast<double>(ts.tv_sec) + static_cast<double>(ts.tv_nsec) / 1e9;
277 }
278 }
279# endif
280
281# if defined(RUSAGE_SELF)
282 struct rusage usage{};
283 if (getrusage(RUSAGE_SELF, &usage) == 0) {
284 return static_cast<double>(usage.ru_utime.tv_sec) + static_cast<double>(usage.ru_utime.tv_usec) / 1e6;
285 }
286# endif
287
288# if defined(_SC_CLK_TCK)
289 struct tms t{};
290 if (times(&t) != (clock_t)-1) {
291 return static_cast<double>(t.tms_utime) / static_cast<double>(sysconf(_SC_CLK_TCK));
292 }
293# endif
294
295# if defined(CLOCKS_PER_SEC)
296 clock_t cl = clock();
297 if (cl != (clock_t)-1) {
298 return static_cast<double>(cl) / static_cast<double>(CLOCKS_PER_SEC);
299 }
300# endif
301# else
302# warning "get_cpu_time() may not work correctly: unsupported platform"
303# endif
304 return std::numeric_limits<double>::quiet_NaN();
305 }
306
307}; // namespace time_shield
308
309#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:48
int64_t ts_ms_t
Unix timestamp in milliseconds since epoch.
Definition types.hpp:49
double fts_t
Floating-point timestamp (fractional seconds since epoch).
Definition types.hpp:51
int64_t ts_us_t
Unix timestamp in microseconds since epoch.
Definition types.hpp:50
ts_us_t timestamp_us() noexcept
Get the current UTC timestamp in microseconds.
ts_ms_t now() noexcept
Get the current UTC timestamp in milliseconds.
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 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.