2025-04-16 01:37:48 +01:00
|
|
|
#include "Time.hpp"
|
|
|
|
|
|
|
|
|
|
#define chr std::chrono
|
|
|
|
|
#define TIMESPEC_NSEC_PER_SEC 1000000000L
|
|
|
|
|
|
|
|
|
|
using s_ns = std::pair<uint64_t, uint64_t>;
|
|
|
|
|
|
|
|
|
|
static s_ns timediff(const s_ns& a, const s_ns& b) {
|
|
|
|
|
s_ns d;
|
|
|
|
|
|
|
|
|
|
d.first = a.first - b.first;
|
|
|
|
|
if (a.second >= b.second)
|
|
|
|
|
d.second = a.second - b.second;
|
|
|
|
|
else {
|
2026-02-01 15:18:06 +01:00
|
|
|
d.second = (TIMESPEC_NSEC_PER_SEC + a.second) - b.second;
|
2025-04-16 01:37:48 +01:00
|
|
|
d.first -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static s_ns timeadd(const s_ns& a, const s_ns& b) {
|
|
|
|
|
s_ns d;
|
|
|
|
|
|
|
|
|
|
d.first = a.first + b.first;
|
|
|
|
|
if (a.second + b.second >= TIMESPEC_NSEC_PER_SEC) {
|
|
|
|
|
d.second = a.second + b.second - TIMESPEC_NSEC_PER_SEC;
|
|
|
|
|
d.first += 1;
|
|
|
|
|
} else
|
|
|
|
|
d.second = a.second + b.second;
|
|
|
|
|
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Time::steady_tp Time::steadyNow() {
|
|
|
|
|
return chr::steady_clock::now();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Time::system_tp Time::systemNow() {
|
|
|
|
|
return chr::system_clock::now();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t Time::millis(const steady_tp& tp) {
|
|
|
|
|
return chr::duration_cast<chr::milliseconds>(tp.time_since_epoch()).count();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s_ns Time::secNsec(const steady_tp& tp) {
|
2026-02-01 15:18:06 +01:00
|
|
|
const uint64_t sec = chr::duration_cast<chr::seconds>(tp.time_since_epoch()).count();
|
|
|
|
|
const auto nsecdur = tp - chr::steady_clock::time_point(chr::seconds(sec));
|
|
|
|
|
return {sec, chr::duration_cast<chr::nanoseconds>(nsecdur).count()};
|
2025-04-16 01:37:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t Time::millis(const system_tp& tp) {
|
|
|
|
|
return chr::duration_cast<chr::milliseconds>(tp.time_since_epoch()).count();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s_ns Time::secNsec(const system_tp& tp) {
|
2026-02-01 15:18:06 +01:00
|
|
|
const uint64_t sec = chr::duration_cast<chr::seconds>(tp.time_since_epoch()).count();
|
|
|
|
|
const auto nsecdur = tp - chr::system_clock::time_point(chr::seconds(sec));
|
|
|
|
|
return {sec, chr::duration_cast<chr::nanoseconds>(nsecdur).count()};
|
2025-04-16 01:37:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: this is a mess, but C++ doesn't define what steady_clock is.
|
|
|
|
|
// At least on Linux, system_clock == CLOCK_REALTIME
|
|
|
|
|
// and steady_clock == CLOCK_MONOTONIC,
|
|
|
|
|
// or at least it seems so with gcc and gcc's stl.
|
|
|
|
|
// but, since we can't *ever* be sure, we have to guess.
|
|
|
|
|
// In general, this may shift the time around by a couple hundred ns. Doesn't matter, realistically.
|
|
|
|
|
|
|
|
|
|
Time::steady_tp Time::fromTimespec(const timespec* ts) {
|
2026-02-01 15:18:06 +01:00
|
|
|
timespec mono{}, real{};
|
2025-04-16 01:37:48 +01:00
|
|
|
clock_gettime(CLOCK_MONOTONIC, &mono);
|
|
|
|
|
clock_gettime(CLOCK_REALTIME, &real);
|
2026-02-01 15:18:06 +01:00
|
|
|
auto now = Time::steadyNow();
|
|
|
|
|
auto nowSys = Time::systemNow();
|
|
|
|
|
s_ns stdSteady, stdReal;
|
2025-04-16 01:37:48 +01:00
|
|
|
stdSteady = Time::secNsec(now);
|
|
|
|
|
stdReal = Time::secNsec(nowSys);
|
|
|
|
|
|
|
|
|
|
// timespec difference, REAL - MONO
|
|
|
|
|
s_ns diff;
|
|
|
|
|
diff.first = real.tv_sec - mono.tv_sec;
|
|
|
|
|
if (real.tv_nsec >= mono.tv_nsec)
|
|
|
|
|
diff.second = real.tv_nsec - mono.tv_nsec;
|
|
|
|
|
else {
|
2026-02-01 15:18:06 +01:00
|
|
|
diff.second = TIMESPEC_NSEC_PER_SEC + real.tv_nsec - mono.tv_nsec;
|
2025-04-16 01:37:48 +01:00
|
|
|
diff.first -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// STD difference, REAL - MONO
|
|
|
|
|
s_ns diff2 = timediff(stdReal, stdSteady);
|
|
|
|
|
|
|
|
|
|
s_ns diffFinal;
|
|
|
|
|
s_ns monotime = {ts->tv_sec, ts->tv_nsec};
|
|
|
|
|
|
|
|
|
|
if (diff.first >= diff2.first || (diff.first == diff2.first && diff.second >= diff2.second))
|
|
|
|
|
diffFinal = timediff(diff, diff2);
|
|
|
|
|
else
|
|
|
|
|
diffFinal = timediff(diff2, diff);
|
|
|
|
|
|
|
|
|
|
auto sum = timeadd(monotime, diffFinal);
|
|
|
|
|
return chr::steady_clock::time_point(std::chrono::seconds(sum.first)) + chr::nanoseconds(sum.second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct timespec Time::toTimespec(const steady_tp& tp) {
|
|
|
|
|
struct timespec mono, real;
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &mono);
|
|
|
|
|
clock_gettime(CLOCK_REALTIME, &real);
|
|
|
|
|
Time::steady_tp now = Time::steadyNow();
|
|
|
|
|
Time::system_tp nowSys = Time::systemNow();
|
|
|
|
|
s_ns stdSteady, stdReal;
|
|
|
|
|
stdSteady = Time::secNsec(now);
|
|
|
|
|
stdReal = Time::secNsec(nowSys);
|
|
|
|
|
|
|
|
|
|
// timespec difference, REAL - MONO
|
|
|
|
|
s_ns diff;
|
|
|
|
|
diff.first = real.tv_sec - mono.tv_sec;
|
|
|
|
|
if (real.tv_nsec >= mono.tv_nsec)
|
|
|
|
|
diff.second = real.tv_nsec - mono.tv_nsec;
|
|
|
|
|
else {
|
2026-02-01 15:18:06 +01:00
|
|
|
diff.second = TIMESPEC_NSEC_PER_SEC + real.tv_nsec - mono.tv_nsec;
|
2025-04-16 01:37:48 +01:00
|
|
|
diff.first -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// STD difference, REAL - MONO
|
|
|
|
|
s_ns diff2 = timediff(stdReal, stdSteady);
|
|
|
|
|
|
|
|
|
|
s_ns diffFinal;
|
|
|
|
|
s_ns tpTime = secNsec(tp);
|
|
|
|
|
|
|
|
|
|
if (diff.first >= diff2.first || (diff.first == diff2.first && diff.second >= diff2.second))
|
|
|
|
|
diffFinal = timediff(diff, diff2);
|
|
|
|
|
else
|
|
|
|
|
diffFinal = timediff(diff2, diff);
|
|
|
|
|
|
|
|
|
|
auto sum = timeadd(tpTime, diffFinal);
|
|
|
|
|
return timespec{.tv_sec = sum.first, .tv_nsec = sum.second};
|
|
|
|
|
}
|