aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/utils/calendar.cpp
diff options
context:
space:
mode:
authorSimon Warta <[email protected]>2015-07-17 17:10:02 +0200
committerSimon Warta <[email protected]>2015-07-27 13:04:40 +0200
commitd4be8c6f64420bcc0f55ce6ae18bf9363bd46481 (patch)
tree18cf389fa35efd254a8a410a57b2165dca787ed7 /src/lib/utils/calendar.cpp
parent1f3ef881b103c4b8734691051f5de38f99c912af (diff)
Add mktime fallback for non-POSIX timegm()
Closes #202
Diffstat (limited to 'src/lib/utils/calendar.cpp')
-rw-r--r--src/lib/utils/calendar.cpp61
1 files changed, 56 insertions, 5 deletions
diff --git a/src/lib/utils/calendar.cpp b/src/lib/utils/calendar.cpp
index f62303e49..966c97730 100644
--- a/src/lib/utils/calendar.cpp
+++ b/src/lib/utils/calendar.cpp
@@ -11,6 +11,7 @@
#include <ctime>
#include <sstream>
#include <iomanip>
+#include <mutex>
namespace Botan {
@@ -34,11 +35,53 @@ std::tm do_gmtime(std::time_t time_val)
return tm;
}
+#if !defined(BOTAN_TARGET_OS_HAS_TIMEGM) && !defined(BOTAN_TARGET_OS_HAS_MKGMTIME)
+
+#pragma message "Caution! A fallback version of timegm() is used which is not thread-safe"
+
+std::mutex ENV_TZ;
+
+std::time_t fallback_timegm(std::tm *tm)
+ {
+ std::time_t out;
+ std::string tz_backup;
+
+ ENV_TZ.lock();
+
+ // Store current value of env variable TZ
+ const char* tz_env_pointer = ::getenv("TZ");
+ if (tz_env_pointer != nullptr)
+ tz_backup = std::string(tz_env_pointer);
+
+ // Clear value of TZ
+ ::setenv("TZ", "", 1);
+ ::tzset();
+
+ out = ::mktime(tm);
+
+ // Restore TZ
+ if (!tz_backup.empty())
+ {
+ // setenv makes a copy of the second argument
+ ::setenv("TZ", tz_backup.data(), 1);
+ }
+ else
+ {
+ ::unsetenv("TZ");
+ }
+ ::tzset();
+
+ ENV_TZ.unlock();
+
+ return out;
+}
+#endif
+
}
std::chrono::system_clock::time_point calendar_point::to_std_timepoint()
{
- if (year < 1900)
+ if (year < 1970)
throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years before 1990.");
// 32 bit time_t ends at January 19, 2038
@@ -48,7 +91,9 @@ std::chrono::system_clock::time_point calendar_point::to_std_timepoint()
if (year > 2037)
throw Invalid_Argument("calendar_point::to_std_timepoint() does not support years after 2037.");
+ // std::tm: struct without any timezone information
std::tm tm;
+ tm.tm_isdst = -1; // i.e. no DST information available
tm.tm_sec = seconds;
tm.tm_min = minutes;
tm.tm_hour = hour;
@@ -56,12 +101,18 @@ std::chrono::system_clock::time_point calendar_point::to_std_timepoint()
tm.tm_mon = month - 1;
tm.tm_year = year - 1900;
- // Convert std::tm to std::time_t
+ // Define a function alias `botan_timegm`
+ #if defined(BOTAN_TARGET_OS_HAS_TIMEGM)
+ std::time_t (&botan_timegm)(std::tm *tm) = timegm;
+ #elif defined(BOTAN_TARGET_OS_HAS_MKGMTIME)
// http://stackoverflow.com/questions/16647819/timegm-cross-platform
- #if defined(BOTAN_TARGET_OS_IS_WINDOWS)
- #define timegm _mkgmtime
+ std::time_t (&botan_timegm)(std::tm *tm) = _mkgmtime;
+ #else
+ std::time_t (&botan_timegm)(std::tm *tm) = fallback_timegm;
#endif
- std::time_t tt = timegm(&tm);
+
+ // Convert std::tm to std::time_t
+ std::time_t tt = botan_timegm(&tm);
if (tt == -1)
throw Invalid_Argument("calendar_point couldn't be converted: " + to_string());