From 9b623ea3943165fe7efb5e47a0b5b9452c1599e6 Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Wed, 9 May 2018 00:09:55 +0200 Subject: 9.8 --- zen/time.h | 199 ++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 119 insertions(+), 80 deletions(-) (limited to 'zen/time.h') diff --git a/zen/time.h b/zen/time.h index 67156b9a..74898c7c 100755 --- a/zen/time.h +++ b/zen/time.h @@ -22,19 +22,19 @@ struct TimeComp //replaces std::tm and SYSTEMTIME int minute = 0; //0-59 int second = 0; //0-60 (including leap second) }; - 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; } +inline bool operator!=(const TimeComp& lhs, const TimeComp& rhs) { return !(lhs == rhs); } -TimeComp getLocalTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to local time components -time_t localToTimeT(const TimeComp& comp); //convert local time components to time_t (UTC), returns -1 on error +TimeComp getLocalTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to local time components, returns TimeComp() on error +time_t localToTimeT(const TimeComp& tc); //convert local time components to time_t (UTC), returns -1 on error -TimeComp getUtcTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to UTC time components -time_t utcToTimeT(const TimeComp& comp); //convert UTC time components to time_t (UTC), returns -1 on error +TimeComp getUtcTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to UTC time components, returns TimeComp() on error +time_t utcToTimeT(const TimeComp& tc); //convert UTC time components to time_t (UTC), returns -1 on error -TimeComp getCompileTime(); +TimeComp getCompileTime(); //returns TimeComp() on error //---------------------------------------------------------------------------------------------------------------------------------- @@ -45,7 +45,7 @@ format (current) date and time; example: formatTime(FORMAT_TIME); -> "17:55:34" */ template -String formatTime(const String2& format, const TimeComp& comp = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure +String formatTime(const String2& 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. 08/23/01 @@ -58,8 +58,12 @@ const struct FormatIsoDateTimeTag {} FORMAT_ISO_DATE_TIME = {}; //%Y-%m-%d %H:%M //---------------------------------------------------------------------------------------------------------------------------------- +/* +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"); +*/ template -bool parseTime(const String& format, const String2& str, TimeComp& comp); //similar to ::strptime(), return true on success +TimeComp parseTime(const String& format, const String2& str); //similar to ::strptime() //---------------------------------------------------------------------------------------------------------------------------------- @@ -75,29 +79,26 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp); //simi - - - //############################ implementation ############################## -namespace implementation +namespace impl { inline -std::tm toClibTimeComponents(const TimeComp& comp) +std::tm toClibTimeComponents(const TimeComp& tc) { - assert(1 <= comp.month && comp.month <= 12 && - 1 <= comp.day && comp.day <= 31 && - 0 <= comp.hour && comp.hour <= 23 && - 0 <= comp.minute && comp.minute <= 59 && - 0 <= comp.second && comp.second <= 61); + assert(1 <= tc.month && tc.month <= 12 && + 1 <= tc.day && tc.day <= 31 && + 0 <= tc.hour && tc.hour <= 23 && + 0 <= tc.minute && tc.minute <= 59 && + 0 <= tc.second && tc.second <= 61); std::tm ctc = {}; - ctc.tm_year = comp.year - 1900; //years since 1900 - ctc.tm_mon = comp.month - 1; //0-11 - ctc.tm_mday = comp.day; //1-31 - ctc.tm_hour = comp.hour; //0-23 - ctc.tm_min = comp.minute; //0-59 - ctc.tm_sec = comp.second; //0-60 (including leap second) - ctc.tm_isdst = -1; //> 0 if DST is active, == 0 if DST is not active, < 0 if the information is not available + ctc.tm_year = tc.year - 1900; //years since 1900 + ctc.tm_mon = tc.month - 1; //0-11 + ctc.tm_mday = tc.day; //1-31 + ctc.tm_hour = tc.hour; //0-23 + ctc.tm_min = tc.minute; //0-59 + ctc.tm_sec = tc.second; //0-60 (including leap second) + ctc.tm_isdst = -1; //> 0 if DST is active, == 0 if DST is not active, < 0 if the information is not available //ctc.tm_wday //ctc.tm_yday return ctc; @@ -106,14 +107,14 @@ std::tm toClibTimeComponents(const TimeComp& comp) inline TimeComp toZenTimeComponents(const std::tm& ctc) { - TimeComp comp; - comp.year = ctc.tm_year + 1900; - comp.month = ctc.tm_mon + 1; - comp.day = ctc.tm_mday; - comp.hour = ctc.tm_hour; - comp.minute = ctc.tm_min; - comp.second = ctc.tm_sec; - return comp; + TimeComp tc; + tc.year = ctc.tm_year + 1900; + tc.month = ctc.tm_mon + 1; + tc.day = ctc.tm_mday; + tc.hour = ctc.tm_hour; + tc.minute = ctc.tm_min; + tc.second = ctc.tm_sec; + return tc; } @@ -206,7 +207,6 @@ bool isValid(const std::tm& t) template inline size_t strftimeWrap(CharType* buffer, size_t bufferSize, const CharType* format, const std::tm* timeptr) { - return strftimeWrap_impl(buffer, bufferSize, format, timeptr); } @@ -215,10 +215,10 @@ struct UserDefinedFormatTag {}; struct PredefinedFormatTag {}; template inline -String formatTime(const String2& format, const TimeComp& comp, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure +String formatTime(const String2& format, const TimeComp& tc, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure { using CharType = typename GetCharType::Type; - std::tm ctc = toClibTimeComponents(comp); + 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 @@ -227,11 +227,12 @@ String formatTime(const String2& format, const TimeComp& comp, UserDefinedFormat return String(buffer, charsWritten); } + template inline -String formatTime(FormatType, const TimeComp& comp, PredefinedFormatTag) +String formatTime(FormatType, const TimeComp& tc, PredefinedFormatTag) { using CharType = typename GetCharType::Type; - return formatTime(GetFormat().format(CharType()), comp, UserDefinedFormatTag()); + return formatTime(GetFormat().format(CharType()), tc, UserDefinedFormatTag()); } } @@ -239,37 +240,49 @@ String formatTime(FormatType, const TimeComp& comp, PredefinedFormatTag) inline TimeComp getLocalTime(time_t utc) { - std::tm comp = {}; - if (::localtime_r(&utc, &comp) == nullptr) + if (utc == -1) //failure code from std::time(nullptr) + return TimeComp(); + + std::tm ctc = {}; + if (::localtime_r(&utc, &ctc) == nullptr) return TimeComp(); - return implementation::toZenTimeComponents(comp); + return impl::toZenTimeComponents(ctc); } inline TimeComp getUtcTime(time_t utc) { - std::tm comp = {}; - if (::gmtime_r(&utc, &comp) == nullptr) + if (utc == -1) //failure code from std::time(nullptr) return TimeComp(); - return implementation::toZenTimeComponents(comp); + std::tm ctc = {}; + if (::gmtime_r(&utc, &ctc) == nullptr) + return TimeComp(); + + return impl::toZenTimeComponents(ctc); } inline -time_t localToTimeT(const TimeComp& comp) //returns -1 on error +time_t localToTimeT(const TimeComp& tc) //returns -1 on error { - std::tm ctc = implementation::toClibTimeComponents(comp); + if (tc == TimeComp()) + return -1; + + std::tm ctc = impl::toClibTimeComponents(tc); return std::mktime(&ctc); } inline -time_t utcToTimeT(const TimeComp& comp) //returns -1 on error +time_t utcToTimeT(const TimeComp& tc) //returns -1 on error { - std::tm ctc = implementation::toClibTimeComponents(comp); + if (tc == TimeComp()) + return -1; + + std::tm ctc = impl::toClibTimeComponents(tc); ctc.tm_isdst = 0; //"Zero (0) to indicate that standard time is in effect" => unused by _mkgmtime, but take no chances return ::timegm(&ctc); } @@ -283,39 +296,36 @@ TimeComp getCompileTime() if (compileTime[4] == ' ') //day is space-padded, but %d expects zero-padding compileTime[4] = '0'; - TimeComp tc = {}; - if (parseTime("%b %d %Y %H:%M:%S", compileTime, tc)) - return tc; - - assert(false); - return TimeComp(); + return parseTime("%b %d %Y %H:%M:%S", compileTime); } template inline -String formatTime(const String2& format, const TimeComp& comp) +String formatTime(const String2& format, const TimeComp& tc) { + if (tc == TimeComp()) //failure code from getLocalTime() + return String(); + using FormatTag = typename SelectIf< IsSameType::value || IsSameType::value || IsSameType::value || IsSameType::value || IsSameType::value || - IsSameType::value, implementation::PredefinedFormatTag, implementation::UserDefinedFormatTag>::Type; + IsSameType::value, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>::Type; - return implementation::formatTime(format, comp, FormatTag()); + return impl::formatTime(format, tc, FormatTag()); } +namespace impl +{ template -bool parseTime(const String& format, const String2& str, TimeComp& comp) //return true on success +TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTag) { using CharType = typename GetCharType::Type; static_assert(IsSameType::Type>::value, ""); - const CharType* itFmt = strBegin(format); - const CharType* const fmtLast = itFmt + strLength(format); - const CharType* itStr = strBegin(str); const CharType* const strLast = itStr + strLength(str); @@ -332,6 +342,11 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur return true; }; + TimeComp output; + + const CharType* itFmt = strBegin(format); + const CharType* const fmtLast = itFmt + strLength(format); + for (; itFmt != fmtLast; ++itFmt) { const CharType fmt = *itFmt; @@ -340,22 +355,22 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur { ++itFmt; if (itFmt == fmtLast) - return false; + return TimeComp(); switch (*itFmt) { case 'Y': - if (!extractNumber(comp.year, 4)) - return false; + if (!extractNumber(output.year, 4)) + return TimeComp(); break; case 'm': - if (!extractNumber(comp.month, 2)) - return false; + if (!extractNumber(output.month, 2)) + return TimeComp(); break; case 'b': //abbreviated month name: Jan-Dec { if (strLast - itStr < 3) - return false; + 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) @@ -365,30 +380,30 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur asciiToLower(itStr[2]) == name[2]; }); if (itMonth == std::end(months)) - return false; + return TimeComp(); - comp.month = 1 + static_cast(itMonth - std::begin(months)); + output.month = 1 + static_cast(itMonth - std::begin(months)); itStr += 3; } break; case 'd': - if (!extractNumber(comp.day, 2)) - return false; + if (!extractNumber(output.day, 2)) + return TimeComp(); break; case 'H': - if (!extractNumber(comp.hour, 2)) - return false; + if (!extractNumber(output.hour, 2)) + return TimeComp(); break; case 'M': - if (!extractNumber(comp.minute, 2)) - return false; + if (!extractNumber(output.minute, 2)) + return TimeComp(); break; case 'S': - if (!extractNumber(comp.second, 2)) - return false; + if (!extractNumber(output.second, 2)) + return TimeComp(); break; default: - return false; + return TimeComp(); } } else if (isWhiteSpace(fmt)) //single whitespace in format => skip 0..n whitespace chars @@ -399,12 +414,36 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur else { if (itStr == strLast || *itStr != fmt) - return false; + return TimeComp(); ++itStr; } } - return itStr == strLast; + if (itStr != strLast) + return TimeComp(); + + return output; +} + + +template inline +TimeComp parseTime(FormatType, const String& str, PredefinedFormatTag) +{ + using CharType = typename GetCharType::Type; + return parseTime(GetFormat().format(CharType()), str, UserDefinedFormatTag()); +} +} + + +template inline +TimeComp parseTime(const String& format, const String2& str) +{ + using FormatTag = typename SelectIf< + IsSameType::value || + IsSameType::value || + IsSameType::value, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>::Type; + + return impl::parseTime(format, str, FormatTag()); } } -- cgit