/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: Clock.cpp Date: 2021-6-13 Author: Reece ***/ #include #include "Clock.hpp" using high_res_clock = std::chrono::high_resolution_clock; using sys_clock = std::chrono::system_clock; #if defined(AURORA_PLATFORM_WIN32) #define timegm _mkgmtime #endif static sys_clock::duration gEpoch; static sys_clock::duration gUnixDelta; static auto InitEpoch() { std::tm start{}; start.tm_mday = 29; // day number start.tm_mon = 7; // month idx, aug start.tm_year = 101; // 1900 + 101 start.tm_hour = 9; // 11 - index - DST start.tm_min = 15; // minute offset auto epoch = sys_clock::from_time_t(timegm(&start)).time_since_epoch(); std::tm unixStart{}; unixStart.tm_mday = 1; unixStart.tm_year = 70; auto nixepoch = sys_clock::from_time_t(timegm(&unixStart)).time_since_epoch(); gUnixDelta = epoch - nixepoch; gEpoch = epoch; return 0; } static auto ___ = InitEpoch(); template static inline T NormalizeEpoch(T sysEpoch) { return sysEpoch - gEpoch; } template static inline T DecodeEpoch(T auroraEpoch) { return auroraEpoch + gEpoch; } template static auto TimeFromDurationSinceEpoch(Duration_t in) { auto duration = std::chrono::duration_cast(in); return std::chrono::time_point(DecodeEpoch(duration)); } template static time_t CalculateTimeT(AuUInt64 in) { return sys_clock::to_time_t(TimeFromDurationSinceEpoch(Duration_t(in))); } namespace Aurora::Time { AUKN_SYM time_t SToCTime(AuInt64 time) { return CalculateTimeT(time); } AUKN_SYM time_t NSToCTime(AuInt64 time) { return CalculateTimeT(time); } AUKN_SYM time_t MSToCTime(AuInt64 time) { return CalculateTimeT(time); } AUKN_SYM AuUInt64 CurrentClock() { return NormalizeEpoch(sys_clock::now().time_since_epoch()).count(); } AUKN_SYM AuUInt64 CurrentClockMS() { return std::chrono::duration_cast(NormalizeEpoch(sys_clock::now().time_since_epoch())).count(); } AUKN_SYM AuUInt64 CurrentClockNS() { return std::chrono::duration_cast(NormalizeEpoch(sys_clock::now().time_since_epoch())).count(); } AUKN_SYM AuInt64 CTimeToMS(time_t time) { return std::chrono::duration_cast(NormalizeEpoch(sys_clock::from_time_t(time).time_since_epoch())).count(); } AUKN_SYM AuUInt64 CurrentInternalClock() { return high_res_clock::now().time_since_epoch().count(); } AUKN_SYM AuUInt64 CurrentInternalClockMS() { return std::chrono::duration_cast(high_res_clock::now().time_since_epoch()).count(); } AUKN_SYM AuUInt64 CurrentInternalClockNS() { return std::chrono::duration_cast(high_res_clock::now().time_since_epoch()).count(); } AUKN_SYM AuInt64 ConvertAuroraToUnixMS(AuInt64 in) { return std::chrono::duration_cast(std::chrono::milliseconds(in) + gUnixDelta).count(); } AUKN_SYM AuInt64 ConvertAuroraToUnixNS(AuInt64 in) { return std::chrono::duration_cast(std::chrono::nanoseconds(in) + gUnixDelta).count(); } AUKN_SYM AuInt64 ConvertUnixToAuroraMS(AuInt64 in) { return std::chrono::duration_cast(std::chrono::milliseconds(in) - gUnixDelta).count(); } AUKN_SYM AuInt64 ConvertUnixToAuroraNS(AuInt64 in) { return std::chrono::duration_cast(std::chrono::nanoseconds(in) - gUnixDelta).count(); } AUKN_SYM AuUInt64 ConvertInternalToAuroraEpochMS(AuUInt64 in) { static AuInt64 epochDelta = 0; if (epochDelta == 0) { epochDelta = CurrentClockMS() - CurrentInternalClockMS(); } return epochDelta + in; } AUKN_SYM AuUInt64 ConvertInternalToAuroraEpochNS(AuUInt64 in) { static AuInt64 epochDelta = 0; if (epochDelta == 0) { epochDelta = CurrentClockNS() - CurrentInternalClockNS(); } return epochDelta + in; } AUKN_SYM double CPUFrequencyDeltaNS() { static double frequency = 0; if (frequency != 0) { return frequency; } return frequency = (static_cast(high_res_clock::period::num) / static_cast(high_res_clock::period::den) * 1'000'000'000.f); } AUKN_SYM double CPUFrequencyDeltaMS() { static double frequency = 0; if (frequency != 0) { return frequency; } return frequency = (static_cast(high_res_clock::period::num) / static_cast(high_res_clock::period::den) * 1'000.f); } AUKN_SYM AuUInt64 ClockJiffies() { static AuUInt64 frequency = 0; if (frequency != 0) { return frequency; } return frequency = static_cast(high_res_clock::period::den) / static_cast(high_res_clock::period::num); } AUKN_SYM tm ToCivilTime(AuInt64 time, bool UTC) { std::tm ret{}; auto timet = MSToCTime(time); if (UTC) { #if defined(AURORA_COMPILER_MSVC) auto tm = gmtime_s(&ret, &timet); #else auto tm = gmtime_r(&timet, &ret); #endif #if defined(AURORA_COMPILER_MSVC) SysAssert(!tm, "couldn't convert civil time"); #else SysAssert(tm, "couldn't convert civil time"); #endif } else { #if defined(AURORA_COMPILER_MSVC) if (localtime_s(&ret, &timet)) #else if (!localtime_r(&timet, &ret)) #endif { LogWarn("Couldn't convert local civil time"); return ToCivilTime(time, true); } } tm _; _.CopyFrom(ret); return _; } AUKN_SYM AuInt64 FromCivilTime(const tm &time, bool UTC) { ::tm tm; time_t timet; time.CopyTo(tm); if (UTC) { tm.tm_isdst = 0; timet = timegm(&tm); } else { tm.tm_isdst = -1; // out of the 2 crts i've bothered to check, out of 3, this is legal timet = mktime(&tm); } if ((timet == 0) || (timet == -1)) { return 0; } return std::chrono::duration_cast(NormalizeEpoch(std::chrono::system_clock::from_time_t(timet).time_since_epoch())).count(); } }