54 template <
typename _NorWT>
55 requires std::same_as<_NorWT, char> || std::same_as<_NorWT, wchar_t>
56 [[nodiscard]]
constexpr const _NorWT*
NorW_1(
const char*
const _Str,
const wchar_t*
const _WStr)
noexcept
58 if constexpr (std::is_same_v<_NorWT, char>) {
65#define _NORW(_NorWT, _Literal) NorW_1<_NorWT>(_Literal, L##_Literal)
76 template <
typename T =
char>
77 requires std::same_as<T, char> || std::same_as<T, wchar_t>
78 static std::basic_string<T>
ISO8601(
const std::chrono::system_clock::time_point& rawtp = std::chrono::system_clock::now())
80 const auto rawtime = std::chrono::system_clock::to_time_t(rawtp);
83 auto msTime = std::chrono::duration_cast<std::chrono::milliseconds>(rawtp.time_since_epoch()).count() % 1000;
85 const auto ec = gmtime_s(&timeInfo, &rawtime);
87 if constexpr (std::is_same_v<T, char>) {
90 std::vector<char> buff(32, 0);
92 if (ec != EINVAL) strftime(buff.data(), buff.capacity(),
"%FT%T", &timeInfo);
93 return std::format(
"{}.{:03}Z", buff.data(), msTime);
95 else if constexpr (std::is_same_v<T, wchar_t>) {
97 std::vector<wchar_t> buff(32, 0);
98 if (ec != EINVAL) wcsftime(buff.data(), buff.capacity(), L
"%FT%T", &timeInfo);
99 return std::format(L
"{}.{:03}Z", buff.data(), msTime);
110 template <
typename T =
char>
111 requires std::same_as<T, char> || std::same_as<T, wchar_t>
112 static std::basic_string<T>
RFC7231(
const std::chrono::system_clock::time_point& rawtp = std::chrono::system_clock::now())
114 auto rawtime = std::chrono::system_clock::to_time_t(rawtp);
118 auto ec = gmtime_s(&timeInfo, &rawtime);
123 if constexpr (std::is_same_v<T, char>) {
124 std::vector<char> buff(32, 0);
125 if (ec != EINVAL) strftime(buff.data(), buff.capacity(),
"%a, %d %h %Y %T GMT", &timeInfo);
130 if constexpr (std::is_same_v<T, wchar_t>) {
131 std::vector<wchar_t> buff(32, 0);
132 if (ec != EINVAL) wcsftime(buff.data(), buff.capacity(), L
"%a, %d %h %Y %T GMT", &timeInfo);
143 template <
typename T =
char>
144 requires std::same_as<T, char> || std::same_as<T, wchar_t>
145 static std::basic_string<T>
toTimespan(
const std::chrono::seconds& arg)
147 auto asSeconds = arg.count();
155 auto hours = (asSeconds / 3600) % 24;
156 auto days = (asSeconds / 86400);
157 auto months = (asSeconds / 2629743);
158 auto years = asSeconds / 31556926;
159 auto weeks = (asSeconds / 604800);
160 auto minutes = (asSeconds / 60) % 60;
161 auto seconds = asSeconds % 60;
163 if constexpr (std::is_same_v<T, char>)
164 return std::format(
"{}.{:02}:{:02}:{:02}", days, hours, minutes, seconds);
165 else if constexpr (std::is_same_v<T, wchar_t>)
166 return std::format(L
"{}.{:02}:{:02}:{:02}", days, hours, minutes, seconds);
175 template <
class T = std::
string>
176 requires std::same_as<T, std::string> || std::same_as<T, std::wstring> || std::same_as<T, uint64_t>
177 static std::chrono::system_clock::time_point
parseEpoch(
const T& arg)
180 uint64_t epoch1ntp {0};
181 uint64_t epoch1millis {0};
182 __time64_t epoch1 {0};
183 std::chrono::system_clock::time_point ret_tp {};
187 if constexpr (std::is_same_v<T, uint64_t>)
189 else if constexpr (std::is_same_v<T, std::string>) {
190 epoch1ntp = std::stoull(arg.data());
192 if (
auto locMilli = arg.find(
"."); locMilli != std::string::npos) {
193 epoch1millis = std::stoull(arg.substr(locMilli + 1).data());
194 epoch1millis *= 1000000;
198 else if constexpr (std::is_same_v<T, std::wstring>) {
199 epoch1ntp = std::stoull(arg.data());
201 if (
auto locMilli = arg.find(L
"."); locMilli != std::string::npos) {
202 epoch1millis = std::stoull(arg.substr(locMilli + 1).data());
203 epoch1millis *= 1000000;
212 epoch1 = (epoch1ntp > 2208988800ULL) ? epoch1ntp - 2208988800ULL : epoch1ntp;
215 _gmtime64_s(&epoch1tm, &epoch1);
218 ret_tp = std::chrono::system_clock::from_time_t(epoch1);
220 ret_tp += std::chrono::milliseconds(epoch1millis);
233 template <
typename T =
char>
234 requires std::same_as<T, char> || std::same_as<T, wchar_t>
235 static std::tuple<std::chrono::milliseconds, std::basic_string<T>>
236 diff(
const std::chrono::time_point<std::chrono::system_clock>& end,
237 const std::chrono::time_point<std::chrono::system_clock>& start)
241 auto delta = end - start;
242 uint64_t uptimeMilliseconds = chrono::duration_cast<chrono::milliseconds>(delta).count();
243 uint64_t uptimeSeconds = chrono::duration_cast<chrono::seconds>(delta).count();
244 uint64_t uptimeMinutes = chrono::duration_cast<chrono::minutes>(delta).count();
245 uint64_t uptimeHours = chrono::duration_cast<chrono::hours>(delta).count();
248 uptimeMinutes = uptimeMinutes % 60i64;
250 uptimeSeconds = (uptimeSeconds - (uptimeMinutes * 60i64)) % 60i64;
252 uptimeMilliseconds = (uptimeMilliseconds) % 1000i64;
256 if constexpr (std::is_same_v<T, char>)
257 return {std::chrono::duration_cast<std::chrono::milliseconds>(delta),
258 std::format(
"{:02}:{:02}:{:02}.{:03}", uptimeHours, uptimeMinutes, uptimeSeconds, uptimeMilliseconds)};
259 else if constexpr (std::is_same_v<T, wchar_t>)
260 return {std::chrono::duration_cast<std::chrono::milliseconds>(delta),
261 std::format(L
"{:02}:{:02}:{:02}.{:03}", uptimeHours, uptimeMinutes, uptimeSeconds, uptimeMilliseconds)};
277 template <
typename T =
char,
typename D = std::chrono::microseconds>
278 requires std::same_as<T, char> || std::same_as<T, wchar_t>
283 std::chrono::days days(std::chrono::duration_cast<std::chrono::days>(arg));
284 std::chrono::months months(std::chrono::duration_cast<std::chrono::months>(arg));
285 std::chrono::years years(std::chrono::duration_cast<std::chrono::years>(arg));
286 std::chrono::weeks weeks(std::chrono::duration_cast<std::chrono::weeks>(arg));
289 std::chrono::hours hours(std::chrono::duration_cast<std::chrono::hours>(arg));
290 std::chrono::minutes minutes((std::chrono::duration_cast<std::chrono::minutes>(arg) / 60s));
291 std::chrono::seconds seconds(std::chrono::duration_cast<std::chrono::seconds>(arg) % 60s);
292 std::chrono::milliseconds millis(std::chrono::duration_cast<std::chrono::milliseconds>(arg) % 1000ms);
293 hours %= std::chrono::days(1);
294 minutes %= std::chrono::hours(1);
295 days -= std::chrono::duration_cast<std::chrono::days>(weeks);
297 if (years > std::chrono::years(0)) {
299 if (millis > 500ms) seconds += 1s;
300 return std::format(
_NORW(T,
"{}years / {}months / {}weeks {} {} {} {}"),
309 else if (months > std::chrono::months(0)) {
311 if (millis > 500ms) seconds += 1s;
313 _NORW(T,
"{}months / {}weeks {} {} {} {}"), months.count(), weeks.count(), days, hours, minutes, seconds);
315 else if (weeks > std::chrono::weeks(0)) {
317 if (millis > 500ms) seconds += 1s;
318 return std::format(
_NORW(T,
"{}weeks {} {} {} {}"), weeks.count(), days, hours, minutes, seconds);
320 else if (days > std::chrono::days(0)) {
322 if (millis > 500ms) seconds += 1s;
323 return std::format(
_NORW(T,
"{} {} {} {}"), days, hours, minutes, seconds);
325 else if (hours > std::chrono::hours(0)) {
327 if (millis > 500ms) seconds += 1s;
328 return std::format(
_NORW(T,
"{} {} {}"), hours, minutes, seconds);
330 else if (millis > std::chrono::milliseconds(0)) {
331 return std::format(
_NORW(T,
"{} {} {}"), minutes, seconds, millis);
334 return std::format(
_NORW(T,
"{} {}"), minutes, seconds);
343 template <
class T =
char>
344 requires std::same_as<T, char> || std::same_as<T, wchar_t>
345 static std::chrono::system_clock::time_point
parseISO8601(
const std::basic_string<T>& arg)
347 uint32_t yearPart = 0, monthPart = 0, dayPart = 0, hourPart = 0, minutePart = 0, secondPart = 0, millisecondPart = 0;
349 if constexpr (std::is_same_v<T, char>) {
351 "%d-%d-%dT%d:%d:%d.%ldZ",
360 else if constexpr (std::is_same_v<T, wchar_t>) {
361 swscanf_s(arg.data(),
362 L
"%d-%d-%dT%d:%d:%d.%ldZ",
372 throw std::invalid_argument(
"Type is not supported; must be std::string[_view] or std::wstring[_view]");
375 if (yearPart > 0 && monthPart > 0 && dayPart > 0) {
377 retTime.tm_year = yearPart - 1900;
378 retTime.tm_mon = monthPart - 1;
379 retTime.tm_mday = dayPart;
380 retTime.tm_hour = hourPart;
381 retTime.tm_min = minutePart;
382 retTime.tm_sec = (int)secondPart;
384 auto tp = std::chrono::system_clock::from_time_t(_mkgmtime(&retTime));
385 tp += std::chrono::milliseconds(millisecondPart);
#define _NORW(_NorWT, _Literal)
constexpr const _NorWT * NorW_1(const char *const _Str, const wchar_t *const _WStr) noexcept
In support of the macro NORW which allows us to declare/use narrow/wide strings as needed....
Date Time utilities for REST API.
static std::basic_string< T > durationString(const D &arg)
Return string with weeks days hours minutes seconds for the provided duration (default microseconds)
static std::basic_string< T > ISO8601(const std::chrono::system_clock::time_point &rawtp=std::chrono::system_clock::now())
Converts the argument to ISO8601 format.
static std::basic_string< T > RFC7231(const std::chrono::system_clock::time_point &rawtp=std::chrono::system_clock::now())
Build a time and date string compliant with the RFC7231.
static std::chrono::system_clock::time_point parseEpoch(const T &arg)
Converts the epoch time into a time_point. The reason for string is due to the permissibility of epoc...
static std::tuple< std::chrono::milliseconds, std::basic_string< T > > diff(const std::chrono::time_point< std::chrono::system_clock > &end, const std::chrono::time_point< std::chrono::system_clock > &start)
Returns a tuple where the first is the chrono::duration<Z> and the second is std::basic_string<T> as.
static std::basic_string< T > toTimespan(const std::chrono::seconds &arg)
Returns D.HH:MM:SS ; days.hours:minutes:seconds.
static std::chrono::system_clock::time_point parseISO8601(const std::basic_string< T > &arg)
Converts from ISO8601 format string into time_point.