AuroraRuntime/Source/Time/AuCivilTime.cpp

179 lines
4.7 KiB
C++

/***
Copyright (C) 2021-2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuCivilTime.cpp
File: AuClock.cpp
Date: 2023-09-18
Date: 2021-6-13
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuCivilTime.hpp"
#include "Time.hpp"
#if defined(AURORA_IS_MODERNNT_DERIVED)
#define timegm _mkgmtime
#endif
using sys_clock = std::chrono::system_clock; // more stds to remove
static sys_clock::duration gEpoch;
static sys_clock::duration gUnixDelta;
static auto InitEpoch()
{
std::tm start{0, 15, 10, 29, 7, 101, 0, 0, 0};
auto epoch = sys_clock::from_time_t(timegm(&start)).time_since_epoch();
std::tm unixStart{};
unixStart.tm_mday = 1;
unixStart.tm_year = 70;
// dont care what the spec says, you can't trust some ms stls
// sys_clock can have its own epoch for all we care
auto nixEpoch = sys_clock::from_time_t(timegm(&unixStart)).time_since_epoch();
gUnixDelta = epoch - nixEpoch;
gEpoch = epoch;
return 0;
}
static auto ___ = InitEpoch();
sys_clock::duration __NormalizeEpoch(sys_clock::duration sysEpoch)
{
return sysEpoch - gEpoch;
}
sys_clock::duration __DecodeEpoch(sys_clock::duration auroraEpoch)
{
return auroraEpoch + gEpoch;
}
template <typename Duration_t>
static auto TimeFromDurationSinceEpoch(Duration_t in)
{
auto duration = std::chrono::duration_cast<sys_clock::duration>(in);
return std::chrono::time_point<sys_clock>(__DecodeEpoch(duration));
}
template<typename Duration_t>
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<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 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 tm ToCivilTime(AuInt64 time, ETimezoneShift shift)
{
std::tm ret {};
auto timet = MSToCTime(time);
if (shift == ETimezoneShift::eUTC)
{
#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
{
SysPushErrorGeneric("Couldn't convert local civil time");
#if 0
SysPanic();
#else
return ToCivilTime(time, ETimezoneShift::eUTC);
#endif
}
}
tm _;
_.CopyFrom(ret);
return _;
}
AUKN_SYM AuInt64 FromCivilTime(const tm &time, ETimezoneShift shift)
{
::tm tm;
time_t timet;
time.CopyTo(tm);
if (shift == ETimezoneShift::eUTC)
{
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();
}
AUKN_SYM tm NormalizeCivilTimezone(const Time::tm &time, ETimezoneShift shift)
{
if ((time.isdst.ValueOr(-1) == 0) && (shift == ETimezoneShift::eUTC))
{
return time;
}
return ToCivilTime(FromCivilTime(time, shift));
}
}