common/Util.cpp | 44 +++++++++++++++++++++++++++++++++---------- common/Util.hpp | 3 ++ test/WhiteBoxTests.cpp | 50 ++++++++++++++++++++++++++++++++++--------------- 3 files changed, 72 insertions(+), 25 deletions(-)
New commits: commit d038ceb118bc777756f8390dd959cb94c860ef25 Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Fri Oct 25 20:48:05 2019 -0400 Commit: Ashod Nakashian <ashnak...@gmail.com> CommitDate: Tue Oct 29 02:39:34 2019 +0100 test: Improve iso8601ToTimestamp and tests Using double caused all sorts of rounding issues, especially with random unit-test failures. Luckily, we don't need doubles and can do everything with integers. Also added a new function to print time_point as iso8601 string, for logging and convenience. Change-Id: I1c2040c02d1143282dbde0dadef32613b77c330d Reviewed-on: https://gerrit.libreoffice.org/81578 Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> Tested-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/common/Util.cpp b/common/Util.cpp index 3ceb2378a..49d465035 100644 --- a/common/Util.cpp +++ b/common/Util.cpp @@ -25,7 +25,6 @@ #include <sys/types.h> #include <unistd.h> #include <dirent.h> -#include <time.h> #include <atomic> #include <cassert> @@ -33,6 +32,7 @@ #include <cstdio> #include <cstdlib> #include <cstring> +#include <ctime> #include <fstream> #include <iomanip> #include <iostream> @@ -836,31 +836,55 @@ namespace Util return oss.str(); } - std::chrono::system_clock::time_point iso8601ToTimestamp(const std::string& iso8601Time, const std::string& logName) + std::string time_point_to_iso8601(std::chrono::system_clock::time_point tp) + { + const std::time_t tt = std::chrono::system_clock::to_time_t(tp); + std::tm tm; + gmtime_r(&tt, &tm); + + std::ostringstream oss; + oss << tm.tm_year + 1900 << '-' << std::setfill('0') << std::setw(2) << tm.tm_mon + 1 << '-' + << std::setfill('0') << std::setw(2) << tm.tm_mday << 'T'; + oss << std::setfill('0') << std::setw(2) << tm.tm_hour << ':'; + oss << std::setfill('0') << std::setw(2) << tm.tm_min << ':'; + const std::chrono::duration<double> sec + = tp - std::chrono::system_clock::from_time_t(tt) + std::chrono::seconds(tm.tm_sec); + if (sec.count() < 10) + oss << '0'; + oss << std::fixed << sec.count() << 'Z'; + + return oss.str(); + } + + std::chrono::system_clock::time_point iso8601ToTimestamp(const std::string& iso8601Time, + const std::string& logName) { std::chrono::system_clock::time_point timestamp; std::tm tm; - const char *cstr = iso8601Time.c_str(); - const char *trailing; + const char* cstr = iso8601Time.c_str(); + const char* trailing; if (!(trailing = strptime(cstr, "%Y-%m-%dT%H:%M:%S", &tm))) { LOG_WRN(logName << " [" << iso8601Time << "] is in invalid format." - << "Returning " << timestamp.time_since_epoch().count()); + << "Returning " << timestamp.time_since_epoch().count()); return timestamp; } + timestamp += std::chrono::seconds(timegm(&tm)); if (trailing[0] == '\0') return timestamp; - double us; + if (trailing[0] != '.') { LOG_WRN(logName << " [" << iso8601Time << "] is in invalid format." - << ". Returning " << timestamp.time_since_epoch().count()); + << ". Returning " << timestamp.time_since_epoch().count()); return timestamp; } - char *end = nullptr; - us = strtod(trailing, &end); - std::size_t seconds_us = us * std::chrono::system_clock::period::den / std::chrono::system_clock::period::num; + + char* end = nullptr; + const size_t us = strtoul(trailing + 1, &end, 10); // Skip the '.' and read as integer. + const std::size_t seconds_us = us * std::chrono::system_clock::period::den + / std::chrono::system_clock::period::num / 1000000; timestamp += std::chrono::system_clock::duration(seconds_us); diff --git a/common/Util.hpp b/common/Util.hpp index d345950ba..82389c1ab 100644 --- a/common/Util.hpp +++ b/common/Util.hpp @@ -935,6 +935,9 @@ int main(int argc, char**argv) //// Return time in ISO8061 fraction format std::string getIso8601FracformatTime(std::chrono::system_clock::time_point time); + /// Convert a time_point to iso8601 formatted string. + std::string time_point_to_iso8601(std::chrono::system_clock::time_point tp); + //// Convert time from ISO8061 fraction format std::chrono::system_clock::time_point iso8601ToTimestamp(const std::string& iso8601Time, const std::string& logName); diff --git a/test/WhiteBoxTests.cpp b/test/WhiteBoxTests.cpp index 597adb500..219c3ccf2 100644 --- a/test/WhiteBoxTests.cpp +++ b/test/WhiteBoxTests.cpp @@ -738,37 +738,57 @@ void WhiteBoxTests::testTime() { std::ostringstream oss; - std::chrono::system_clock::time_point t(std::chrono::nanoseconds(1567444337874777375)); - CPPUNIT_ASSERT_EQUAL(std::string("2019-09-02T17:12:17.874777Z"), Util::getIso8601FracformatTime(t)); + std::chrono::system_clock::time_point t(std::chrono::nanoseconds(1567444337874777375)); + CPPUNIT_ASSERT_EQUAL(std::string("2019-09-02T17:12:17.874777Z"), + Util::getIso8601FracformatTime(t)); t = std::chrono::system_clock::time_point(std::chrono::nanoseconds(0)); - CPPUNIT_ASSERT_EQUAL(std::string("1970-01-01T00:00:00.000000Z"), Util::getIso8601FracformatTime(t)); + CPPUNIT_ASSERT_EQUAL(std::string("1970-01-01T00:00:00.000000Z"), + Util::getIso8601FracformatTime(t)); - t = Util::iso8601ToTimestamp("2019-09-02T17:12:17.874777Z", "LastModifiedTime"); - oss << t.time_since_epoch().count(); - CPPUNIT_ASSERT_EQUAL(std::string("1567444337874777000"), oss.str()); - - oss.str(std::string()); t = Util::iso8601ToTimestamp("1970-01-01T00:00:00.000000Z", "LastModifiedTime"); oss << t.time_since_epoch().count(); CPPUNIT_ASSERT_EQUAL(std::string("0"), oss.str()); + CPPUNIT_ASSERT_EQUAL(std::string("1970-01-01T00:00:00.000000Z"), + Util::time_point_to_iso8601(t)); oss.str(std::string()); - t = std::chrono::system_clock::now(); - uint64_t t_in_micros = (t.time_since_epoch().count() / 1000) * 1000; - oss << t_in_micros; - std::string first = oss.str(); - std::string s = Util::getIso8601FracformatTime(t); - t = Util::iso8601ToTimestamp(s, "LastModifiedTime"); + t = Util::iso8601ToTimestamp("2019-09-02T17:12:17.874777Z", "LastModifiedTime"); + oss << t.time_since_epoch().count(); + CPPUNIT_ASSERT_EQUAL(std::string("1567444337874777000"), oss.str()); + CPPUNIT_ASSERT_EQUAL(std::string("2019-09-02T17:12:17.874777Z"), + Util::time_point_to_iso8601(t)); + oss.str(std::string()); + t = Util::iso8601ToTimestamp("2019-10-24T14:31:28.063730Z", "LastModifiedTime"); oss << t.time_since_epoch().count(); - CPPUNIT_ASSERT_EQUAL(first, oss.str()); + CPPUNIT_ASSERT_EQUAL(std::string("1571927488063730000"), oss.str()); + CPPUNIT_ASSERT_EQUAL(std::string("2019-10-24T14:31:28.063730Z"), + Util::time_point_to_iso8601(t)); + + t = Util::iso8601ToTimestamp("2020-02-20T20:02:20.100000Z", "LastModifiedTime"); + CPPUNIT_ASSERT_EQUAL(std::string("2020-02-20T20:02:20.100000Z"), + Util::time_point_to_iso8601(t)); t = std::chrono::system_clock::time_point(); CPPUNIT_ASSERT_EQUAL(std::string("Thu, 01 Jan 1970 00:00:00"), Util::getHttpTime(t)); t = std::chrono::system_clock::time_point(std::chrono::nanoseconds(1569592993495336798)); CPPUNIT_ASSERT_EQUAL(std::string("Fri, 27 Sep 2019 14:03:13"), Util::getHttpTime(t)); + + for (int i = 0; i < 100; ++i) + { + t = std::chrono::system_clock::now(); + const uint64_t t_in_micros = (t.time_since_epoch().count() / 1000) * 1000; + + const std::string s = Util::getIso8601FracformatTime(t); + t = Util::iso8601ToTimestamp(s, "LastModifiedTime"); + CPPUNIT_ASSERT_EQUAL(std::to_string(t_in_micros), + std::to_string(t.time_since_epoch().count())); + + // Allow a small delay to get a different timestamp on next iteration. + sleep(0); + } } CPPUNIT_TEST_SUITE_REGISTRATION(WhiteBoxTests); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits