diff options
author | Daniel Wilhelm <shieldwed@outlook.com> | 2017-02-13 21:25:04 -0700 |
---|---|---|
committer | Daniel Wilhelm <shieldwed@outlook.com> | 2017-02-13 21:25:04 -0700 |
commit | 9d071d2a2cec9a7662a02669488569a017f0ea35 (patch) | |
tree | c83a623fbdff098339b66d21ea2e81f3f67344ae /zen/time.h | |
parent | 8.8 (diff) | |
download | FreeFileSync-9d071d2a2cec9a7662a02669488569a017f0ea35.tar.gz FreeFileSync-9d071d2a2cec9a7662a02669488569a017f0ea35.tar.bz2 FreeFileSync-9d071d2a2cec9a7662a02669488569a017f0ea35.zip |
8.9
Diffstat (limited to 'zen/time.h')
-rwxr-xr-x[-rw-r--r--] | zen/time.h | 725 |
1 files changed, 368 insertions, 357 deletions
diff --git a/zen/time.h b/zen/time.h index a4613408..1b6a3c92 100644..100755 --- a/zen/time.h +++ b/zen/time.h @@ -1,357 +1,368 @@ -// ***************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * -// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * -// ***************************************************************************** - -#ifndef TIME_H_8457092814324342453627 -#define TIME_H_8457092814324342453627 - -#include <ctime> -#include "string_tools.h" - - -namespace zen -{ -struct TimeComp //replaces std::tm and SYSTEMTIME -{ - int year = 0; // - - int month = 0; //1-12 - int day = 0; //1-31 - int hour = 0; //0-23 - int minute = 0; //0-59 - int second = 0; //0-60 (including leap second) -}; - -TimeComp localTime (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 - -//---------------------------------------------------------------------------------------------------------------------------------- - -/* -format (current) date and time; example: - formatTime<std::wstring>(L"%Y|%m|%d"); -> "2011|10|29" - formatTime<std::wstring>(FORMAT_DATE); -> "2011-10-29" - formatTime<std::wstring>(FORMAT_TIME); -> "17:55:34" -*/ -template <class String, class String2> -String formatTime(const String2& format, const TimeComp& comp = localTime()); //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 -const struct FormatTimeTag {} FORMAT_TIME = {}; //%X - locale dependent time representation: e.g. 14:55:02 -const struct FormatDateTimeTag {} FORMAT_DATE_TIME = {}; //%c - locale dependent date and time: e.g. Thu Aug 23 14:55:02 2001 - -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 - -//---------------------------------------------------------------------------------------------------------------------------------- - -template <class String, class String2> -bool parseTime(const String& format, const String2& str, TimeComp& comp); //similar to ::strptime(), return true on success - -//---------------------------------------------------------------------------------------------------------------------------------- - - - - - - - - - - - - - - - - -//############################ implementation ############################## -namespace implementation -{ -inline -std::tm toClibTimeComponents(const TimeComp& comp) -{ - 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); - - 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_wday - //ctc.tm_yday - return ctc; -} - -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; -} - - -template <class T> -struct GetFormat; //get default time formats as char* or wchar_t* - -template <> -struct GetFormat<FormatDateTag> //%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<FormatTimeTag> //%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<FormatDateTimeTag> //%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<FormatIsoDateTag> //%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<FormatIsoTimeTag> //%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<FormatIsoDateTimeTag> //%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) -{ - -> not enough! MSCRT has different limits than the C standard which even seem to change with different versions: - _VALIDATE_RETURN((( timeptr->tm_sec >=0 ) && ( timeptr->tm_sec <= 59 ) ), EINVAL, FALSE) - _VALIDATE_RETURN(( timeptr->tm_year >= -1900 ) && ( timeptr->tm_year <= 8099 ), EINVAL, FALSE) - -> also std::mktime does *not* help here at all! - - auto inRange = [](int value, int minVal, int maxVal) { return minVal <= value && value <= maxVal; }; - - //http://www.cplusplus.com/reference/clibrary/ctime/tm/ - return inRange(t.tm_sec , 0, 61) && - inRange(t.tm_min , 0, 59) && - inRange(t.tm_hour, 0, 23) && - inRange(t.tm_mday, 1, 31) && - inRange(t.tm_mon , 0, 11) && - //tm_year - inRange(t.tm_wday, 0, 6) && - inRange(t.tm_yday, 0, 365); - //tm_isdst -}; -*/ - -template <class CharType> inline -size_t strftimeWrap(CharType* buffer, size_t bufferSize, const CharType* format, const std::tm* timeptr) -{ -#if defined _MSC_VER && !defined NDEBUG - //there's no way around: application init must register an invalid parameter handler that does nothing !!! - //=> strftime will abort with 0 and set errno to EINVAL instead of CRASHING THE APPLICATION! - _invalid_parameter_handler oldHandler = _set_invalid_parameter_handler(nullptr); - assert(oldHandler); - _set_invalid_parameter_handler(oldHandler); -#endif - - return strftimeWrap_impl(buffer, bufferSize, format, timeptr); -} - - -struct UserDefinedFormatTag {}; -struct PredefinedFormatTag {}; - -template <class String, class String2> inline -String formatTime(const String2& format, const TimeComp& comp, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure -{ - using CharType = typename GetCharType<String>::Type; - std::tm ctc = toClibTimeComponents(comp); - 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 - - CharType buffer[256] = {}; - const size_t charsWritten = strftimeWrap(buffer, 256, strBegin(format), &ctc); - return String(buffer, charsWritten); -} - -template <class String, class FormatType> inline -String formatTime(FormatType, const TimeComp& comp, PredefinedFormatTag) -{ - using CharType = typename GetCharType<String>::Type; - return formatTime<String>(GetFormat<FormatType>().format(CharType()), comp, UserDefinedFormatTag()); -} -} - - -inline -TimeComp localTime(time_t utc) -{ - std::tm lt = {}; - -#ifdef ZEN_WIN //use thread-safe variants of std::localtime()! - if (::localtime_s(<, &utc) != 0) -#else - if (::localtime_r(&utc, <) == nullptr) -#endif - return TimeComp(); - - return implementation::toZenTimeComponents(lt); -} - - -inline -time_t localToTimeT(const TimeComp& comp) //returns -1 on error -{ - std::tm ctc = implementation::toClibTimeComponents(comp); - return std::mktime(&ctc); -} - - -template <class String, class String2> inline -String formatTime(const String2& format, const TimeComp& comp) -{ - using FormatTag = typename SelectIf< - IsSameType<String2, FormatDateTag >::value || - IsSameType<String2, FormatTimeTag >::value || - IsSameType<String2, FormatDateTimeTag >::value || - IsSameType<String2, FormatIsoDateTag >::value || - IsSameType<String2, FormatIsoTimeTag >::value || - IsSameType<String2, FormatIsoDateTimeTag>::value, implementation::PredefinedFormatTag, implementation::UserDefinedFormatTag>::Type; - - return implementation::formatTime<String>(format, comp, FormatTag()); -} - - -template <class String, class String2> -bool parseTime(const String& format, const String2& str, TimeComp& comp) //return true on success -{ - using CharType = typename GetCharType<String>::Type; - static_assert(IsSameType<CharType, typename GetCharType<String2>::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); - - auto extractNumber = [&](int& result, size_t digitCount) -> bool - { - if (strLast - itStr < makeSigned(digitCount)) - return false; - - if (std::any_of(itStr, itStr + digitCount, [](CharType c) { return !isDigit(c); })) - return false; - - result = zen::stringTo<int>(StringRef<const CharType>(itStr, itStr + digitCount)); - itStr += digitCount; - return true; - }; - - for (; itFmt != fmtLast; ++itFmt) - { - const CharType fmt = *itFmt; - - if (fmt == '%') - { - ++itFmt; - if (itFmt == fmtLast) - return false; - - switch (*itFmt) - { - case 'Y': - if (!extractNumber(comp.year, 4)) - return false; - break; - case 'm': - if (!extractNumber(comp.month, 2)) - return false; - break; - case 'd': - if (!extractNumber(comp.day, 2)) - return false; - break; - case 'H': - if (!extractNumber(comp.hour, 2)) - return false; - break; - case 'M': - if (!extractNumber(comp.minute, 2)) - return false; - break; - case 'S': - if (!extractNumber(comp.second, 2)) - return false; - break; - default: - return false; - } - } - else if (isWhiteSpace(fmt)) //single whitespace in format => skip 0..n whitespace chars - { - while (itStr != strLast && isWhiteSpace(*itStr)) - ++itStr; - } - else - { - if (itStr == strLast || *itStr != fmt) - return false; - ++itStr; - } - } - - return itStr == strLast; -} -} - -#endif //TIME_H_8457092814324342453627 +// *****************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 *
+// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
+// *****************************************************************************
+
+#ifndef TIME_H_8457092814324342453627
+#define TIME_H_8457092814324342453627
+
+#include <ctime>
+#include "string_tools.h"
+
+
+namespace zen
+{
+struct TimeComp //replaces std::tm and SYSTEMTIME
+{
+ int year = 0; // -
+ int month = 0; //1-12
+ int day = 0; //1-31
+ int hour = 0; //0-23
+ int minute = 0; //0-59
+ int second = 0; //0-60 (including leap second)
+};
+
+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 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
+
+//----------------------------------------------------------------------------------------------------------------------------------
+
+/*
+format (current) date and time; example:
+ formatTime<std::wstring>(L"%Y|%m|%d"); -> "2011|10|29"
+ formatTime<std::wstring>(FORMAT_DATE); -> "2011-10-29"
+ formatTime<std::wstring>(FORMAT_TIME); -> "17:55:34"
+*/
+template <class String, class String2>
+String formatTime(const String2& format, const TimeComp& comp = 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
+const struct FormatTimeTag {} FORMAT_TIME = {}; //%X - locale dependent time representation: e.g. 14:55:02
+const struct FormatDateTimeTag {} FORMAT_DATE_TIME = {}; //%c - locale dependent date and time: e.g. Thu Aug 23 14:55:02 2001
+
+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
+
+//----------------------------------------------------------------------------------------------------------------------------------
+
+template <class String, class String2>
+bool parseTime(const String& format, const String2& str, TimeComp& comp); //similar to ::strptime(), return true on success
+
+//----------------------------------------------------------------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//############################ implementation ##############################
+namespace implementation
+{
+inline
+std::tm toClibTimeComponents(const TimeComp& comp)
+{
+ 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);
+
+ 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_wday
+ //ctc.tm_yday
+ return ctc;
+}
+
+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;
+}
+
+
+template <class T>
+struct GetFormat; //get default time formats as char* or wchar_t*
+
+template <>
+struct GetFormat<FormatDateTag> //%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<FormatTimeTag> //%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<FormatDateTimeTag> //%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<FormatIsoDateTag> //%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<FormatIsoTimeTag> //%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<FormatIsoDateTimeTag> //%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)
+{
+ -> not enough! MSCRT has different limits than the C standard which even seem to change with different versions:
+ _VALIDATE_RETURN((( timeptr->tm_sec >=0 ) && ( timeptr->tm_sec <= 59 ) ), EINVAL, FALSE)
+ _VALIDATE_RETURN(( timeptr->tm_year >= -1900 ) && ( timeptr->tm_year <= 8099 ), EINVAL, FALSE)
+ -> also std::mktime does *not* help here at all!
+
+ auto inRange = [](int value, int minVal, int maxVal) { return minVal <= value && value <= maxVal; };
+
+ //http://www.cplusplus.com/reference/clibrary/ctime/tm/
+ return inRange(t.tm_sec , 0, 61) &&
+ inRange(t.tm_min , 0, 59) &&
+ inRange(t.tm_hour, 0, 23) &&
+ inRange(t.tm_mday, 1, 31) &&
+ inRange(t.tm_mon , 0, 11) &&
+ //tm_year
+ inRange(t.tm_wday, 0, 6) &&
+ inRange(t.tm_yday, 0, 365);
+ //tm_isdst
+};
+*/
+
+template <class CharType> 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 <class String, class String2> inline
+String formatTime(const String2& format, const TimeComp& comp, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure
+{
+ using CharType = typename GetCharType<String>::Type;
+ std::tm ctc = toClibTimeComponents(comp);
+ 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
+
+ CharType buffer[256] = {};
+ const size_t charsWritten = strftimeWrap(buffer, 256, strBegin(format), &ctc);
+ return String(buffer, charsWritten);
+}
+
+template <class String, class FormatType> inline
+String formatTime(FormatType, const TimeComp& comp, PredefinedFormatTag)
+{
+ using CharType = typename GetCharType<String>::Type;
+ return formatTime<String>(GetFormat<FormatType>().format(CharType()), comp, UserDefinedFormatTag());
+}
+}
+
+
+inline
+TimeComp getLocalTime(time_t utc)
+{
+ std::tm comp = {};
+ if (::localtime_r(&utc, &comp) == nullptr)
+ return TimeComp();
+
+ return implementation::toZenTimeComponents(comp);
+}
+
+
+inline
+TimeComp getUtcTime(time_t utc)
+{
+ std::tm comp = {};
+ if (::gmtime_r(&utc, &comp) == nullptr)
+ return TimeComp();
+
+ return implementation::toZenTimeComponents(comp);
+}
+
+
+inline
+time_t localToTimeT(const TimeComp& comp) //returns -1 on error
+{
+ std::tm ctc = implementation::toClibTimeComponents(comp);
+ return std::mktime(&ctc);
+}
+
+
+inline
+time_t utcToTimeT(const TimeComp& comp) //returns -1 on error
+{
+ std::tm ctc = implementation::toClibTimeComponents(comp);
+ ctc.tm_isdst = 0; //"Zero (0) to indicate that standard time is in effect" => unused by _mkgmtime, but take no chances
+ return ::timegm(&ctc);
+}
+
+
+template <class String, class String2> inline
+String formatTime(const String2& format, const TimeComp& comp)
+{
+ using FormatTag = typename SelectIf<
+ IsSameType<String2, FormatDateTag >::value ||
+ IsSameType<String2, FormatTimeTag >::value ||
+ IsSameType<String2, FormatDateTimeTag >::value ||
+ IsSameType<String2, FormatIsoDateTag >::value ||
+ IsSameType<String2, FormatIsoTimeTag >::value ||
+ IsSameType<String2, FormatIsoDateTimeTag>::value, implementation::PredefinedFormatTag, implementation::UserDefinedFormatTag>::Type;
+
+ return implementation::formatTime<String>(format, comp, FormatTag());
+}
+
+
+template <class String, class String2>
+bool parseTime(const String& format, const String2& str, TimeComp& comp) //return true on success
+{
+ using CharType = typename GetCharType<String>::Type;
+ static_assert(IsSameType<CharType, typename GetCharType<String2>::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);
+
+ auto extractNumber = [&](int& result, size_t digitCount) -> bool
+ {
+ if (strLast - itStr < makeSigned(digitCount))
+ return false;
+
+ if (std::any_of(itStr, itStr + digitCount, [](CharType c) { return !isDigit(c); }))
+ return false;
+
+ result = zen::stringTo<int>(StringRef<const CharType>(itStr, itStr + digitCount));
+ itStr += digitCount;
+ return true;
+ };
+
+ for (; itFmt != fmtLast; ++itFmt)
+ {
+ const CharType fmt = *itFmt;
+
+ if (fmt == '%')
+ {
+ ++itFmt;
+ if (itFmt == fmtLast)
+ return false;
+
+ switch (*itFmt)
+ {
+ case 'Y':
+ if (!extractNumber(comp.year, 4))
+ return false;
+ break;
+ case 'm':
+ if (!extractNumber(comp.month, 2))
+ return false;
+ break;
+ case 'd':
+ if (!extractNumber(comp.day, 2))
+ return false;
+ break;
+ case 'H':
+ if (!extractNumber(comp.hour, 2))
+ return false;
+ break;
+ case 'M':
+ if (!extractNumber(comp.minute, 2))
+ return false;
+ break;
+ case 'S':
+ if (!extractNumber(comp.second, 2))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ }
+ else if (isWhiteSpace(fmt)) //single whitespace in format => skip 0..n whitespace chars
+ {
+ while (itStr != strLast && isWhiteSpace(*itStr))
+ ++itStr;
+ }
+ else
+ {
+ if (itStr == strLast || *itStr != fmt)
+ return false;
+ ++itStr;
+ }
+ }
+
+ return itStr == strLast;
+}
+}
+
+#endif //TIME_H_8457092814324342453627
|