From 2c4db439d235b68478d90c450289d2d0ba418547 Mon Sep 17 00:00:00 2001 From: B Stack Date: Wed, 18 Mar 2020 08:59:09 -0400 Subject: add upstream 10.21 --- zen/time.h | 184 +++++++++++-------------------------------------------------- 1 file changed, 32 insertions(+), 152 deletions(-) (limited to 'zen/time.h') diff --git a/zen/time.h b/zen/time.h index 27ce518f..9718e5f6 100644 --- a/zen/time.h +++ b/zen/time.h @@ -8,7 +8,7 @@ #define TIME_H_8457092814324342453627 #include -#include "string_tools.h" +#include "zstring.h" namespace zen @@ -24,7 +24,7 @@ struct TimeComp //replaces std::tm and SYSTEMTIME }; inline bool operator==(const TimeComp& lhs, const TimeComp& rhs) { - return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day && lhs.hour == rhs.hour && lhs.minute == rhs.minute && lhs.second == rhs.second; + return lhs.second == rhs.second && lhs.minute == rhs.minute && lhs.hour == rhs.hour && lhs.day == rhs.day && lhs.month == rhs.month && lhs.year == rhs.year; } inline bool operator!=(const TimeComp& lhs, const TimeComp& rhs) { return !(lhs == rhs); } @@ -37,34 +37,26 @@ time_t utcToTimeT(const TimeComp& tc); //convert UTC time compone TimeComp getCompileTime(); //returns TimeComp() on error //---------------------------------------------------------------------------------------------------------------------------------- - -/* -format (current) date and time; example: - formatTime(L"%Y|%m|%d"); -> "2011|10|29" - formatTime(FORMAT_DATE); -> "2011-10-29" - formatTime(FORMAT_TIME); -> "17:55:34" -*/ -template -String formatTime(const String2& format, const TimeComp& tc = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure +/* format (current) date and time; example: + formatTime(Zstr("%Y|%m|%d")); -> "2011|10|29" + formatTime(formatDateTag); -> "2011-10-29" + formatTime(formatTimeTag); -> "17:55:34" */ +Zstring formatTime(const Zchar* format, const TimeComp& tc = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure //the "format" parameter of formatTime() is partially specialized with the following type tags: -const struct FormatDateTag {} FORMAT_DATE = {}; //%x - locale dependent date representation: e.g. 8/23/2001 -const struct FormatTimeTag {} FORMAT_TIME = {}; //%X - locale dependent time representation: e.g. 2:55:02 PM -const struct FormatDateTimeTag {} FORMAT_DATE_TIME = {}; //%c - locale dependent date and time: e.g. 8/23/2001 2:55:02 PM +const Zchar* const formatDateTag = Zstr("%x"); //locale-dependent date representation: e.g. 8/23/2001 +const Zchar* const formatTimeTag = Zstr("%X"); //locale-dependent time representation: e.g. 2:55:02 PM +const Zchar* const formatDateTimeTag = Zstr("%c"); //locale-dependent date and time: e.g. 8/23/2001 2:55:02 PM -const struct FormatIsoDateTag {} FORMAT_ISO_DATE = {}; //%Y-%m-%d - e.g. 2001-08-23 -const struct FormatIsoTimeTag {} FORMAT_ISO_TIME = {}; //%H:%M:%S - e.g. 14:55:02 -const struct FormatIsoDateTimeTag {} FORMAT_ISO_DATE_TIME = {}; //%Y-%m-%d %H:%M:%S - e.g. 2001-08-23 14:55:02 +const Zchar* const formatIsoDateTag = Zstr("%Y-%m-%d"); //e.g. 2001-08-23 +const Zchar* const formatIsoTimeTag = Zstr("%H:%M:%S"); //e.g. 14:55:02 +const Zchar* const formatIsoDateTimeTag = Zstr("%Y-%m-%d %H:%M:%S"); //e.g. 2001-08-23 14:55:02 //---------------------------------------------------------------------------------------------------------------------------------- - -/* -example: parseTime("%Y-%m-%d %H:%M:%S", "2001-08-23 14:55:02"); - parseTime(FORMAT_ISO_DATE_TIME, "2001-08-23 14:55:02"); -*/ +//example: parseTime("%Y-%m-%d %H:%M:%S", "2001-08-23 14:55:02"); +// parseTime(formatIsoDateTimeTag, "2001-08-23 14:55:02"); template TimeComp parseTime(const String& format, const String2& str); //similar to ::strptime() - //---------------------------------------------------------------------------------------------------------------------------------- @@ -118,68 +110,6 @@ TimeComp toZenTimeComponents(const std::tm& ctc) } -template -struct GetFormat; //get default time formats as char* or wchar_t* - -template <> -struct GetFormat //%x - locale dependent date representation: e.g. 08/23/01 -{ - const char* format(char) const { return "%x"; } - const wchar_t* format(wchar_t) const { return L"%x"; } -}; - -template <> -struct GetFormat //%X - locale dependent time representation: e.g. 14:55:02 -{ - const char* format(char) const { return "%X"; } - const wchar_t* format(wchar_t) const { return L"%X"; } -}; - -template <> -struct GetFormat //%c - locale dependent date and time: e.g. Thu Aug 23 14:55:02 2001 -{ - const char* format(char) const { return "%c"; } - const wchar_t* format(wchar_t) const { return L"%c"; } -}; - -template <> -struct GetFormat //%Y-%m-%d - e.g. 2001-08-23 -{ - const char* format(char) const { return "%Y-%m-%d"; } - const wchar_t* format(wchar_t) const { return L"%Y-%m-%d"; } -}; - -template <> -struct GetFormat //%H:%M:%S - e.g. 14:55:02 -{ - const char* format(char) const { return "%H:%M:%S"; } - const wchar_t* format(wchar_t) const { return L"%H:%M:%S"; } -}; - -template <> -struct GetFormat //%Y-%m-%d %H:%M:%S - e.g. 2001-08-23 14:55:02 -{ - const char* format(char) const { return "%Y-%m-%d %H:%M:%S"; } - const wchar_t* format(wchar_t) const { return L"%Y-%m-%d %H:%M:%S"; } -}; - - -//strftime() craziness on invalid input: -// VS 2010: CRASH unless "_invalid_parameter_handler" is set: https://msdn.microsoft.com/en-us/library/ksazx244.aspx -// GCC: returns 0, apparently no crash. Still, considering some clib maintainer's comments, we should expect the worst! -inline -size_t strftimeWrap_impl(char* buffer, size_t bufferSize, const char* format, const std::tm* timeptr) -{ - return std::strftime(buffer, bufferSize, format, timeptr); -} - - -inline -size_t strftimeWrap_impl(wchar_t* buffer, size_t bufferSize, const wchar_t* format, const std::tm* timeptr) -{ - return std::wcsftime(buffer, bufferSize, format, timeptr); -} - /* inline bool isValid(const std::tm& t) @@ -203,35 +133,6 @@ bool isValid(const std::tm& t) //tm_isdst }; */ - -template inline -size_t strftimeWrap(CharType* buffer, size_t bufferSize, const CharType* format, const std::tm* timeptr) -{ - return strftimeWrap_impl(buffer, bufferSize, format, timeptr); -} - - -struct UserDefinedFormatTag {}; -struct PredefinedFormatTag {}; - -template inline -String formatTime(const String2& format, const TimeComp& tc, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure -{ - std::tm ctc = toClibTimeComponents(tc); - std::mktime(&ctc); // unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday - //note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent - - GetCharTypeT buffer[256] = {}; - const size_t charsWritten = strftimeWrap(buffer, 256, strBegin(format), &ctc); - return String(buffer, charsWritten); -} - - -template inline -String formatTime(FormatType, const TimeComp& tc, PredefinedFormatTag) -{ - return formatTime(GetFormat().format(GetCharTypeT()), tc, UserDefinedFormatTag()); -} } @@ -298,28 +199,29 @@ TimeComp getCompileTime() } -template inline -String formatTime(const String2& format, const TimeComp& tc) +inline +Zstring formatTime(const Zchar* format, const TimeComp& tc) { if (tc == TimeComp()) //failure code from getLocalTime() - return String(); + return Zstring(); - using FormatTag = std::conditional_t< - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>; + std::tm ctc = impl::toClibTimeComponents(tc); + std::mktime(&ctc); //unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday + //note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent - return impl::formatTime(format, tc, FormatTag()); + Zstring buffer(256, Zstr('\0')); + //strftime() craziness on invalid input: + // VS 2010: CRASH unless "_invalid_parameter_handler" is set: https://docs.microsoft.com/en-us/cpp/c-runtime-library/parameter-validation + // GCC: returns 0, apparently no crash. Still, considering some clib maintainer's comments, we should expect the worst! + // Windows: avoid char-based strftime() which uses ANSI encoding! (e.g. Greek letters for AM/PM) + const size_t charsWritten = std::strftime(&buffer[0], buffer.size(), format, &ctc); + buffer.resize(charsWritten); + return buffer; } -namespace impl -{ template -TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTag) +TimeComp parseTime(const String& format, const String2& str) { using CharType = GetCharTypeT; static_assert(std::is_same_v>); @@ -371,11 +273,9 @@ TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTa return TimeComp(); const char* months[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }; - auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* name) + auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* month) { - return asciiToLower(itStr[0]) == name[0] && - asciiToLower(itStr[1]) == name[1] && - asciiToLower(itStr[2]) == name[2]; + return equalAsciiNoCase(makeStringView(itStr, 3), month); }); if (itMonth == std::end(months)) return TimeComp(); @@ -422,26 +322,6 @@ TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTa return output; } - - -template inline -TimeComp parseTime(FormatType, const String& str, PredefinedFormatTag) -{ - return parseTime(GetFormat().format(GetCharTypeT()), str, UserDefinedFormatTag()); -} -} - - -template inline -TimeComp parseTime(const String& format, const String2& str) -{ - using FormatTag = std::conditional_t< - std::is_same_v || - std::is_same_v || - std::is_same_v, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>; - - return impl::parseTime(format, str, FormatTag()); -} } #endif //TIME_H_8457092814324342453627 -- cgit