Implement CFX_DateTime::Now() in terms of FXSYS_time()

Allows overriding the Now() function's return via the usual
FSDK_SetTimeFunction() mechanism as needed by subsequent test CLs.
We avoid more system dependent code, and an unimplemented case for
Fuchsia. We lose msec accuracy, but the only two callers of Now()
don't require this.

Change-Id: I27b87df5364c1432f9a877b496e55789f1c29af3
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/93831
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcrt/BUILD.gn b/core/fxcrt/BUILD.gn
index b92e1d6..865516a 100644
--- a/core/fxcrt/BUILD.gn
+++ b/core/fxcrt/BUILD.gn
@@ -155,6 +155,7 @@
     "byteorder_unittest.cpp",
     "bytestring_unittest.cpp",
     "cfx_bitstream_unittest.cpp",
+    "cfx_datetime_unittest.cpp",
     "cfx_seekablestreamproxy_unittest.cpp",
     "cfx_timer_unittest.cpp",
     "cfx_widetextbuf_unittest.cpp",
diff --git a/core/fxcrt/cfx_datetime.cpp b/core/fxcrt/cfx_datetime.cpp
index b45d39f..731b56a 100644
--- a/core/fxcrt/cfx_datetime.cpp
+++ b/core/fxcrt/cfx_datetime.cpp
@@ -7,15 +7,10 @@
 #include "core/fxcrt/cfx_datetime.h"
 
 #include "build/build_config.h"
+#include "core/fxcrt/fx_extension.h"
 #include "core/fxcrt/fx_system.h"
 #include "third_party/base/check.h"
 
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
-    BUILDFLAG(IS_APPLE) || defined(OS_ASMJS)
-#include <sys/time.h>
-#include <time.h>
-#endif
-
 namespace {
 
 constexpr uint8_t kDaysPerMonth[12] = {31, 28, 31, 30, 31, 30,
@@ -69,18 +64,6 @@
          iYear / 400;
 }
 
-// Exact same structure as Win32 SYSTEMTIME.
-struct FX_SYSTEMTIME {
-  uint16_t wYear;
-  uint16_t wMonth;
-  uint16_t wDayOfWeek;
-  uint16_t wDay;
-  uint16_t wHour;
-  uint16_t wMinute;
-  uint16_t wSecond;
-  uint16_t wMillisecond;
-};
-
 }  // namespace
 
 uint8_t FX_DaysInMonth(int32_t iYear, uint8_t iMonth) {
@@ -99,33 +82,13 @@
 
 // static
 CFX_DateTime CFX_DateTime::Now() {
-  FX_SYSTEMTIME local_time;
-#if BUILDFLAG(IS_WIN)
-  ::GetLocalTime(reinterpret_cast<LPSYSTEMTIME>(&local_time));
-#elif BUILDFLAG(IS_FUCHSIA)
-  // TODO(crbug.com/pdfium/1775): Implement using ICU.
-#else
-  timeval tv;
-  gettimeofday(&tv, nullptr);
-
-  struct tm st;
-  localtime_r(&tv.tv_sec, &st);
-  local_time.wYear = st.tm_year + 1900;
-  local_time.wMonth = st.tm_mon + 1;
-  local_time.wDayOfWeek = st.tm_wday;
-  local_time.wDay = st.tm_mday;
-  local_time.wHour = st.tm_hour;
-  local_time.wMinute = st.tm_min;
-  local_time.wSecond = st.tm_sec;
-  local_time.wMillisecond = tv.tv_usec / 1000;
-#endif  // BUILDFLAG(IS_WIN)
-
-  return CFX_DateTime(local_time.wYear, static_cast<uint8_t>(local_time.wMonth),
-                      static_cast<uint8_t>(local_time.wDay),
-                      static_cast<uint8_t>(local_time.wHour),
-                      static_cast<uint8_t>(local_time.wMinute),
-                      static_cast<uint8_t>(local_time.wSecond),
-                      local_time.wMillisecond);
+  time_t t = FXSYS_time(nullptr);
+  struct tm* pTime = FXSYS_localtime(&t);
+  return CFX_DateTime(
+      pTime->tm_year + 1900, static_cast<uint8_t>(pTime->tm_mon + 1),
+      static_cast<uint8_t>(pTime->tm_mday),
+      static_cast<uint8_t>(pTime->tm_hour), static_cast<uint8_t>(pTime->tm_min),
+      static_cast<uint8_t>(pTime->tm_sec), 0);
 }
 
 int32_t CFX_DateTime::GetDayOfWeek() const {
diff --git a/core/fxcrt/cfx_datetime.h b/core/fxcrt/cfx_datetime.h
index 2b4f8d5..617eaa6 100644
--- a/core/fxcrt/cfx_datetime.h
+++ b/core/fxcrt/cfx_datetime.h
@@ -14,7 +14,7 @@
 
 class CFX_DateTime {
  public:
-  static CFX_DateTime Now();
+  static CFX_DateTime Now();  // Accurate to seconds, subject to test overrides.
 
   CFX_DateTime() = default;
   CFX_DateTime(int32_t year,
diff --git a/core/fxcrt/cfx_datetime_unittest.cpp b/core/fxcrt/cfx_datetime_unittest.cpp
new file mode 100644
index 0000000..c0eaaee
--- /dev/null
+++ b/core/fxcrt/cfx_datetime_unittest.cpp
@@ -0,0 +1,33 @@
+// Copyright 2021 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/fxcrt/cfx_datetime.h"
+
+#include "core/fxcrt/fx_extension.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class FakeTimeTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    // Arbitrary, picked descending digits, 2020-04-23 15:05:21.
+    FXSYS_SetTimeFunction([]() -> time_t { return 1587654321; });
+    FXSYS_SetLocaltimeFunction([](const time_t* t) { return gmtime(t); });
+  }
+
+  void TearDown() override {
+    FXSYS_SetTimeFunction(nullptr);
+    FXSYS_SetLocaltimeFunction(nullptr);
+  }
+};
+
+TEST_F(FakeTimeTest, Now) {
+  CFX_DateTime dt = CFX_DateTime::Now();
+  EXPECT_EQ(2020, dt.GetYear());
+  EXPECT_EQ(4, dt.GetMonth());
+  EXPECT_EQ(23, dt.GetDay());
+  EXPECT_EQ(15, dt.GetHour());
+  EXPECT_EQ(5, dt.GetMinute());
+  EXPECT_EQ(21, dt.GetSecond());
+  EXPECT_EQ(0, dt.GetMillisecond());
+}