[Libreoffice-commits] online.git: common/Util.cpp common/Util.hpp test/WhiteBoxTests.cpp

Ashod Nakashian (via logerrit) logerrit at kemper.freedesktop.org
Tue Oct 29 01:39:53 UTC 2019


 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.nakashian at collabora.co.uk>
AuthorDate: Fri Oct 25 20:48:05 2019 -0400
Commit:     Ashod Nakashian <ashnakash at 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 <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at 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);


More information about the Libreoffice-commits mailing list