Time Shield Library 2.0.0
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_HEADER_CORE_TIME_UTILS_HPP_INCLUDED
4#define TIME_SHIELD_HEADER_CORE_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# ifndef NOMINMAX
26# define NOMINMAX
27# endif
28# include <Windows.h>
29#elif TIME_SHIELD_PLATFORM_UNIX
30# include <unistd.h>
31# include <sys/resource.h>
32# include <sys/times.h>
33# include <time.h>
34#else
35# error "Unsupported platform for get_cpu_time()"
36#endif
37
38namespace time_shield {
39
43 inline struct timespec get_timespec_impl() noexcept {
44 // https://en.cppreference.com/w/c/chrono/timespec_get
45 struct timespec ts;
46# if defined(CLOCK_REALTIME)
47 clock_gettime(CLOCK_REALTIME, &ts); // POSIX implementation
48# else
49 timespec_get(&ts, TIME_UTC);
50# endif
51 return ts;
52 }
53
64 inline int64_t now_realtime_us() {
65# if TIME_SHIELD_PLATFORM_WINDOWS
66 static std::once_flag init_flag;
67 static int64_t s_perf_freq = 0;
68 static int64_t s_anchor_perf = 0;
69 static int64_t s_anchor_realtime_us = 0;
70
71 std::call_once(init_flag, []() {
72 LARGE_INTEGER freq = {};
73 LARGE_INTEGER counter = {};
74 ::QueryPerformanceFrequency(&freq);
75 ::QueryPerformanceCounter(&counter);
76
77 s_perf_freq = static_cast<int64_t>(freq.QuadPart);
78 s_anchor_perf = static_cast<int64_t>(counter.QuadPart);
79
80 FILETIME ft;
81 ::GetSystemTimeAsFileTime(&ft);
82
83 ULARGE_INTEGER uli;
84 uli.LowPart = ft.dwLowDateTime;
85 uli.HighPart = ft.dwHighDateTime;
86
87 // 100ns ticks since 1601-01-01 to 1970-01-01 (signed constant!)
88 const int64_t k_epoch_diff_100ns = 116444736000000000LL;
89
90 const int64_t filetime_100ns = static_cast<int64_t>(uli.QuadPart);
91 // Convert 100ns since 1601 -> us since 1970
92 s_anchor_realtime_us = (filetime_100ns - k_epoch_diff_100ns) / 10;
93 });
94
95 LARGE_INTEGER now = {};
96 ::QueryPerformanceCounter(&now);
97
98 const int64_t now_ticks = static_cast<int64_t>(now.QuadPart);
99 const int64_t delta_ticks = now_ticks - s_anchor_perf;
100
101 // Avoid overflow of (delta_ticks * 1000000)
102 const int64_t q = delta_ticks / s_perf_freq;
103 const int64_t r = delta_ticks % s_perf_freq;
104
105 const int64_t delta_us =
106 q * 1000000LL + (r * 1000000LL) / s_perf_freq;
107
108 return s_anchor_realtime_us + delta_us;
109# else
110 static std::once_flag init_flag;
111 static int64_t s_anchor_realtime_us = 0;
112 static int64_t s_anchor_mono_ns = 0;
113
114 std::call_once(init_flag, []() {
115 struct timespec realtime_ts{};
116 struct timespec mono_ts{};
117
118# if defined(CLOCK_MONOTONIC_RAW)
119 clock_gettime(CLOCK_MONOTONIC_RAW, &mono_ts);
120# else
121 clock_gettime(CLOCK_MONOTONIC, &mono_ts);
122# endif
123 clock_gettime(CLOCK_REALTIME, &realtime_ts);
124
125 s_anchor_realtime_us = static_cast<int64_t>(realtime_ts.tv_sec) * 1000000LL
126 + realtime_ts.tv_nsec / 1000;
127 s_anchor_mono_ns = static_cast<int64_t>(mono_ts.tv_sec) * 1000000000LL
128 + mono_ts.tv_nsec;
129 });
130
131 struct timespec mono_now_ts{};
132# if defined(CLOCK_MONOTONIC_RAW)
133 clock_gettime(CLOCK_MONOTONIC_RAW, &mono_now_ts);
134# else
135 clock_gettime(CLOCK_MONOTONIC, &mono_now_ts);
136# endif
137
138 const int64_t mono_now_ns = static_cast<int64_t>(mono_now_ts.tv_sec) * 1000000000LL
139 + mono_now_ts.tv_nsec;
140 const int64_t delta_ns = mono_now_ns - s_anchor_mono_ns;
141 return s_anchor_realtime_us + delta_ns / 1000;
142# endif
143 }
144
152 inline ts_t monotonic_sec() noexcept {
153 const auto ticks = std::chrono::steady_clock::now().time_since_epoch();
154 return static_cast<ts_t>(std::chrono::duration_cast<std::chrono::seconds>(ticks).count());
155 }
156
164 inline ts_ms_t monotonic_ms() noexcept {
165 const auto ticks = std::chrono::steady_clock::now().time_since_epoch();
166 return static_cast<ts_ms_t>(std::chrono::duration_cast<std::chrono::milliseconds>(ticks).count());
167 }
168
176 inline ts_us_t monotonic_us() noexcept {
177 const auto ticks = std::chrono::steady_clock::now().time_since_epoch();
178 return static_cast<ts_us_t>(std::chrono::duration_cast<std::chrono::microseconds>(ticks).count());
179 }
180
185 template<class T = int>
186 inline T ns_of_sec() noexcept {
187 const struct timespec ts = get_timespec_impl();
188 return static_cast<T>(ts.tv_nsec);
189 }
190
195 template<class T = int>
196 inline T us_of_sec() noexcept {
197 const struct timespec ts = get_timespec_impl();
198 return static_cast<T>(ts.tv_nsec / NS_PER_US);
199 }
200
205 template<class T = int>
206 inline T ms_of_sec() noexcept {
207 const struct timespec ts = get_timespec_impl();
208 return static_cast<T>(ts.tv_nsec / NS_PER_MS);
209 }
210
213 inline ts_t ts() noexcept {
214 const struct timespec ts = get_timespec_impl();
215 return ts.tv_sec;
216 }
217
221 inline ts_t timestamp() noexcept {
222 const struct timespec ts = get_timespec_impl();
223 return ts.tv_sec;
224 }
225
229 inline fts_t fts() noexcept {
230 const struct timespec ts = get_timespec_impl();
231 return static_cast<fts_t>(ts.tv_sec) + static_cast<fts_t>(ts.tv_nsec) / static_cast<fts_t>(NS_PER_SEC);
232 }
233
237 inline fts_t ftimestamp() noexcept {
238 const struct timespec ts = get_timespec_impl();
239 return static_cast<fts_t>(ts.tv_sec) + static_cast<fts_t>(ts.tv_nsec) / static_cast<fts_t>(NS_PER_SEC);
240 }
241
245 inline ts_ms_t ts_ms() noexcept {
246 const struct timespec ts = get_timespec_impl();
247 return MS_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_MS;
248 }
249
253 inline ts_ms_t timestamp_ms() noexcept {
254 const struct timespec ts = get_timespec_impl();
255 return MS_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_MS;
256 }
257
261 inline ts_ms_t now() noexcept {
262 const struct timespec ts = get_timespec_impl();
263 return MS_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_MS;
264 }
265
269 inline ts_us_t ts_us() noexcept {
270 const struct timespec ts = get_timespec_impl();
271 return US_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_US;
272 }
273
277 inline ts_us_t timestamp_us() noexcept {
278 const struct timespec ts = get_timespec_impl();
279 return US_PER_SEC * ts.tv_sec + ts.tv_nsec / NS_PER_US;
280 }
281
287 inline double get_cpu_time() noexcept {
288# if TIME_SHIELD_PLATFORM_WINDOWS
289 FILETIME create_time{}, exit_time{}, kernel_time{}, user_time{};
290 if (GetProcessTimes(GetCurrentProcess(), &create_time, &exit_time, &kernel_time, &user_time)) {
291 ULARGE_INTEGER li{};
292 li.LowPart = user_time.dwLowDateTime;
293 li.HighPart = user_time.dwHighDateTime;
294 return static_cast<double>(li.QuadPart) / 10000000.0;
295 }
296# elif TIME_SHIELD_PLATFORM_UNIX
297 // AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris
298# if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
299 clockid_t id = (clockid_t)-1;
300# if defined(_POSIX_CPUTIME) && (_POSIX_CPUTIME > 0)
301 if (clock_getcpuclockid(0, &id) != 0) {
302# if defined(CLOCK_PROCESS_CPUTIME_ID)
303 id = CLOCK_PROCESS_CPUTIME_ID;
304# elif defined(CLOCK_VIRTUAL)
305 id = CLOCK_VIRTUAL;
306# endif
307 }
308# elif defined(CLOCK_PROCESS_CPUTIME_ID)
309 id = CLOCK_PROCESS_CPUTIME_ID;
310# elif defined(CLOCK_VIRTUAL)
311 id = CLOCK_VIRTUAL;
312# endif
313 if (id != (clockid_t)-1) {
314 struct timespec ts;
315 if (clock_gettime(id, &ts) == 0) {
316 return static_cast<double>(ts.tv_sec) + static_cast<double>(ts.tv_nsec) / 1e9;
317 }
318 }
319# endif
320
321# if defined(RUSAGE_SELF)
322 struct rusage usage{};
323 if (getrusage(RUSAGE_SELF, &usage) == 0) {
324 return static_cast<double>(usage.ru_utime.tv_sec) + static_cast<double>(usage.ru_utime.tv_usec) / 1e6;
325 }
326# endif
327
328# if defined(_SC_CLK_TCK)
329 struct tms t{};
330 if (times(&t) != (clock_t)-1) {
331 return static_cast<double>(t.tms_utime) / static_cast<double>(sysconf(_SC_CLK_TCK));
332 }
333# endif
334
335# if defined(CLOCKS_PER_SEC)
336 clock_t cl = clock();
337 if (cl != (clock_t)-1) {
338 return static_cast<double>(cl) / static_cast<double>(CLOCKS_PER_SEC);
339 }
340# endif
341# else
342# warning "get_cpu_time() may not work correctly: unsupported platform"
343# endif
344 return std::numeric_limits<double>::quiet_NaN();
345 }
346
347}; // namespace time_shield
348
349#endif // TIME_SHIELD_HEADER_CORE_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_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.