summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlouiz’ <louiz@louiz.org>2016-10-11 00:18:48 +0200
committerlouiz’ <louiz@louiz.org>2016-10-11 00:20:43 +0200
commit548e4ad473e7be22f971184312cc5ce9b8fe56b7 (patch)
tree3b7be9c89c931bb49ad9bc7e14d6e21a446e90f0
parent116472920ce4bcd4c9512db67108cdbf9895e8ad (diff)
downloadbiboumi-548e4ad473e7be22f971184312cc5ce9b8fe56b7.tar.gz
biboumi-548e4ad473e7be22f971184312cc5ce9b8fe56b7.tar.bz2
biboumi-548e4ad473e7be22f971184312cc5ce9b8fe56b7.tar.xz
biboumi-548e4ad473e7be22f971184312cc5ce9b8fe56b7.zip
Parse the timezone myself, instead of using the broken strptime
See https://lab.louiz.org/louiz/biboumi/issues/3215 https://github.com/andikleen/glibc/blob/master/time/strptime_l.c#L746-L747 for why strptime() sucks We use std::get_time now, to parse the date and time. And we parse the timezone by hand. fix #3215
-rw-r--r--louloulibs/utils/time.cpp44
-rw-r--r--tests/utils.cpp16
2 files changed, 53 insertions, 7 deletions
diff --git a/louloulibs/utils/time.cpp b/louloulibs/utils/time.cpp
index abf0a84..7ad6663 100644
--- a/louloulibs/utils/time.cpp
+++ b/louloulibs/utils/time.cpp
@@ -1,6 +1,10 @@
#include <utils/time.hpp>
#include <time.h>
+#include <sstream>
+#include <iomanip>
+#include <locale>
+
namespace utils
{
std::string to_string(const std::time_t& timestamp)
@@ -14,12 +18,42 @@ std::string to_string(const std::time_t& timestamp)
std::time_t parse_datetime(const std::string& stamp)
{
- auto stamp2 = stamp.substr(0, stamp.size() - 1) + "z";
- struct tm tm;
- if (!::strptime(stamp2.data(), "%FT%T%Z", &tm))
+ static const char* format = "%Y-%m-%dT%H:%M:%S";
+ std::tm t = {};
+ std::istringstream ss(stamp);
+ ss.imbue(std::locale("en_US.utf-8"));
+
+ std::string timezone;
+ ss >> std::get_time(&t, format) >> timezone;
+ if (ss.fail())
+ return -1;
+
+ if (timezone.empty())
return -1;
- auto res = ::timegm(&tm);
- return res;
+
+ if (timezone.compare(0, 1, "Z") != 0)
+ {
+ std::stringstream tz_ss;
+ tz_ss << timezone;
+ int multiplier = -1;
+ char prefix;
+ int hours;
+ char sep;
+ int minutes;
+ tz_ss >> prefix >> hours >> sep >> minutes;
+ if (tz_ss.fail())
+ return -1;
+ if (prefix == '-')
+ multiplier = +1;
+ else if (prefix != '+')
+ return -1;
+
+ t.tm_hour += multiplier * hours;
+ t.tm_min += multiplier * minutes;
+ }
+ return ::timegm(&t);
}
}
+
+
diff --git a/tests/utils.cpp b/tests/utils.cpp
index a18fc81..48951da 100644
--- a/tests/utils.cpp
+++ b/tests/utils.cpp
@@ -124,7 +124,19 @@ TEST_CASE("time_to_string")
TEST_CASE("parse_datetime")
{
- CHECK(utils::parse_datetime("1970-01-01T00:00:00z") == 0);
+ CHECK(utils::parse_datetime("1970-01-01T00:00:00Z") == 0);
+
+ const int twenty_three_hours = 82800;
+ CHECK(utils::parse_datetime("1970-01-01T23:00:12Z") == twenty_three_hours + 12);
+ CHECK(utils::parse_datetime("1970-01-01T23:00:12Z") == utils::parse_datetime("1970-01-01T23:00:12+00:00"));
+ CHECK(utils::parse_datetime("1970-01-01T23:00:12Z") == utils::parse_datetime("1970-01-01T23:00:12-00:00"));
+ CHECK(utils::parse_datetime("1970-01-02T00:00:12Z") == utils::parse_datetime("1970-01-01T23:00:12-01:00"));
+ CHECK(utils::parse_datetime("1970-01-02T00:00:12Z") == utils::parse_datetime("1970-01-02T01:00:12+01:00"));
+
CHECK(utils::parse_datetime("2016-08-29T14:29:29Z") == 1472480969);
+
CHECK(utils::parse_datetime("blah") == -1);
-} \ No newline at end of file
+ CHECK(utils::parse_datetime("1970-01-02T00:00:12B") == -1);
+ CHECK(utils::parse_datetime("1970-01-02T00:00:12*00:00") == -1);
+ CHECK(utils::parse_datetime("1970-01-02T00:00:12+0000") == -1);
+}