Replace FX_TIMEZONE with an integer.

It is much easier to think of the timezone offset in just minutes for
most use cases.

Bug: pdfium:1662
Change-Id: I7783e686b146c969eb52b28d29166394f33379e4
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/78878
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/fxjs/xfa/cfxjse_formcalc_context.cpp b/fxjs/xfa/cfxjse_formcalc_context.cpp
index 7dbca37..a0e8b98 100644
--- a/fxjs/xfa/cfxjse_formcalc_context.cpp
+++ b/fxjs/xfa/cfxjse_formcalc_context.cpp
@@ -2070,7 +2070,7 @@
   // TODO(dsinclair): See if there is other time conversion code in pdfium and
   //   consolidate.
   int32_t mins = hour * 60 + min;
-  mins -= (pMgr->GetDefLocale()->GetTimeZone().tzHour * 60);
+  mins -= pMgr->GetDefLocale()->GetTimeZoneInMinutes();
   while (mins > 1440)
     mins -= 1440;
   while (mins < 0)
@@ -2486,8 +2486,7 @@
 
   constexpr int kMinutesInDay = 24 * 60;
   int32_t minutes_with_tz =
-      hour * 60 + minute -
-      FX_TimeZoneOffsetInMinutes(CXFA_TimeZoneProvider().GetTimeZone());
+      hour * 60 + minute - CXFA_TimeZoneProvider().GetTimeZoneInMinutes();
   minutes_with_tz %= kMinutesInDay;
   if (minutes_with_tz < 0)
     minutes_with_tz += kMinutesInDay;
diff --git a/xfa/fgas/crt/BUILD.gn b/xfa/fgas/crt/BUILD.gn
index 80c4f6c..33f2630 100644
--- a/xfa/fgas/crt/BUILD.gn
+++ b/xfa/fgas/crt/BUILD.gn
@@ -13,8 +13,6 @@
     "cfgas_decimal.h",
     "cfgas_stringformatter.cpp",
     "cfgas_stringformatter.h",
-    "fx_timezone.cpp",
-    "fx_timezone.h",
     "locale_iface.h",
     "locale_mgr_iface.h",
   ]
diff --git a/xfa/fgas/crt/cfgas_stringformatter.cpp b/xfa/fgas/crt/cfgas_stringformatter.cpp
index ac2cbe9..bfeaf01 100644
--- a/xfa/fgas/crt/cfgas_stringformatter.cpp
+++ b/xfa/fgas/crt/cfgas_stringformatter.cpp
@@ -82,9 +82,8 @@
 const wchar_t kDateSymbols[] = L"DJMEeGgYwW";
 const wchar_t kConstChars[] = L",-:/. ";
 
-size_t ParseTimeZone(pdfium::span<const wchar_t> spStr, FX_TIMEZONE* tz) {
-  tz->tzHour = 0;
-  tz->tzMinute = 0;
+size_t ParseTimeZone(pdfium::span<const wchar_t> spStr, int* tz) {
+  *tz = 0;
   if (spStr.empty())
     return 0;
 
@@ -93,18 +92,21 @@
 
   size_t iStart = 1;
   size_t iEnd = iStart + 2;
+  int tz_hour = 0;
   while (iStart < spStr.size() && iStart < iEnd)
-    tz->tzHour = tz->tzHour * 10 + FXSYS_DecimalCharToInt(spStr[iStart++]);
+    tz_hour = tz_hour * 10 + FXSYS_DecimalCharToInt(spStr[iStart++]);
 
   if (iStart < spStr.size() && spStr[iStart] == ':')
     iStart++;
 
   iEnd = iStart + 2;
+  int tz_minute = 0;
   while (iStart < spStr.size() && iStart < iEnd)
-    tz->tzMinute = tz->tzMinute * 10 + FXSYS_DecimalCharToInt(spStr[iStart++]);
+    tz_minute = tz_minute * 10 + FXSYS_DecimalCharToInt(spStr[iStart++]);
 
+  *tz = tz_hour * 60 + tz_minute;
   if (bNegative)
-    tz->tzHour = -tz->tzHour;
+    *tz *= -1;
 
   return iStart;
 }
@@ -334,16 +336,13 @@
   return !!(*cc);
 }
 
-void ResolveZone(FX_TIMEZONE tzDiff,
+void ResolveZone(int tz_diff_minutes,
                  const LocaleIface* pLocale,
                  uint32_t* wHour,
                  uint32_t* wMinute) {
   int32_t iMinuteDiff = *wHour * 60 + *wMinute;
-  FX_TIMEZONE tzLocale = pLocale->GetTimeZone();
-  iMinuteDiff += tzLocale.tzHour * 60 +
-                 (tzLocale.tzHour < 0 ? -tzLocale.tzMinute : tzLocale.tzMinute);
-  iMinuteDiff -= tzDiff.tzHour * 60 +
-                 (tzDiff.tzHour < 0 ? -tzDiff.tzMinute : tzDiff.tzMinute);
+  iMinuteDiff += pLocale->GetTimeZoneInMinutes();
+  iMinuteDiff -= tz_diff_minutes;
 
   iMinuteDiff %= 1440;
   if (iMinuteDiff < 0)
@@ -448,13 +447,10 @@
       tz += spTime[(*cc)++];
       tz += spTime[(*cc)++];
       if (tz.EqualsASCII("GMT")) {
-        FX_TIMEZONE tzDiff;
-        tzDiff.tzHour = 0;
-        tzDiff.tzMinute = 0;
-        if (*cc < spTime.size() && (spTime[*cc] == '-' || spTime[*cc] == '+')) {
-          *cc += ParseTimeZone(spTime.subspan(*cc), &tzDiff);
-        }
-        ResolveZone(tzDiff, pLocale, &hour, &minute);
+        int tz_diff_minutes = 0;
+        if (*cc < spTime.size() && (spTime[*cc] == '-' || spTime[*cc] == '+'))
+          *cc += ParseTimeZone(spTime.subspan(*cc), &tz_diff_minutes);
+        ResolveZone(tz_diff_minutes, pLocale, &hour, &minute);
       } else {
         // Search the timezone list. There are only 8 of them, so linear scan.
         for (size_t i = 0; i < pdfium::size(g_FXLocaleTimeZoneData); ++i) {
@@ -469,9 +465,9 @@
       }
     } else if (symbol.EqualsASCII("z")) {
       if (spTime[*cc] != 'Z') {
-        FX_TIMEZONE tzDiff;
-        *cc += ParseTimeZone(spTime.subspan(*cc), &tzDiff);
-        ResolveZone(tzDiff, pLocale, &hour, &minute);
+        int tz_diff_minutes = 0;
+        *cc += ParseTimeZone(spTime.subspan(*cc), &tz_diff_minutes);
+        ResolveZone(tz_diff_minutes, pLocale, &hour, &minute);
       } else {
         (*cc)++;
       }
@@ -683,11 +679,12 @@
     } else if (symbol.EqualsASCIINoCase("z")) {
       if (symbol.EqualsASCII("Z"))
         wsResult += L"GMT";
-      FX_TIMEZONE tz = pLocale->GetTimeZone();
-      if (tz.tzHour != 0 || tz.tzMinute != 0) {
-        wsResult += tz.tzHour < 0 ? L"-" : L"+";
-        wsResult +=
-            WideString::Format(L"%02d:%02d", abs(tz.tzHour), tz.tzMinute);
+      int tz_minutes = pLocale->GetTimeZoneInMinutes();
+      if (tz_minutes != 0) {
+        wsResult += tz_minutes < 0 ? L"-" : L"+";
+        int abs_tz_minutes = abs(tz_minutes);
+        wsResult += WideString::Format(L"%02d:%02d", abs_tz_minutes / 60,
+                                       abs_tz_minutes % 60);
       }
     }
   }
@@ -849,12 +846,10 @@
   }
 
   if (cc < spTime.size()) {
-    FX_TIMEZONE tzDiff;
-    tzDiff.tzHour = 0;
-    tzDiff.tzMinute = 0;
+    int tz_diff_minutes = 0;
     if (spTime[cc] != 'Z')
-      cc += ParseTimeZone(spTime.subspan(cc), &tzDiff);
-    ResolveZone(tzDiff, pLocale, &hour, &minute);
+      cc += ParseTimeZone(spTime.subspan(cc), &tz_diff_minutes);
+    ResolveZone(tz_diff_minutes, pLocale, &hour, &minute);
   }
 
   datetime->SetTime(hour, minute, second, millisecond);
diff --git a/xfa/fgas/crt/fx_timezone.cpp b/xfa/fgas/crt/fx_timezone.cpp
deleted file mode 100644
index f80a1d8..0000000
--- a/xfa/fgas/crt/fx_timezone.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-// 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.
-
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-
-#include "xfa/fgas/crt/fx_timezone.h"
-
-int FX_TimeZoneOffsetInMinutes(const FX_TIMEZONE& tz) {
-  return tz.tzHour * 60 + tz.tzMinute;
-}
diff --git a/xfa/fgas/crt/fx_timezone.h b/xfa/fgas/crt/fx_timezone.h
deleted file mode 100644
index 777df10..0000000
--- a/xfa/fgas/crt/fx_timezone.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-
-#ifndef XFA_FGAS_CRT_FX_TIMEZONE_H_
-#define XFA_FGAS_CRT_FX_TIMEZONE_H_
-
-#include <stdint.h>
-
-struct FX_TIMEZONE {
-  int8_t tzHour;
-  uint8_t tzMinute;
-};
-
-int FX_TimeZoneOffsetInMinutes(const FX_TIMEZONE& tz);
-
-#endif  // XFA_FGAS_CRT_FX_TIMEZONE_H_
diff --git a/xfa/fgas/crt/locale_iface.h b/xfa/fgas/crt/locale_iface.h
index 6976501..b3b0dc5 100644
--- a/xfa/fgas/crt/locale_iface.h
+++ b/xfa/fgas/crt/locale_iface.h
@@ -8,7 +8,6 @@
 #define XFA_FGAS_CRT_LOCALE_IFACE_H_
 
 #include "core/fxcrt/fx_string.h"
-#include "xfa/fgas/crt/fx_timezone.h"
 
 class LocaleIface {
  public:
@@ -39,7 +38,7 @@
   virtual WideString GetMonthName(int32_t nMonth, bool bAbbr) const = 0;
   virtual WideString GetDayName(int32_t nWeek, bool bAbbr) const = 0;
   virtual WideString GetMeridiemName(bool bAM) const = 0;
-  virtual FX_TIMEZONE GetTimeZone() const = 0;
+  virtual int GetTimeZoneInMinutes() const = 0;
   virtual WideString GetEraName(bool bAD) const = 0;
   virtual WideString GetDatePattern(DateTimeSubcategory eType) const = 0;
   virtual WideString GetTimePattern(DateTimeSubcategory eType) const = 0;
diff --git a/xfa/fxfa/parser/cxfa_nodelocale.cpp b/xfa/fxfa/parser/cxfa_nodelocale.cpp
index 1f717ed..65da971 100644
--- a/xfa/fxfa/parser/cxfa_nodelocale.cpp
+++ b/xfa/fxfa/parser/cxfa_nodelocale.cpp
@@ -91,8 +91,8 @@
   return GetCalendarSymbol(XFA_Element::MeridiemNames, bAM ? 0 : 1, false);
 }
 
-FX_TIMEZONE CXFA_NodeLocale::GetTimeZone() const {
-  return CXFA_TimeZoneProvider().GetTimeZone();
+int CXFA_NodeLocale::GetTimeZoneInMinutes() const {
+  return CXFA_TimeZoneProvider().GetTimeZoneInMinutes();
 }
 
 WideString CXFA_NodeLocale::GetEraName(bool bAD) const {
diff --git a/xfa/fxfa/parser/cxfa_nodelocale.h b/xfa/fxfa/parser/cxfa_nodelocale.h
index f6fdac9..479222d 100644
--- a/xfa/fxfa/parser/cxfa_nodelocale.h
+++ b/xfa/fxfa/parser/cxfa_nodelocale.h
@@ -34,7 +34,7 @@
   WideString GetMonthName(int32_t nMonth, bool bAbbr) const override;
   WideString GetDayName(int32_t nWeek, bool bAbbr) const override;
   WideString GetMeridiemName(bool bAM) const override;
-  FX_TIMEZONE GetTimeZone() const override;
+  int GetTimeZoneInMinutes() const override;
   WideString GetEraName(bool bAD) const override;
 
   WideString GetDatePattern(DateTimeSubcategory eType) const override;
diff --git a/xfa/fxfa/parser/cxfa_timezoneprovider.cpp b/xfa/fxfa/parser/cxfa_timezoneprovider.cpp
index 7973c2c..6385ac6 100644
--- a/xfa/fxfa/parser/cxfa_timezoneprovider.cpp
+++ b/xfa/fxfa/parser/cxfa_timezoneprovider.cpp
@@ -26,9 +26,7 @@
     g_bProviderTimeZoneSet = true;
     TZSET();
   }
-  m_tz.tzHour = static_cast<int8_t>(TIMEZONE / -3600);
-  m_tz.tzMinute =
-      static_cast<int8_t>((abs(static_cast<int>(TIMEZONE)) % 3600) / 60);
+  tz_minutes_ = TIMEZONE / -60;
 }
 
 CXFA_TimeZoneProvider::~CXFA_TimeZoneProvider() = default;
diff --git a/xfa/fxfa/parser/cxfa_timezoneprovider.h b/xfa/fxfa/parser/cxfa_timezoneprovider.h
index 3cfc8ad..853f75c 100644
--- a/xfa/fxfa/parser/cxfa_timezoneprovider.h
+++ b/xfa/fxfa/parser/cxfa_timezoneprovider.h
@@ -7,17 +7,15 @@
 #ifndef XFA_FXFA_PARSER_CXFA_TIMEZONEPROVIDER_H_
 #define XFA_FXFA_PARSER_CXFA_TIMEZONEPROVIDER_H_
 
-#include "xfa/fgas/crt/fx_timezone.h"
-
 class CXFA_TimeZoneProvider {
  public:
   CXFA_TimeZoneProvider();
   ~CXFA_TimeZoneProvider();
 
-  FX_TIMEZONE GetTimeZone() const { return m_tz; }
+  int GetTimeZoneInMinutes() const { return tz_minutes_; }
 
  private:
-  FX_TIMEZONE m_tz;
+  int tz_minutes_;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_TIMEZONEPROVIDER_H_
diff --git a/xfa/fxfa/parser/cxfa_timezoneprovider_unittest.cpp b/xfa/fxfa/parser/cxfa_timezoneprovider_unittest.cpp
index f4e7027..232b2a6 100644
--- a/xfa/fxfa/parser/cxfa_timezoneprovider_unittest.cpp
+++ b/xfa/fxfa/parser/cxfa_timezoneprovider_unittest.cpp
@@ -10,63 +10,49 @@
 TEST(CXFA_TimeZoneProviderTest, HourOffsets) {
   {
     ScopedSetTZ scoped_set_tz("UTC");
-    CXFA_TimeZoneProvider provider;
-    EXPECT_EQ(0, FX_TimeZoneOffsetInMinutes(provider.GetTimeZone()));
+    EXPECT_EQ(0, CXFA_TimeZoneProvider().GetTimeZoneInMinutes());
   }
   {
     ScopedSetTZ scoped_set_tz("UTC+1");
-    CXFA_TimeZoneProvider provider;
-    EXPECT_EQ(-60, FX_TimeZoneOffsetInMinutes(provider.GetTimeZone()));
+    EXPECT_EQ(-60, CXFA_TimeZoneProvider().GetTimeZoneInMinutes());
   }
   {
     ScopedSetTZ scoped_set_tz("UTC-1");
-    CXFA_TimeZoneProvider provider;
-    EXPECT_EQ(60, FX_TimeZoneOffsetInMinutes(provider.GetTimeZone()));
+    EXPECT_EQ(60, CXFA_TimeZoneProvider().GetTimeZoneInMinutes());
   }
   {
     ScopedSetTZ scoped_set_tz("UTC+14");
-    CXFA_TimeZoneProvider provider;
-    EXPECT_EQ(-840, FX_TimeZoneOffsetInMinutes(provider.GetTimeZone()));
+    EXPECT_EQ(-840, CXFA_TimeZoneProvider().GetTimeZoneInMinutes());
   }
   {
     ScopedSetTZ scoped_set_tz("UTC-14");
-    CXFA_TimeZoneProvider provider;
-    EXPECT_EQ(840, FX_TimeZoneOffsetInMinutes(provider.GetTimeZone()));
+    EXPECT_EQ(840, CXFA_TimeZoneProvider().GetTimeZoneInMinutes());
   }
 }
 
 TEST(CXFA_TimeZoneProviderTest, HalfHourOffsets) {
   {
     ScopedSetTZ scoped_set_tz("UTC+0:30");
-    CXFA_TimeZoneProvider provider;
-    // TODO(crbug.com/pdfium/1662): Should be -30.
-    EXPECT_EQ(30, FX_TimeZoneOffsetInMinutes(provider.GetTimeZone()));
+    EXPECT_EQ(-30, CXFA_TimeZoneProvider().GetTimeZoneInMinutes());
   }
   {
     ScopedSetTZ scoped_set_tz("UTC-0:30");
-    CXFA_TimeZoneProvider provider;
-    EXPECT_EQ(30, FX_TimeZoneOffsetInMinutes(provider.GetTimeZone()));
+    EXPECT_EQ(30, CXFA_TimeZoneProvider().GetTimeZoneInMinutes());
   }
   {
     ScopedSetTZ scoped_set_tz("UTC+1:30");
-    CXFA_TimeZoneProvider provider;
-    // TODO(crbug.com/pdfium/1662): Should be -90.
-    EXPECT_EQ(-30, FX_TimeZoneOffsetInMinutes(provider.GetTimeZone()));
+    EXPECT_EQ(-90, CXFA_TimeZoneProvider().GetTimeZoneInMinutes());
   }
   {
     ScopedSetTZ scoped_set_tz("UTC-1:30");
-    CXFA_TimeZoneProvider provider;
-    EXPECT_EQ(90, FX_TimeZoneOffsetInMinutes(provider.GetTimeZone()));
+    EXPECT_EQ(90, CXFA_TimeZoneProvider().GetTimeZoneInMinutes());
   }
   {
     ScopedSetTZ scoped_set_tz("UTC+9:30");
-    CXFA_TimeZoneProvider provider;
-    // TODO(crbug.com/pdfium/1662): Should be -570.
-    EXPECT_EQ(-510, FX_TimeZoneOffsetInMinutes(provider.GetTimeZone()));
+    EXPECT_EQ(-570, CXFA_TimeZoneProvider().GetTimeZoneInMinutes());
   }
   {
     ScopedSetTZ scoped_set_tz("UTC-9:30");
-    CXFA_TimeZoneProvider provider;
-    EXPECT_EQ(570, FX_TimeZoneOffsetInMinutes(provider.GetTimeZone()));
+    EXPECT_EQ(570, CXFA_TimeZoneProvider().GetTimeZoneInMinutes());
   }
 }
diff --git a/xfa/fxfa/parser/cxfa_xmllocale.cpp b/xfa/fxfa/parser/cxfa_xmllocale.cpp
index b28c4ec..5b09f4d 100644
--- a/xfa/fxfa/parser/cxfa_xmllocale.cpp
+++ b/xfa/fxfa/parser/cxfa_xmllocale.cpp
@@ -111,8 +111,8 @@
   return GetCalendarSymbol(L"meridiem", bAM ? 0 : 1, false);
 }
 
-FX_TIMEZONE CXFA_XMLLocale::GetTimeZone() const {
-  return CXFA_TimeZoneProvider().GetTimeZone();
+int CXFA_XMLLocale::GetTimeZoneInMinutes() const {
+  return CXFA_TimeZoneProvider().GetTimeZoneInMinutes();
 }
 
 WideString CXFA_XMLLocale::GetEraName(bool bAD) const {
diff --git a/xfa/fxfa/parser/cxfa_xmllocale.h b/xfa/fxfa/parser/cxfa_xmllocale.h
index c693cbd..3d48aaf 100644
--- a/xfa/fxfa/parser/cxfa_xmllocale.h
+++ b/xfa/fxfa/parser/cxfa_xmllocale.h
@@ -38,7 +38,7 @@
   WideString GetMonthName(int32_t nMonth, bool bAbbr) const override;
   WideString GetDayName(int32_t nWeek, bool bAbbr) const override;
   WideString GetMeridiemName(bool bAM) const override;
-  FX_TIMEZONE GetTimeZone() const override;
+  int GetTimeZoneInMinutes() const override;
   WideString GetEraName(bool bAD) const override;
 
   WideString GetDatePattern(DateTimeSubcategory eType) const override;