From e28c61e431842f83a2375039460f83b3373ac623 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Mon, 21 Aug 2023 16:33:03 +0200 Subject: [PATCH] chrono: finish AOsn date and time-stamp implementations Signed-off-by: Simon Rozman --- include/stdex/chrono.hpp | 241 +++++++++++++++++++++++++++++++-------- 1 file changed, 196 insertions(+), 45 deletions(-) diff --git a/include/stdex/chrono.hpp b/include/stdex/chrono.hpp index 73c045c29..05383cd44 100644 --- a/include/stdex/chrono.hpp +++ b/include/stdex/chrono.hpp @@ -14,28 +14,19 @@ namespace stdex { namespace chrono { - struct aosn_clock + /// + /// AOsn date + /// + struct aosn_date { - using rep = int64_t; - using period = std::ratio<1, 1'000'000>; // 1 microsecond + using rep = int32_t; + using period = std::ratio<86400>; // 1 day using duration = std::chrono::duration; - using time_point = std::chrono::time_point; + using time_point = std::chrono::time_point; static constexpr bool is_steady = false; - static constexpr rep f_second = 1000; // number of milliseconds per second - static constexpr rep f_minute = 60; // number of seconds per minute - static constexpr rep f_hour = 60; // number of minutes na hour - static constexpr rep f_day = 24; // number of hours na day - static constexpr rep f_week = 7; // number of days per week - - static constexpr rep second = f_second; // number of milliseconds per second - static constexpr rep minute = f_minute * second; // number of milliseconds per minute - static constexpr rep hour = f_hour * minute; // number of milliseconds per hour - static constexpr rep day = f_day * hour; // number of milliseconds per day - static constexpr rep week = f_week * day; // number of milliseconds per week - /// - /// Gets current time + /// Gets current date /// static time_point now() noexcept { @@ -50,23 +41,64 @@ namespace stdex { #endif } - static inline int32_t now_jul(_Out_opt_ uint32_t* hour = nullptr) noexcept + /// + /// Returns time_t from time point + /// + static __time64_t to_time_t(_In_ const time_point tp) noexcept { -#ifdef _WIN32 - SYSTEMTIME t; - GetSystemTime(&t); - duration tp = from_system(t).time_since_epoch(); -#else - struct timespec t; - clock_gettime(CLOCK_REALTIME, &t); - duration tp = from_system(t).time_since_epoch(); -#endif - if (hour) - *hour = (uint32_t)(tp.count() % day); - return (uint32_t)(tp.count() / day); + return static_cast<__time64_t>(tp.time_since_epoch().count()) * 86400 - 210866803200; } - static int32_t gre2jul(_In_ uint8_t day, _In_ uint8_t month, _In_ int32_t year) noexcept + /// + /// Returns time point from time_t + /// + static time_point from_time_t(_In_ __time64_t t) noexcept + { + return time_point(duration(static_cast((t + 210866803200) / 86400))); + } + +#ifdef _WIN32 + /// + /// Returns time point from SYSTEMTIME + /// + static time_point from_system(_In_ const SYSTEMTIME& t) noexcept + { + return from_dmy(static_cast(t.wDay), static_cast(t.wMonth), static_cast(t.wYear)); + } + + /// + /// Returns time point from FILETIME + /// + static time_point from_system(_In_ const FILETIME& t) noexcept + { + uint64_t x = ((static_cast(t.dwHighDateTime)) << 32) | t.dwLowDateTime; + return time_point(duration(static_cast(x / 86400000 + 2305814))); // Convert from 100 ns to 1-day interval and adjust epoch + } + + /// + /// Returns time point from DATE + /// + static time_point from_system(_In_ DATE t) + { + SYSTEMTIME st; + if (!VariantTimeToSystemTime(t, &st)) + throw std::invalid_argument("failed to convert date from VARIANT_DATE"); + return from_system(st); + } +#else + /// + /// Returns time point from struct timespec + /// + static time_point from_system(_In_ const struct timespec& t) noexcept + { + return from_time_t(t.tv_sec); + } +#endif + + /// + /// Returns time point from calendar day, month and year + /// + static time_point from_dmy(_In_ uint8_t day, _In_ uint8_t month, _In_ int32_t year) noexcept { int32_t mtmp, ytmp; if (month > 2) { @@ -77,19 +109,20 @@ namespace stdex { mtmp = month + 9; ytmp = year - 1; } - int32_t ctmp = (ytmp / 100); int32_t dtmp = ytmp - (100 * ctmp); int32_t result1 = 146097L * ctmp / 4; int32_t result2 = (1461 * dtmp) / 4; int32_t result3 = (153 * mtmp + 2) / 5; - - return (int32_t)result1 + day + result2 + 1721119L + result3; + return time_point(duration(static_cast(result1) + day + result2 + 1721119L + result3)); } - static void jul2gre(_In_ int32_t jul, _Out_opt_ uint8_t* day, _Out_opt_ uint8_t* month, _Out_opt_ int32_t* year) noexcept + /// + /// Returns calendar day, month and year from time point + /// + static void to_dmy(_In_ const time_point tp, _Out_opt_ uint8_t* day, _Out_opt_ uint8_t* month, _Out_opt_ int32_t* year) noexcept { - int32_t mtmp = jul - 1721119L; + int32_t mtmp = tp.time_since_epoch().count() - 1721119L; int32_t yr = (4 * mtmp - 1) / 146097L; mtmp = 4 * mtmp - 1 - 146097L * yr; int32_t da = mtmp / 4; @@ -100,43 +133,112 @@ namespace stdex { da = 5 * da - 3 - 153 * mo; da = (da + 5) / 5; yr = 100 * yr + mtmp; - if (mo < 10) mo += 3; else { mo -= 9; yr++; } - if (day) *day = static_cast(da); if (month) *month = static_cast(mo); if (year) *year = yr; } - static __time64_t to_time_t(_In_ const time_point& tp) noexcept + /// + /// Returns day-of-week from time point (0 = Mon, 1 = Tue...) + /// + static uint8_t day_of_week(_In_ const time_point tp) { - return tp.time_since_epoch().count() / second - 210866803200; + return static_cast(tp.time_since_epoch().count() % 7); } + /// + /// Returns day-of-week from calendar day, month and year (0 = Mon, 1 = Tue...) + /// + static uint8_t day_of_week(_In_ uint8_t day, _In_ uint8_t month, _In_ int32_t year) + { + return static_cast(from_dmy(day, month, year).time_since_epoch().count() % 7); + } + }; + + /// + /// AOsn timestamp + /// + struct aosn_timestamp + { + using rep = int64_t; + using period = std::ratio<1, 1'000'000>; // 1 microsecond + using duration = std::chrono::duration; + using time_point = std::chrono::time_point; + static constexpr bool is_steady = false; + + static constexpr rep f_second = 1000; // number of milliseconds per second + static constexpr rep f_minute = 60; // number of seconds per minute + static constexpr rep f_hour = 60; // number of minutes per hour + static constexpr rep f_day = 24; // number of hours per day + static constexpr rep f_week = 7; // number of days per week + + static constexpr rep p_second = f_second; // number of milliseconds per second + static constexpr rep p_minute = f_minute * p_second; // number of milliseconds per minute + static constexpr rep p_hour = f_hour * p_minute; // number of milliseconds per hour + static constexpr rep p_day = f_day * p_hour; // number of milliseconds per day + static constexpr rep p_week = f_week * p_day; // number of milliseconds per week + + /// + /// Gets current timestamp + /// + static time_point now() noexcept + { +#ifdef _WIN32 + FILETIME t; + GetSystemTimeAsFileTime(&t); + return from_system(t); +#else + time_t t; + time(&t); + return from_time_t(t); +#endif + } + + /// + /// Returns time_t from time point + /// + static __time64_t to_time_t(_In_ const time_point tp) noexcept + { + return tp.time_since_epoch().count() / p_second - 210866803200; + } + + /// + /// Returns time point from time_t + /// static time_point from_time_t(_In_ __time64_t t) noexcept { - return time_point(duration(((rep)t + 210866803200) * second)); + return time_point(duration((static_cast(t) + 210866803200) * p_second)); } #ifdef _WIN32 + /// + /// Returns time point from SYSTEMTIME + /// static time_point from_system(_In_ const SYSTEMTIME& t) noexcept { - return time_point(duration( - ((rep)gre2jul((uint8_t)t.wDay, (uint8_t)t.wMonth, (int32_t)t.wYear)) * day + - ((rep)t.wHour * hour + (rep)t.wMinute * minute + (rep)t.wSecond * second + t.wMilliseconds))); + return from_dmy( + static_cast(t.wDay), static_cast(t.wMonth), static_cast(t.wYear), + static_cast(t.wHour), static_cast(t.wMinute), static_cast(t.wSecond), static_cast(t.wMilliseconds)); } + /// + /// Returns time point from FILETIME + /// static time_point from_system(_In_ const FILETIME& t) noexcept { - rep x = (((rep)t.dwHighDateTime) << 32) | t.dwLowDateTime; + rep x = ((static_cast(t.dwHighDateTime)) << 32) | t.dwLowDateTime; return time_point(duration(x / 10000 + 199222329600000)); // Convert from 100 ns to 1 ms interval and adjust epoch } + /// + /// Returns time point from DATE + /// static time_point from_system(_In_ DATE t) { SYSTEMTIME st; @@ -145,11 +247,60 @@ namespace stdex { return from_system(st); } #else + /// + /// Returns time point from struct timespec + /// static time_point from_system(_In_ const struct timespec& t) noexcept { return from_time_t(t.tv_sec) + t.tv_nsec / 1000; } #endif + + /// + /// Returns aosn_date::time_point from time point + /// + static aosn_date::time_point to_date(_In_ time_point tp) noexcept + { + return aosn_date::time_point(aosn_date::duration(static_cast(tp.time_since_epoch().count() / p_day))); + } + + /// + /// Returns time point from aosn_date::time_point + /// + static time_point from_date(_In_ aosn_date::time_point date) noexcept + { + return time_point(duration(static_cast(date.time_since_epoch().count()) * p_day)); + } + + /// + /// Returns time point from calendar day, month, year and time + /// + static time_point from_dmy( + _In_ uint8_t day, _In_ uint8_t month, _In_ int32_t year, + _In_ uint8_t hour, _In_ uint8_t minute, _In_ uint8_t second, _In_ uint16_t millisecond) noexcept + { + return time_point(duration( + (static_cast(aosn_date::from_dmy(day, month, year).time_since_epoch().count()) * p_day) + + (static_cast(hour) * p_hour + static_cast(minute) * p_minute + static_cast(second) * p_second + millisecond))); + } + + /// + /// Returns calendar day, month, year and time from time point + /// + static void to_dmy(_In_ const time_point tp, + _Out_opt_ uint8_t* day, _Out_opt_ uint8_t* month, _Out_opt_ int32_t* year, + _Out_opt_ uint8_t* hour, _Out_opt_ uint8_t* minute, _Out_opt_ uint8_t* second, _Out_opt_ uint16_t* millisecond) noexcept + { + aosn_date::to_dmy(to_date(tp), day, month, year); + int32_t u = static_cast(tp.time_since_epoch().count() % p_day); + if (millisecond) *millisecond = static_cast(u % f_second); + u = u / f_second; + if (second) *second = static_cast(u % f_minute); + u = u / f_minute; + if (minute) *minute = static_cast(u % f_hour); + u = u / f_hour; + if (hour) *hour = static_cast(u); + } }; } }