diff options
author | Daniel Wilhelm <shieldwed@outlook.com> | 2017-04-20 16:55:28 -0600 |
---|---|---|
committer | Daniel Wilhelm <shieldwed@outlook.com> | 2017-04-20 16:59:56 -0600 |
commit | 823740e1ffa2b3bd39f8dea8062f5c5a0d9c741b (patch) | |
tree | 63222010af3b90a36f29c1c9c360116973cdff38 /zen/time.h | |
parent | add .gitattributes for less line ending hassles (diff) | |
download | FreeFileSync-823740e1ffa2b3bd39f8dea8062f5c5a0d9c741b.tar.gz FreeFileSync-823740e1ffa2b3bd39f8dea8062f5c5a0d9c741b.tar.bz2 FreeFileSync-823740e1ffa2b3bd39f8dea8062f5c5a0d9c741b.zip |
normalize most lineendings
Diffstat (limited to 'zen/time.h')
-rwxr-xr-x | zen/time.h | 736 |
1 files changed, 368 insertions, 368 deletions
@@ -1,368 +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 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
+// ***************************************************************************** +// * 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 |