summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
Diffstat (limited to 'zen')
-rw-r--r--zen/file_path.cpp1
-rw-r--r--zen/format_unit.cpp2
-rw-r--r--zen/legacy_compiler.h9
-rw-r--r--zen/time.h99
4 files changed, 87 insertions, 24 deletions
diff --git a/zen/file_path.cpp b/zen/file_path.cpp
index 68137b90..716dd8de 100644
--- a/zen/file_path.cpp
+++ b/zen/file_path.cpp
@@ -100,6 +100,7 @@ Zstring zen::appendPath(const Zstring& basePath, const Zstring& relPath)
if (relPath.empty())
return basePath; //with or without path separator, e.g. C:\ or C:\folder
+ //assert(!basePath.empty());
if (basePath.empty()) //basePath might be a relative path, too!
return relPath;
diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp
index 13280b68..2aa6e094 100644
--- a/zen/format_unit.cpp
+++ b/zen/format_unit.cpp
@@ -170,7 +170,7 @@ std::wstring zen::formatUtcToLocalTime(time_t utcTime)
{
auto errorMsg = [&] { return _("Error") + L" (time_t: " + numberTo<std::wstring>(utcTime) + L')'; };
- const TimeComp& loc = getLocalTime(utcTime);
+ const TimeComp& loc = getLocalTime(utcTime); //returns TimeComp() on error
std::wstring dateString = utfTo<std::wstring>(formatTime(Zstr("%x %X"), loc));
return !dateString.empty() ? dateString : errorMsg();
diff --git a/zen/legacy_compiler.h b/zen/legacy_compiler.h
index 6c9381ee..33394de3 100644
--- a/zen/legacy_compiler.h
+++ b/zen/legacy_compiler.h
@@ -34,4 +34,13 @@ double fromChars(const char* first, const char* last);
const char* toChars(char* first, char* last, double num);
}
+
+#if 0 //neat: supported on MSVC, but not yet on GCC, Clang
+auto closure = [](this auto&& self)
+{
+ self(); //just call ourself until the stack overflows
+ //e.g. use for: deleteEmptyFolderTask, removeFolderRecursionImpl, scheduleMoreTasks, traverse
+};
+#endif
+
#endif //LEGACY_COMPILER_H_839567308565656789
diff --git a/zen/time.h b/zen/time.h
index c5b6f23c..c2c10fd5 100644
--- a/zen/time.h
+++ b/zen/time.h
@@ -26,11 +26,13 @@ struct TimeComp //replaces std::tm and SYSTEMTIME
bool operator==(const TimeComp&) const = default;
};
-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); //convert time_t (UTC) to UTC time components, returns TimeComp() on error
+TimeComp getUtcTime(); //utc = std::time()
+std::pair<time_t, bool /*success*/> utcToTimeT(const TimeComp& tc); //convert UTC time components to time_t (UTC)
-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 getLocalTime(time_t utc); //convert time_t (UTC) to local time components, returns TimeComp() on error
+TimeComp getLocalTime(); //utc = std::time()
+std::pair<time_t, bool /*success*/> localToTimeT(const TimeComp& tc); //convert local time components to time_t (UTC)
TimeComp getCompileTime(); //returns TimeComp() on error
@@ -134,62 +136,113 @@ bool isValid(const std::tm& t)
}
+constexpr auto daysPer400Years = 100 * (4 * 365 /*usual days per year*/ + 1 /*including leap day*/) - 3 /*no leap days for centuries, except if divisible by 400 */;
+constexpr auto secsPer400Years = 3600LL * 24 * daysPer400Years;
+
+
inline
-TimeComp getLocalTime(time_t utc)
+TimeComp getUtcTime(time_t utc)
{
- if (utc == -1) //failure code from std::time(nullptr)
- return TimeComp();
+ //Windows: gmtime_s() only works for years [1970, 3001]
+ //=> map into working 400-year range [1970, 2370)
+ // bonus: avoid asking for bugs for time_t(-1)
+ const int cycles400 = static_cast<int>(numeric::intDivFloor(utc, secsPer400Years));
+ utc -= secsPer400Years * cycles400;
std::tm ctc = {};
- if (::localtime_r(&utc, &ctc) == nullptr)
+ if (::gmtime_r(&utc, &ctc) == nullptr) //Linux, macOS: apparently NO limits (tested years 0 to 10.000!)
return TimeComp();
+ ctc.tm_year += 400 * cycles400;
+
return impl::toZenTimeComponents(ctc);
}
-constexpr auto daysPer400Years = 100 * (4 * 365 /*usual days per year*/ + 1 /*including leap day*/) - 3 /*no leap days for centuries, except if divisible by 400 */;
-constexpr auto secsPer400Years = 3600LL * 24 * daysPer400Years;
+inline
+TimeComp getUtcTime()
+{
+ const time_t utc = std::time(nullptr); //returns -1 on error
+ if (utc == -1)
+ return TimeComp();
+
+ return getUtcTime(utc);
+}
inline
-TimeComp getUtcTime(time_t utc)
+TimeComp getLocalTime(time_t utc)
{
- if (utc == -1) //failure code from std::time(nullptr)
- return TimeComp();
+ const int cycles400 = static_cast<int>(numeric::intDivFloor(utc, secsPer400Years));
+ utc -= secsPer400Years * cycles400;
std::tm ctc = {};
- if (::gmtime_r(&utc, &ctc) == nullptr) //Linux, macOS: apparently NO limits (tested years 0 to 10.000!)
+ if (::localtime_r(&utc, &ctc) == nullptr)
return TimeComp();
+ ctc.tm_year += 400 * cycles400;
+
return impl::toZenTimeComponents(ctc);
}
inline
-time_t localToTimeT(const TimeComp& tc) //returns -1 on error
+TimeComp getLocalTime()
{
- if (tc == TimeComp())
- return -1;
+ const time_t utc = std::time(nullptr); //returns -1 on error
+ if (utc == -1)
+ return TimeComp();
- std::tm ctc = impl::toClibTimeComponents(tc);
- return std::mktime(&ctc);
+ return getLocalTime(utc);
}
inline
-time_t utcToTimeT(const TimeComp& tc) //returns -1 on error
+std::pair<time_t, bool /*success*/> utcToTimeT(const TimeComp& tc)
{
if (tc == TimeComp())
- return -1;
+ return {};
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
+ /* Windows: _mkgmtime() only works for years [1970, 3001]
+ macOS: timegm() requires tm_year >= 1900; apparently no upper limit (tested until year 10.000!)
+ Linux, 64-bit: apparently NO limits (tested years 0 to 10.000!)
+ 32-bit: timegm() only works for years [1902, 2038] => sucks to be on 32-bit! :>
+
+ => map into working 400-year range [1970, 2370)
+ bonus: disambiguate -1 error code from time_t(-1) */
+ const int cycles400 = numeric::intDivFloor(ctc.tm_year + 1900 - 1970, 400);
+ ctc.tm_year -= 400 * cycles400;
+
+ const time_t utc = ::timegm(&ctc);
+ if (utc == -1)
+ return {};
+
+ assert(utc >= 0);
+ return {utc + secsPer400Years * cycles400, true};
+}
+
+
+inline
+std::pair<time_t, bool /*success*/> localToTimeT(const TimeComp& tc) //convert local time components to time_t (UTC)
+{
+ if (tc == TimeComp())
+ return {};
+
+ std::tm ctc = impl::toClibTimeComponents(tc);
- time_t utc = ::timegm(&ctc);
+ const int cycles400 = numeric::intDivFloor(ctc.tm_year + 1900 - 1971/*[!]*/, 400); //see utcToTimeT()
+ //1971: ensures resulting time_t >= 0 after time zone, DST adaption, or std::mktime will fail on Windows!
+ ctc.tm_year -= 400 * cycles400;
- return utc;
+ const time_t locTime = std::mktime(&ctc);
+ if (locTime == -1)
+ return {};
+
+ assert(locTime > 0);
+ return {locTime + secsPer400Years * cycles400, true};
}
bgstack15