257 lines
6.9 KiB
C++
257 lines
6.9 KiB
C++
/***
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: Clock.cpp
|
|
Date: 2021-6-13
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#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<typename T>
|
|
static inline T NormalizeEpoch(T sysEpoch)
|
|
{
|
|
return sysEpoch - gEpoch;
|
|
}
|
|
|
|
template<typename T>
|
|
static inline T DecodeEpoch(T auroraEpoch)
|
|
{
|
|
return auroraEpoch + gEpoch;
|
|
}
|
|
|
|
template<typename Clock_t, typename Duration_t>
|
|
static auto TimeFromDurationSinceEpoch(Duration_t in)
|
|
{
|
|
auto duration = std::chrono::duration_cast<typename Clock_t::duration>(in);
|
|
return std::chrono::time_point<Clock_t>(DecodeEpoch(duration));
|
|
}
|
|
|
|
template<typename Duration_t>
|
|
static time_t CalculateTimeT(AuUInt64 in)
|
|
{
|
|
return sys_clock::to_time_t(TimeFromDurationSinceEpoch<sys_clock>(Duration_t(in)));
|
|
}
|
|
|
|
namespace Aurora::Time
|
|
{
|
|
AUKN_SYM time_t SToCTime(AuInt64 time)
|
|
{
|
|
return CalculateTimeT<std::chrono::seconds>(time);
|
|
}
|
|
|
|
AUKN_SYM time_t NSToCTime(AuInt64 time)
|
|
{
|
|
return CalculateTimeT<std::chrono::nanoseconds>(time);
|
|
}
|
|
|
|
AUKN_SYM time_t MSToCTime(AuInt64 time)
|
|
{
|
|
return CalculateTimeT<std::chrono::milliseconds>(time);
|
|
}
|
|
|
|
AUKN_SYM AuUInt64 CurrentClock()
|
|
{
|
|
return NormalizeEpoch(sys_clock::now().time_since_epoch()).count();
|
|
}
|
|
|
|
AUKN_SYM AuUInt64 CurrentClockMS()
|
|
{
|
|
return std::chrono::duration_cast<std::chrono::milliseconds>(NormalizeEpoch(sys_clock::now().time_since_epoch())).count();
|
|
}
|
|
|
|
AUKN_SYM AuUInt64 CurrentClockNS()
|
|
{
|
|
return std::chrono::duration_cast<std::chrono::nanoseconds>(NormalizeEpoch(sys_clock::now().time_since_epoch())).count();
|
|
}
|
|
|
|
AUKN_SYM AuInt64 CTimeToMS(time_t time)
|
|
{
|
|
return std::chrono::duration_cast<std::chrono::milliseconds>(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<std::chrono::milliseconds>(high_res_clock::now().time_since_epoch()).count();
|
|
}
|
|
|
|
AUKN_SYM AuUInt64 CurrentInternalClockNS()
|
|
{
|
|
return std::chrono::duration_cast<std::chrono::nanoseconds>(high_res_clock::now().time_since_epoch()).count();
|
|
}
|
|
|
|
AUKN_SYM AuInt64 ConvertAuroraToUnixMS(AuInt64 in)
|
|
{
|
|
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::milliseconds(in) + gUnixDelta).count();
|
|
}
|
|
|
|
AUKN_SYM AuInt64 ConvertAuroraToUnixNS(AuInt64 in)
|
|
{
|
|
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::nanoseconds(in) + gUnixDelta).count();
|
|
}
|
|
|
|
AUKN_SYM AuInt64 ConvertUnixToAuroraMS(AuInt64 in)
|
|
{
|
|
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::milliseconds(in) - gUnixDelta).count();
|
|
}
|
|
|
|
AUKN_SYM AuInt64 ConvertUnixToAuroraNS(AuInt64 in)
|
|
{
|
|
return std::chrono::duration_cast<std::chrono::nanoseconds>(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<double>(high_res_clock::period::num) / static_cast<double>(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<double>(high_res_clock::period::num) / static_cast<double>(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<double>(high_res_clock::period::den) / static_cast<double>(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<std::chrono::milliseconds>(NormalizeEpoch(std::chrono::system_clock::from_time_t(timet).time_since_epoch())).count();
|
|
}
|
|
}
|