stdex
Additional custom or not Standard C++ covered algorithms
Loading...
Searching...
No Matches
chrono.hpp
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 2023 Amebis
4*/
5
6#pragma once
7
8#include "sal.hpp"
9#include "system.hpp"
10#include "string.hpp"
11#include <stdint.h>
12#include <chrono>
13#include <memory>
14#include <stdexcept>
15
16namespace stdex {
17 namespace chrono
18 {
22 struct aosn_date
23 {
24 using rep = int32_t;
25 using period = std::ratio<86400>; // 1 day
26 using duration = std::chrono::duration<rep, period>;
27 using time_point = std::chrono::time_point<aosn_date>;
28 static constexpr bool is_steady = false;
29
33 static time_point now() noexcept
34 {
35#ifdef _WIN32
36 FILETIME t;
37 GetSystemTimeAsFileTime(&t);
38 return from_system(t);
39#else
40 time_t t;
41 time(&t);
42 return from_time_t(t);
43#endif
44 }
45
49 static __time64_t to_time_t(_In_ const time_point tp) noexcept
50 {
51 return static_cast<__time64_t>(tp.time_since_epoch().count()) * 86400 - 210866803200;
52 }
53
57 static time_point from_time_t(_In_ __time64_t t) noexcept
58 {
59 return time_point(duration(static_cast<rep>((t + 210866803200) / 86400)));
60 }
61
62#ifdef _WIN32
66 static time_point from_system(_In_ const SYSTEMTIME& t) noexcept
67 {
68 return from_dmy(static_cast<uint8_t>(t.wDay), static_cast<uint8_t>(t.wMonth), static_cast<int32_t>(t.wYear));
69 }
70
74 static time_point from_system(_In_ const FILETIME& t) noexcept
75 {
76 uint64_t x = ((static_cast<uint64_t>(t.dwHighDateTime)) << 32) | t.dwLowDateTime;
77 return time_point(duration(static_cast<rep>(x / 86400000 + 2305814))); // Convert from 100 ns to 1-day interval and adjust epoch
78 }
79
83 static time_point from_system(_In_ DATE t)
84 {
85 SYSTEMTIME st;
86 if (!VariantTimeToSystemTime(t, &st))
87 throw std::invalid_argument("failed to convert date from VARIANT_DATE");
88 return from_system(st);
89 }
90#else
94 static time_point from_system(_In_ const struct timespec& t) noexcept
95 {
96 return from_time_t(t.tv_sec);
97 }
98#endif
99
103 static time_point from_dmy(_In_ uint8_t day, _In_ uint8_t month, _In_ int32_t year) noexcept
104 {
105 int32_t mtmp, ytmp;
106 if (month > 2) {
107 mtmp = month - 3;
108 ytmp = year;
109 }
110 else {
111 mtmp = month + 9;
112 ytmp = year - 1;
113 }
114 int32_t ctmp = (ytmp / 100);
115 int32_t dtmp = ytmp - (100 * ctmp);
116 int32_t result1 = 146097L * ctmp / 4;
117 int32_t result2 = (1461 * dtmp) / 4;
118 int32_t result3 = (153 * mtmp + 2) / 5;
119 return time_point(duration(static_cast<int32_t>(result1) + day + result2 + 1721119L + result3));
120 }
121
125 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
126 {
127 int32_t mtmp = tp.time_since_epoch().count() - 1721119L;
128 int32_t yr = (4 * mtmp - 1) / 146097L;
129 mtmp = 4 * mtmp - 1 - 146097L * yr;
130 int32_t da = mtmp / 4;
131 mtmp = (4 * da + 3) / 1461;
132 da = 4 * da + 3 - 1461 * mtmp;
133 da = (da + 4) / 4;
134 int32_t mo = (5 * da - 3) / 153;
135 da = 5 * da - 3 - 153 * mo;
136 da = (da + 5) / 5;
137 yr = 100 * yr + mtmp;
138 if (mo < 10)
139 mo += 3;
140 else {
141 mo -= 9;
142 yr++;
143 }
144 if (day) *day = static_cast<uint8_t>(da);
145 if (month) *month = static_cast<uint8_t>(mo);
146 if (year) *year = yr;
147 }
148
152 static uint8_t day_of_week(_In_ const time_point tp)
153 {
154 return static_cast<uint8_t>(tp.time_since_epoch().count() % 7);
155 }
156
160 static uint8_t day_of_week(_In_ uint8_t day, _In_ uint8_t month, _In_ int32_t year)
161 {
162 return static_cast<uint8_t>(from_dmy(day, month, year).time_since_epoch().count() % 7);
163 }
164 };
165
170 {
171 using rep = int64_t;
172 using period = std::ratio<1, 1'000'000>; // 1 microsecond
173 using duration = std::chrono::duration<rep, period>;
174 using time_point = std::chrono::time_point<aosn_timestamp>;
175 static constexpr bool is_steady = false;
176
177 static constexpr rep f_second = 1000; // number of milliseconds per second
178 static constexpr rep f_minute = 60; // number of seconds per minute
179 static constexpr rep f_hour = 60; // number of minutes per hour
180 static constexpr rep f_day = 24; // number of hours per day
181 static constexpr rep f_week = 7; // number of days per week
182
183 static constexpr rep p_second = f_second; // number of milliseconds per second
184 static constexpr rep p_minute = f_minute * p_second; // number of milliseconds per minute
185 static constexpr rep p_hour = f_hour * p_minute; // number of milliseconds per hour
186 static constexpr rep p_day = f_day * p_hour; // number of milliseconds per day
187 static constexpr rep p_week = f_week * p_day; // number of milliseconds per week
188
192 static time_point now() noexcept
193 {
194#ifdef _WIN32
195 FILETIME t;
196 GetSystemTimeAsFileTime(&t);
197 return from_system(t);
198#else
199 time_t t;
200 time(&t);
201 return from_time_t(t);
202#endif
203 }
204
208 static __time64_t to_time_t(_In_ const time_point tp) noexcept
209 {
210 return tp.time_since_epoch().count() / p_second - 210866803200;
211 }
212
216 static time_point from_time_t(_In_ __time64_t t) noexcept
217 {
218 return time_point(duration((static_cast<rep>(t) + 210866803200) * p_second));
219 }
220
221#ifdef _WIN32
225 static time_point from_system(_In_ const SYSTEMTIME& t) noexcept
226 {
227 return from_dmy(
228 static_cast<uint8_t>(t.wDay), static_cast<uint8_t>(t.wMonth), static_cast<int32_t>(t.wYear),
229 static_cast<uint8_t>(t.wHour), static_cast<uint8_t>(t.wMinute), static_cast<uint8_t>(t.wSecond), static_cast<uint16_t>(t.wMilliseconds));
230 }
231
235 static time_point from_system(_In_ const FILETIME& t) noexcept
236 {
237 rep x = ((static_cast<rep>(t.dwHighDateTime)) << 32) | t.dwLowDateTime;
238 return time_point(duration(x / 10000 + 199222329600000)); // Convert from 100 ns to 1 ms interval and adjust epoch
239 }
240
244 static time_point from_system(_In_ DATE t)
245 {
246 SYSTEMTIME st;
247 if (!VariantTimeToSystemTime(t, &st))
248 throw std::invalid_argument("failed to convert date from VARIANT_DATE");
249 return from_system(st);
250 }
251#else
255 static time_point from_system(_In_ const struct timespec& t) noexcept
256 {
257 return from_time_t(t.tv_sec) + t.tv_nsec / 1000;
258 }
259#endif
260
261 static void to_system(_In_ time_point tp, _Out_ struct tm& date) noexcept
262 {
263 uint8_t day, month, hour, minute, second;
264 uint16_t millisecond;
265 int32_t year;
266 to_dmy(tp, &day, &month, &year, &hour, &minute, &second, &millisecond);
267 date.tm_sec = second;
268 date.tm_min = minute;
269 date.tm_hour = hour;
270 date.tm_mday = day;
271 date.tm_mon = month - 1;
272 date.tm_year = year - 1900;
273 date.tm_wday = (static_cast<int>(aosn_date::day_of_week(to_date(tp))) + 1) % 7;
274 date.tm_yday = 0;
275 date.tm_isdst = 0;
276 }
277
281 static aosn_date::time_point to_date(_In_ time_point tp) noexcept
282 {
283 return aosn_date::time_point(aosn_date::duration(static_cast<aosn_date::rep>(tp.time_since_epoch().count() / p_day)));
284 }
285
289 static time_point from_date(_In_ aosn_date::time_point date) noexcept
290 {
291 return time_point(duration(static_cast<rep>(date.time_since_epoch().count()) * p_day));
292 }
293
297 static time_point from_dmy(
298 _In_ uint8_t day, _In_ uint8_t month, _In_ int32_t year,
299 _In_ uint8_t hour, _In_ uint8_t minute, _In_ uint8_t second, _In_ uint16_t millisecond) noexcept
300 {
301 return time_point(duration(
302 (static_cast<rep>(aosn_date::from_dmy(day, month, year).time_since_epoch().count()) * p_day) +
303 (static_cast<rep>(hour) * p_hour + static_cast<rep>(minute) * p_minute + static_cast<rep>(second) * p_second + millisecond)));
304 }
305
309 static void to_dmy(_In_ const time_point tp,
310 _Out_opt_ uint8_t* day, _Out_opt_ uint8_t* month, _Out_opt_ int32_t* year,
311 _Out_opt_ uint8_t* hour, _Out_opt_ uint8_t* minute, _Out_opt_ uint8_t* second, _Out_opt_ uint16_t* millisecond) noexcept
312 {
313 aosn_date::to_dmy(to_date(tp), day, month, year);
314 int32_t u = static_cast<int32_t>(tp.time_since_epoch().count() % p_day);
315 if (millisecond) *millisecond = static_cast<uint16_t>(u % f_second);
316 u = u / f_second;
317 if (second) *second = static_cast<uint8_t>(u % f_minute);
318 u = u / f_minute;
319 if (minute) *minute = static_cast<uint8_t>(u % f_hour);
320 u = u / f_hour;
321 if (hour) *hour = static_cast<uint8_t>(u);
322 }
323
324 template<class _Traits = std::char_traits<char>, class _Ax = std::allocator<char>>
325 static std::basic_string<char, _Traits, _Ax> to_str(_In_ const time_point tp, _In_z_ const char* format, _In_opt_ locale_t locale)
326 {
327 struct tm date;
328 to_system(tp, date);
329 std::basic_string<char, _Traits, _Ax> str;
330 char stack_buffer[1024 / sizeof(char)];
331 size_t n;
332#if _WIN32
333 n = _strftime_l(stack_buffer, _countof(stack_buffer), format, &date, locale);
334#else
335 n = strftime_l(stack_buffer, _countof(stack_buffer), format, &date, locale);
336#endif
337 if (n) {
338 str.assign(stack_buffer, stack_buffer + n);
339 return str;
340 }
341 size_t num_chars = stdex::mul(_countof(stack_buffer), 2);
342 for (;;) {
343 std::unique_ptr<char> buf(new char[num_chars]);
344#if _WIN32
345 n = _strftime_l(buf.get(), num_chars, format, &date, locale);
346#else
347 n = strftime_l(buf.get(), num_chars, format, &date, locale);
348#endif
349 if (n) {
350 str.assign(buf.get(), buf.get() + n);
351 return str;
352 }
353 num_chars = stdex::mul(num_chars, 2);
354 }
355 }
356
357 template<class _Traits = std::char_traits<wchar_t>, class _Ax = std::allocator<wchar_t>>
358 static std::basic_string<wchar_t, _Traits, _Ax> to_str(_In_ const time_point tp, _In_z_ const wchar_t* format, _In_opt_ locale_t locale)
359 {
360 struct tm date;
361 to_system(tp, date);
362 std::basic_string<wchar_t, _Traits, _Ax> str;
363 wchar_t stack_buffer[1024 / sizeof(wchar_t)];
364 size_t n;
365#if _WIN32
366 n = _wcsftime_l(stack_buffer, _countof(stack_buffer), format, &date, locale);
367#else
368 n = wcsftime_l(stack_buffer, _countof(stack_buffer), format, &date, locale);
369#endif
370 if (n) {
371 str.assign(stack_buffer, stack_buffer + n);
372 return str;
373 }
374 size_t num_chars = stdex::mul(_countof(stack_buffer), 2);
375 for (;;) {
376 std::unique_ptr<wchar_t> buf(new wchar_t[num_chars]);
377#if _WIN32
378 n = _wcsftime_l(buf.get(), num_chars, format, &date, locale);
379#else
380 n = wcsftime_l(buf.get(), num_chars, format, &date, locale);
381#endif
382 if (n) {
383 str.assign(buf.get(), buf.get() + n);
384 return str;
385 }
386 num_chars = stdex::mul(num_chars, 2);
387 }
388 }
389
390 template<class _Traits = std::char_traits<char>, class _Ax = std::allocator<char>>
391 static std::basic_string<char, _Traits, _Ax> to_rfc822(_In_ const time_point tp)
392 {
393 return to_str(tp, "%a, %d %b %Y %H:%M:%S GMT", locale_C.get());
394 }
395 };
396 }
397}
AOsn date.
Definition chrono.hpp:23
static time_point from_dmy(uint8_t day, uint8_t month, int32_t year) noexcept
Returns time point from calendar day, month and year.
Definition chrono.hpp:103
static void to_dmy(const time_point tp, uint8_t *day, uint8_t *month, int32_t *year) noexcept
Returns calendar day, month and year from time point.
Definition chrono.hpp:125
static __time64_t to_time_t(const time_point tp) noexcept
Returns time_t from time point.
Definition chrono.hpp:49
static uint8_t day_of_week(const time_point tp)
Returns day-of-week from time point (0 = Mon, 1 = Tue...)
Definition chrono.hpp:152
static uint8_t day_of_week(uint8_t day, uint8_t month, int32_t year)
Returns day-of-week from calendar day, month and year (0 = Mon, 1 = Tue...)
Definition chrono.hpp:160
static time_point from_time_t(__time64_t t) noexcept
Returns time point from time_t.
Definition chrono.hpp:57
static time_point from_system(const struct timespec &t) noexcept
Returns time point from struct timespec.
Definition chrono.hpp:94
static time_point now() noexcept
Gets current date.
Definition chrono.hpp:33
AOsn timestamp.
Definition chrono.hpp:170
static __time64_t to_time_t(const time_point tp) noexcept
Returns time_t from time point.
Definition chrono.hpp:208
static time_point from_date(aosn_date::time_point date) noexcept
Returns time point from aosn_date::time_point.
Definition chrono.hpp:289
static time_point from_dmy(uint8_t day, uint8_t month, int32_t year, uint8_t hour, uint8_t minute, uint8_t second, uint16_t millisecond) noexcept
Returns time point from calendar day, month, year and time.
Definition chrono.hpp:297
static aosn_date::time_point to_date(time_point tp) noexcept
Returns aosn_date::time_point from time point.
Definition chrono.hpp:281
static time_point from_system(const struct timespec &t) noexcept
Returns time point from struct timespec.
Definition chrono.hpp:255
static time_point from_time_t(__time64_t t) noexcept
Returns time point from time_t.
Definition chrono.hpp:216
static time_point now() noexcept
Gets current timestamp.
Definition chrono.hpp:192
static void to_dmy(const time_point tp, uint8_t *day, uint8_t *month, int32_t *year, uint8_t *hour, uint8_t *minute, uint8_t *second, uint16_t *millisecond) noexcept
Returns calendar day, month, year and time from time point.
Definition chrono.hpp:309