Fix timezone issues on UsageTimeLimitProcessor.

Bug: 823536, 860679
Change-Id: I79cd88766e92f9f2243d7ce9a4de8545d0932014
Reviewed-on: https://chromium-review.googlesource.com/1124499
Commit-Queue: Henrique Grandinetti <hgrandinetti@google.com>
Reviewed-by: Alexander Alekseev <alemate@chromium.org>
Reviewed-by: Jacob Dufault <jdufault@chromium.org>
Cr-Commit-Position: refs/heads/master@{#576591}
diff --git a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
index c48859a..db5dabf 100644
--- a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
+++ b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
@@ -66,6 +66,7 @@
     : context_(context),
       pref_service_(Profile::FromBrowserContext(context)->GetPrefs()) {
   session_manager::SessionManager::Get()->AddObserver(this);
+  system::TimezoneSettings::GetInstance()->AddObserver(this);
   pref_change_registrar_.Init(pref_service_);
   pref_change_registrar_.Add(
       prefs::kUsageTimeLimit,
@@ -75,6 +76,7 @@
 
 ScreenTimeController::~ScreenTimeController() {
   session_manager::SessionManager::Get()->RemoveObserver(this);
+  system::TimezoneSettings::GetInstance()->RemoveObserver(this);
   SaveScreenTimeProgressBeforeExit();
 }
 
@@ -94,6 +96,8 @@
   ResetTimers();
 
   base::Time now = base::Time::Now();
+  const icu::TimeZone& time_zone =
+      system::TimezoneSettings::GetInstance()->GetTimezone();
   base::Optional<usage_time_limit::State> last_state = GetLastStateFromPref();
   // Used time should be 0 when time usage limit is disabled.
   base::TimeDelta used_time = base::TimeDelta::FromMinutes(0);
@@ -101,9 +105,9 @@
     used_time = GetScreenTimeDuration();
   const base::DictionaryValue* time_limit =
       pref_service_->GetDictionary(prefs::kUsageTimeLimit);
-  usage_time_limit::State state =
-      usage_time_limit::GetState(time_limit->CreateDeepCopy(), used_time,
-                                 first_screen_start_time_, now, last_state);
+  usage_time_limit::State state = usage_time_limit::GetState(
+      time_limit->CreateDeepCopy(), used_time, first_screen_start_time_, now,
+      &time_zone, last_state);
   SaveCurrentStateToPref(state);
 
   // Show/hide time limits message based on the policy enforcement.
@@ -165,8 +169,8 @@
   }
 
   // Schedule timer to refresh the screen time usage.
-  base::Time reset_time =
-      usage_time_limit::GetExpectedResetTime(time_limit->CreateDeepCopy(), now);
+  base::Time reset_time = usage_time_limit::GetExpectedResetTime(
+      time_limit->CreateDeepCopy(), now, &time_zone);
   if (reset_time <= now) {
     RefreshScreenLimit();
   } else {
@@ -435,4 +439,8 @@
   }
 }
 
+void ScreenTimeController::TimezoneChanged(const icu::TimeZone& timezone) {
+  CheckTimeLimit();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/screen_time_controller.h b/chrome/browser/chromeos/child_accounts/screen_time_controller.h
index 63d607d..d75fe10 100644
--- a/chrome/browser/chromeos/child_accounts/screen_time_controller.h
+++ b/chrome/browser/chromeos/child_accounts/screen_time_controller.h
@@ -26,7 +26,8 @@
 // usage) when necessary to determine the current lock screen state.
 // Schedule notifications and lock/unlock screen based on the processor output.
 class ScreenTimeController : public KeyedService,
-                             public session_manager::SessionManagerObserver {
+                             public session_manager::SessionManagerObserver,
+                             public system::TimezoneSettings::Observer {
  public:
   // Registers preferences.
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
@@ -92,6 +93,9 @@
   // session_manager::SessionManagerObserver:
   void OnSessionStateChanged() override;
 
+  // system::TimezoneSettings::Observer:
+  void TimezoneChanged(const icu::TimeZone& timezone) override;
+
   content::BrowserContext* context_;
   PrefService* pref_service_;
   base::OneShotTimer warning_notification_timer_;
diff --git a/chrome/browser/chromeos/child_accounts/usage_time_limit_processor.cc b/chrome/browser/chromeos/child_accounts/usage_time_limit_processor.cc
index 14baafe..c2b4b77d0 100644
--- a/chrome/browser/chromeos/child_accounts/usage_time_limit_processor.cc
+++ b/chrome/browser/chromeos/child_accounts/usage_time_limit_processor.cc
@@ -50,12 +50,21 @@
   exploded.minute = 0;
   exploded.second = 0;
   exploded.millisecond = 0;
-  base::Time out_time;
-  if (base::Time::FromUTCExploded(exploded, &out_time))
-    return out_time;
+  base::Time utc_midnight;
+  if (base::Time::FromUTCExploded(exploded, &utc_midnight))
+    return utc_midnight;
+
+  LOG(ERROR) << "Malformed exploded time.";
   return time;
 }
 
+// Shifts the current weekday, if the value is positive shifts forward and if
+// negative backwards.
+Weekday WeekdayShift(Weekday current_day, int shift) {
+  return static_cast<Weekday>((static_cast<int>(current_day) + shift) %
+                              static_cast<int>(Weekday::kCount));
+}
+
 // Helper class to process the UsageTimeLimit policy.
 class UsageTimeLimitProcessor {
  public:
@@ -66,6 +75,7 @@
       const base::TimeDelta& used_time,
       const base::Time& usage_timestamp,
       const base::Time& current_time,
+      const icu::TimeZone* const time_zone,
       const base::Optional<State>& previous_state);
 
   ~UsageTimeLimitProcessor() = default;
@@ -130,6 +140,15 @@
   // Checks if the time window limit entry for the current weekday is active.
   bool IsTodayTimeWindowLimitActive();
 
+  // Local midnight.
+  base::Time LocalMidnight(base::Time time);
+
+  // Get the current weekday.
+  Weekday GetCurrentWeekday();
+
+  // Get the time zone offset. Used to convert GMT time to local time.
+  base::TimeDelta GetTimeZoneOffset(base::Time time);
+
   // Converts the policy time, which is a delta from midnight, to a timestamp.
   // Since this is done based on the current time, a shift in days param is
   // available.
@@ -153,6 +172,9 @@
   // The current time, not necessarily equal to usage_timestamp.
   const base::Time current_time;
 
+  // Unowned. The device's timezone.
+  const icu::TimeZone* const time_zone;
+
   // Current weekday, extracted from current time.
   internal::Weekday current_weekday;
 
@@ -191,6 +213,7 @@
     const base::TimeDelta& used_time,
     const base::Time& usage_timestamp,
     const base::Time& current_time,
+    const icu::TimeZone* const time_zone,
     const base::Optional<State>& previous_state)
     : time_window_limit(std::move(time_window_limit)),
       time_usage_limit(std::move(time_usage_limit)),
@@ -198,7 +221,8 @@
       used_time(used_time),
       usage_timestamp(usage_timestamp),
       current_time(current_time),
-      current_weekday(internal::GetWeekday(current_time)),
+      time_zone(time_zone),
+      current_weekday(GetCurrentWeekday()),
       previous_state(previous_state),
       enabled_time_usage_limit(GetEnabledTimeUsageLimit()) {
   // This will also set overridden_window_limit to true if applicable.
@@ -209,7 +233,7 @@
 
 base::Time UsageTimeLimitProcessor::GetExpectedResetTime() {
   base::TimeDelta delta_from_midnight =
-      current_time - UTCMidnight(current_time);
+      current_time - LocalMidnight(current_time);
   int shift_in_days = 1;
   if (delta_from_midnight < UsageLimitResetTime())
     shift_in_days = 0;
@@ -498,7 +522,7 @@
 
 base::Time UsageTimeLimitProcessor::GetNextUsageLimitResetTime() {
   bool has_reset_today =
-      (current_time - UTCMidnight(current_time)) >= UsageLimitResetTime();
+      (current_time - LocalMidnight(current_time)) >= UsageLimitResetTime();
   return ConvertPolicyTime(UsageLimitResetTime(), has_reset_today ? 1 : 0);
 }
 
@@ -509,7 +533,7 @@
   }
   // Whether this lock override was created after today's reset.
   bool lock_after_reset = override->created_at >
-                          UTCMidnight(current_time) + LockOverrideResetTime();
+                          LocalMidnight(current_time) + LockOverrideResetTime();
   return ConvertPolicyTime(LockOverrideResetTime(), lock_after_reset ? 1 : 0);
 }
 
@@ -537,7 +561,7 @@
             time_window_limit->entries[WeekdayShift(current_weekday, i)];
         if (window_limit) {
           TimeWindowLimitBoundaries limits = window_limit->GetLimits(
-              UTCMidnight(current_time) + base::TimeDelta::FromDays(i));
+              LocalMidnight(current_time) + base::TimeDelta::FromDays(i));
           // Ignores time window limit if it is overridden.
           if (overridden_window_limit &&
               ContainsTime(limits.starts, limits.ends, current_time)) {
@@ -565,7 +589,7 @@
             time_window_limit->entries[WeekdayShift(current_weekday, i)];
         if (window_limit) {
           TimeWindowLimitBoundaries limits = window_limit->GetLimits(
-              UTCMidnight(current_time) + base::TimeDelta::FromDays(i));
+              LocalMidnight(current_time) + base::TimeDelta::FromDays(i));
           // Ignores time window limit if it is overridden.
           if (overridden_window_limit &&
               ContainsTime(limits.starts, limits.ends, current_time)) {
@@ -699,7 +723,7 @@
       time_window_limit.value()
           .entries[internal::WeekdayShift(current_weekday, -1)];
   base::TimeDelta delta_from_midnight =
-      current_time - UTCMidnight(current_time);
+      current_time - LocalMidnight(current_time);
 
   if ((active_time_window_limit || overridden_window_limit) &&
       (!yesterday_window_limit || !yesterday_window_limit->IsOvernight() ||
@@ -724,8 +748,48 @@
 base::Time UsageTimeLimitProcessor::ConvertPolicyTime(
     base::TimeDelta policy_time,
     int shift_in_days) {
-  return UTCMidnight(current_time) + base::TimeDelta::FromDays(shift_in_days) +
-         policy_time;
+  return LocalMidnight(current_time) +
+         base::TimeDelta::FromDays(shift_in_days) + policy_time;
+}
+
+base::Time UsageTimeLimitProcessor::LocalMidnight(base::Time time) {
+  base::TimeDelta time_zone_offset = GetTimeZoneOffset(time);
+  return UTCMidnight(time + time_zone_offset) - time_zone_offset;
+}
+
+Weekday UsageTimeLimitProcessor::GetCurrentWeekday() {
+  base::TimeDelta time_zone_offset = GetTimeZoneOffset(current_time);
+  base::TimeDelta midnight_delta = current_time - UTCMidnight(current_time);
+  // Shift in days due to the timezone.
+  int time_zone_shift = 0;
+  if (midnight_delta + time_zone_offset < base::TimeDelta::FromHours(0)) {
+    time_zone_shift = -1;
+  } else if (midnight_delta + time_zone_offset >=
+             base::TimeDelta::FromHours(24)) {
+    time_zone_shift = 1;
+  }
+
+  base::Time::Exploded exploded;
+  current_time.UTCExplode(&exploded);
+  return WeekdayShift(static_cast<Weekday>(exploded.day_of_week),
+                      time_zone_shift);
+}
+
+base::TimeDelta UsageTimeLimitProcessor::GetTimeZoneOffset(base::Time time) {
+  int32_t raw_offset, dst_offset;
+  UErrorCode status = U_ZERO_ERROR;
+  time_zone->getOffset(time.ToDoubleT() * base::Time::kMillisecondsPerSecond,
+                       true /* local */, raw_offset, dst_offset, status);
+  base::TimeDelta time_zone_offset =
+      base::TimeDelta::FromMilliseconds(raw_offset + dst_offset);
+  if (U_FAILURE(status)) {
+    LOG(ERROR) << "Failed to get time zone offset, error code: " << status;
+    // The fallback case is to get the raw timezone offset ignoring the daylight
+    // saving time.
+    time_zone_offset =
+        base::TimeDelta::FromMilliseconds(time_zone->getRawOffset());
+  }
+  return time_zone_offset;
 }
 
 }  // namespace
@@ -918,17 +982,6 @@
 
 Override& Override::operator=(Override&&) = default;
 
-Weekday GetWeekday(base::Time time) {
-  base::Time::Exploded exploded;
-  time.LocalExplode(&exploded);
-  return static_cast<Weekday>(exploded.day_of_week);
-}
-
-Weekday WeekdayShift(Weekday current_day, int shift) {
-  return static_cast<Weekday>((static_cast<int>(current_day) + shift) %
-                              static_cast<int>(Weekday::kCount));
-}
-
 }  // namespace internal
 
 base::Optional<internal::TimeWindowLimit> TimeWindowLimitFromPolicy(
@@ -961,6 +1014,7 @@
                const base::TimeDelta& used_time,
                const base::Time& usage_timestamp,
                const base::Time& current_time,
+               const icu::TimeZone* const time_zone,
                const base::Optional<State>& previous_state) {
   base::Optional<internal::TimeWindowLimit> time_window_limit =
       TimeWindowLimitFromPolicy(time_limit);
@@ -970,13 +1024,14 @@
   return internal::UsageTimeLimitProcessor(
              std::move(time_window_limit), std::move(time_usage_limit),
              std::move(override), used_time, current_time, current_time,
-             previous_state)
+             time_zone, previous_state)
       .GetState();
 }
 
 base::Time GetExpectedResetTime(
     const std::unique_ptr<base::DictionaryValue>& time_limit,
-    const base::Time current_time) {
+    const base::Time current_time,
+    const icu::TimeZone* const time_zone) {
   base::Optional<internal::TimeWindowLimit> time_window_limit =
       TimeWindowLimitFromPolicy(time_limit);
   base::Optional<internal::TimeUsageLimit> time_usage_limit =
@@ -985,7 +1040,7 @@
   return internal::UsageTimeLimitProcessor(
              std::move(time_window_limit), std::move(time_usage_limit),
              std::move(override), base::TimeDelta::FromMinutes(0), base::Time(),
-             current_time, base::nullopt)
+             current_time, time_zone, base::nullopt)
       .GetExpectedResetTime();
 }
 
diff --git a/chrome/browser/chromeos/child_accounts/usage_time_limit_processor.h b/chrome/browser/chromeos/child_accounts/usage_time_limit_processor.h
index 823ebcd..9a12f1f 100644
--- a/chrome/browser/chromeos/child_accounts/usage_time_limit_processor.h
+++ b/chrome/browser/chromeos/child_accounts/usage_time_limit_processor.h
@@ -12,6 +12,7 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "chromeos/settings/timezone_settings.h"
 
 namespace chromeos {
 namespace usage_time_limit {
@@ -103,12 +104,6 @@
   DISALLOW_COPY_AND_ASSIGN(Override);
 };
 
-// Retrieves the weekday from a time.
-Weekday GetWeekday(base::Time time);
-
-// Shifts the current weekday, if the value is po
-Weekday WeekdayShift(Weekday current_day, int shift);
-
 }  // namespace internal
 
 enum class ActivePolicies {
@@ -163,12 +158,14 @@
                const base::TimeDelta& used_time,
                const base::Time& usage_timestamp,
                const base::Time& current_time,
+               const icu::TimeZone* const time_zone,
                const base::Optional<State>& previous_state);
 
 // Ruturns the expected time that the used time stored should be reseted.
 base::Time GetExpectedResetTime(
     const std::unique_ptr<base::DictionaryValue>& time_limit,
-    base::Time current_time);
+    base::Time current_time,
+    const icu::TimeZone* const time_zone);
 
 }  // namespace usage_time_limit
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/usage_time_limit_processor_unittest.cc b/chrome/browser/chromeos/child_accounts/usage_time_limit_processor_unittest.cc
index 200097e..738dc02 100644
--- a/chrome/browser/chromeos/child_accounts/usage_time_limit_processor_unittest.cc
+++ b/chrome/browser/chromeos/child_accounts/usage_time_limit_processor_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/values.h"
+#include "chromeos/settings/timezone_settings.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -42,14 +43,15 @@
 
 base::Time TimeFromString(const char* time_string) {
   base::Time time;
-  if (!base::Time::FromUTCString(time_string, &time)) {
+  if (!base::Time::FromUTCString(time_string, &time))
     LOG(ERROR) << "Wrong time string format.";
-  }
+
   return time;
 }
 
 std::string CreatePolicyTimestamp(const char* time_string) {
   base::Time time = TimeFromString(time_string);
+
   return std::to_string(
       base::TimeDelta(time - base::Time::UnixEpoch()).InMilliseconds());
 }
@@ -211,11 +213,16 @@
 // is checked that the state is correct before, during and after the policy is
 // enforced.
 TEST_F(UsageTimeLimitProcessorTest, GetStateOnlyTimeWindowLimitSet) {
+  std::unique_ptr<icu::TimeZone> timezone(
+      icu::TimeZone::createTimeZone("GMT+0300"));
+
   // Set up policy.
-  std::string last_updated_millis = CreatePolicyTimestamp("1 Jan 2018 10:00");
+  std::string last_updated_millis =
+      CreatePolicyTimestamp("1 Jan 2018 10:00 GMT+0300");
   base::Value sunday_time_limit =
       CreateTimeWindow(base::Value("SUNDAY"), CreateTime(22, 0),
                        CreateTime(7, 30), base::Value(last_updated_millis));
+  CreatePolicyTimestamp("1 Jan 2018 10:00 GMT+0300");
   base::Value monday_time_limit =
       CreateTimeWindow(base::Value("MONDAY"), CreateTime(21, 0),
                        CreateTime(7, 30), base::Value(last_updated_millis));
@@ -239,17 +246,17 @@
       base::DictionaryValue::From(std::move(time_limit));
 
   base::Time monday_time_window_limit_start =
-      TimeFromString("Mon, 1 Jan 2018 21:00");
+      TimeFromString("Mon, 1 Jan 2018 21:00 GMT+0300");
   base::Time monday_time_window_limit_end =
-      TimeFromString("Tue, 2 Jan 2018 7:30");
+      TimeFromString("Tue, 2 Jan 2018 7:30 GMT+0300");
   base::Time friday_time_window_limit_start =
-      TimeFromString("Fri, 5 Jan 2018 21:00");
+      TimeFromString("Fri, 5 Jan 2018 21:00 GMT+0300");
 
   // Check state before Monday time window limit.
-  base::Time time_one = TimeFromString("Mon, 1 Jan 2018 20:00");
+  base::Time time_one = TimeFromString("Mon, 1 Jan 2018 20:00 GMT+0300");
   State state_one =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(0), time_one,
-               time_one, base::nullopt);
+               time_one, timezone.get(), base::nullopt);
 
   State expected_state_one;
   expected_state_one.is_locked = false;
@@ -262,10 +269,10 @@
   AssertEqState(expected_state_one, state_one);
 
   // Check state during the Monday time window limit.
-  base::Time time_two = TimeFromString("Mon, 1 Jan 2018 22:00");
+  base::Time time_two = TimeFromString("Mon, 1 Jan 2018 22:00 GMT+0300");
   State state_two =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(0), time_two,
-               time_two, state_one);
+               time_two, timezone.get(), state_one);
 
   State expected_state_two;
   expected_state_two.is_locked = true;
@@ -279,10 +286,10 @@
   AssertEqState(expected_state_two, state_two);
 
   // Check state after the Monday time window limit.
-  base::Time time_three = TimeFromString("Tue, 2 Jan 2018 9:00");
+  base::Time time_three = TimeFromString("Tue, 2 Jan 2018 9:00 GMT+0300");
   State state_three =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(0),
-               time_three, time_three, state_two);
+               time_three, time_three, timezone.get(), state_two);
 
   State expected_state_three;
   expected_state_three.is_locked = false;
@@ -299,6 +306,8 @@
 // is checked that the state is correct before and during the policy is
 // enforced.
 TEST_F(UsageTimeLimitProcessorTest, GetStateOnlyTimeUsageLimitSet) {
+  std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("GMT"));
+
   // Set up policy.
   std::string last_updated = CreatePolicyTimestamp("1 Jan 2018 8:00");
   base::Value tuesday_time_usage =
@@ -322,7 +331,7 @@
   base::Time time_one = TimeFromString("Mon, 1 Jan 2018 20:00");
   State state_one =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
-               time_one, time_one, base::nullopt);
+               time_one, time_one, timezone.get(), base::nullopt);
 
   State expected_state_one;
   expected_state_one.is_locked = false;
@@ -340,7 +349,7 @@
   base::Time time_two = TimeFromString("Tue, 2 Jan 2018 12:00");
   State state_two =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(60),
-               time_two, time_two, state_one);
+               time_two, time_two, timezone.get(), state_one);
 
   State expected_state_two;
   expected_state_two.is_locked = false;
@@ -358,7 +367,7 @@
   base::Time time_three = TimeFromString("Tue, 2 Jan 2018 21:00");
   State state_three =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
-               time_three, time_three, state_two);
+               time_three, time_three, timezone.get(), state_two);
 
   base::Time wednesday_reset_time = TimeFromString("Wed, 3 Jan 2018 8:00");
 
@@ -379,6 +388,8 @@
 
 // Test GetState with both time window limit and time usage limit defined.
 TEST_F(UsageTimeLimitProcessorTest, GetStateWithTimeUsageAndWindowLimitActive) {
+  std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("GMT"));
+
   // Setup time window limit.
   std::string last_updated = CreatePolicyTimestamp("1 Jan 2018 8:00");
   base::Value monday_time_limit =
@@ -416,7 +427,7 @@
   base::Time time_one = TimeFromString("Mon, 1 Jan 2018 14:00");
   State state_one =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(80),
-               time_one, time_one, base::nullopt);
+               time_one, time_one, timezone.get(), base::nullopt);
 
   State expected_state_one;
   expected_state_one.is_locked = false;
@@ -434,7 +445,7 @@
   base::Time time_two = TimeFromString("Mon, 1 Jan 2018 16:00");
   State state_two =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(121),
-               time_two, time_two, state_one);
+               time_two, time_two, timezone.get(), state_one);
 
   base::Time monday_time_window_limit_start =
       TimeFromString("Mon, 1 Jan 2018 21:00");
@@ -456,7 +467,7 @@
   base::Time time_three = TimeFromString("Mon, 1 Jan 2018 21:00");
   State state_three =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
-               time_three, time_three, state_two);
+               time_three, time_three, timezone.get(), state_two);
 
   State expected_state_three;
   expected_state_three.is_locked = true;
@@ -478,7 +489,7 @@
   base::Time time_four = TimeFromString("Fri, 5 Jan 2018 8:30");
   State state_four =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
-               time_four, time_four, state_three);
+               time_four, time_four, timezone.get(), state_three);
 
   State expected_state_four;
   expected_state_four.is_locked = false;
@@ -494,6 +505,8 @@
 
 // Check GetState when a lock override is active.
 TEST_F(UsageTimeLimitProcessorTest, GetStateWithOverrideLock) {
+  std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("GMT"));
+
   std::string created_at = CreatePolicyTimestamp("1 Jan 2018 15:00");
   base::Value override = base::Value(base::Value::Type::DICTIONARY);
   override.SetKey("action", base::Value("LOCK"));
@@ -510,7 +523,7 @@
   base::Time time_one = TimeFromString("Mon, 1 Jan 2018 15:05");
   State state_one =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(0), time_one,
-               time_one, base::nullopt);
+               time_one, timezone.get(), base::nullopt);
 
   // Check that the device is locked until next morning.
   State expected_state_one;
@@ -529,8 +542,12 @@
 // Test GetState when a overridden time window limit has been updated, so the
 // override should not be aplicable anymore.
 TEST_F(UsageTimeLimitProcessorTest, GetStateUpdateUnlockedTimeWindowLimit) {
+  std::unique_ptr<icu::TimeZone> timezone(
+      icu::TimeZone::createTimeZone("GMT+0800"));
+
   // Setup time window limit.
-  std::string last_updated = CreatePolicyTimestamp("Mon, 1 Jan 2018 8:00");
+  std::string last_updated =
+      CreatePolicyTimestamp("Mon, 1 Jan 2018 8:00 GMT+0800");
   base::Value monday_time_limit =
       CreateTimeWindow(base::Value("MONDAY"), CreateTime(18, 0),
                        CreateTime(7, 30), base::Value(last_updated));
@@ -542,7 +559,8 @@
   time_window_limit.SetKey("entries", std::move(window_limit_entries));
 
   // Setup override.
-  std::string created_at = CreatePolicyTimestamp("Mon, 1 Jan 2018 18:30");
+  std::string created_at =
+      CreatePolicyTimestamp("Mon, 1 Jan 2018 18:30 GMT+0800");
   base::Value override = base::Value(base::Value::Type::DICTIONARY);
   override.SetKey("action", base::Value("UNLOCK"));
   override.SetKey("created_at_millis", base::Value(created_at));
@@ -558,24 +576,25 @@
       base::DictionaryValue::From(std::move(time_limit));
 
   // Check that the override is invalidating the time window limit.
-  base::Time time_one = TimeFromString("Mon, 1 Jan 2018 18:35");
+  base::Time time_one = TimeFromString("Mon, 1 Jan 2018 18:35 GMT+0800");
   State state_one =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
-               time_one, time_one, base::nullopt);
+               time_one, time_one, timezone.get(), base::nullopt);
 
   State expected_state_one;
   expected_state_one.is_locked = false;
   expected_state_one.active_policy = ActivePolicies::kOverride;
   expected_state_one.is_time_usage_limit_enabled = false;
   expected_state_one.next_state_change_time =
-      TimeFromString("Mon, 8 Jan 2018 18:00");
+      TimeFromString("Mon, 8 Jan 2018 18:00 GMT+0800");
   expected_state_one.next_state_active_policy = ActivePolicies::kFixedLimit;
   expected_state_one.last_state_changed = base::Time();
 
   AssertEqState(expected_state_one, state_one);
 
   // Change time window limit
-  std::string last_updated_two = CreatePolicyTimestamp("Mon, 1 Jan 2018 19:00");
+  std::string last_updated_two =
+      CreatePolicyTimestamp("Mon, 1 Jan 2018 19:00 GMT+0800");
   base::Value monday_time_limit_two =
       CreateTimeWindow(base::Value("MONDAY"), CreateTime(18, 0),
                        CreateTime(8, 0), base::Value(last_updated_two));
@@ -588,19 +607,20 @@
                                 std::move(time_window_limit_two));
 
   // Check that the new time window limit is enforced.
-  base::Time time_two = TimeFromString("Mon, 1 Jan 2018 19:10");
+  base::Time time_two = TimeFromString("Mon, 1 Jan 2018 19:10 GMT+0800");
   State state_two =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(120),
-               time_two, time_two, state_one);
+               time_two, time_two, timezone.get(), state_one);
 
   State expected_state_two;
   expected_state_two.is_locked = true;
   expected_state_two.active_policy = ActivePolicies::kFixedLimit;
   expected_state_two.is_time_usage_limit_enabled = false;
   expected_state_two.next_state_change_time =
-      TimeFromString("Tue, 2 Jan 2018 8:00");
+      TimeFromString("Tue, 2 Jan 2018 8:00 GMT+0800");
   expected_state_two.next_state_active_policy = ActivePolicies::kNoActivePolicy;
-  expected_state_two.next_unlock_time = TimeFromString("Tue, 2 Jan 2018 8:00");
+  expected_state_two.next_unlock_time =
+      TimeFromString("Tue, 2 Jan 2018 8:00 GMT+0800");
   expected_state_two.last_state_changed = time_two;
 
   AssertEqState(expected_state_two, state_two);
@@ -609,8 +629,10 @@
 // Make sure that the override will only affect policies that started being
 // enforced before it was created.
 TEST_F(UsageTimeLimitProcessorTest, GetStateOverrideTimeWindowLimitOnly) {
+  std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("PST"));
+
   // Setup time window limit.
-  std::string last_updated = CreatePolicyTimestamp("1 Jan 2018 8:00");
+  std::string last_updated = CreatePolicyTimestamp("1 Jan 2018 8:00 PST");
   base::Value monday_time_limit =
       CreateTimeWindow(base::Value("MONDAY"), CreateTime(21, 0),
                        CreateTime(10, 0), base::Value(last_updated));
@@ -630,7 +652,7 @@
   time_usage_limit.SetKey("reset_at", CreateTime(8, 0));
 
   // Setup override.
-  std::string created_at = CreatePolicyTimestamp("Mon, 1 Jan 2018 22:00");
+  std::string created_at = CreatePolicyTimestamp("Mon, 1 Jan 2018 22:00 PST");
   base::Value override = base::Value(base::Value::Type::DICTIONARY);
   override.SetKey("action", base::Value("UNLOCK"));
   override.SetKey("created_at_millis", base::Value(created_at));
@@ -649,10 +671,10 @@
 
   // Check that the override is unlocking the device that should be locked with
   // time window limit.
-  base::Time time_one = TimeFromString("Mon, 1 Jan 2018 22:10");
+  base::Time time_one = TimeFromString("Mon, 1 Jan 2018 22:10 PST");
   State state_one =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(40),
-               time_one, time_one, base::nullopt);
+               time_one, time_one, timezone.get(), base::nullopt);
 
   State expected_state_one;
   expected_state_one.is_locked = false;
@@ -660,7 +682,7 @@
   expected_state_one.is_time_usage_limit_enabled = true;
   expected_state_one.remaining_usage = base::TimeDelta::FromMinutes(20);
   expected_state_one.next_state_change_time =
-      TimeFromString("Mon, 1 Jan 2018 22:30");
+      TimeFromString("Mon, 1 Jan 2018 22:30 PST");
   expected_state_one.next_state_active_policy = ActivePolicies::kUsageLimit;
   expected_state_one.last_state_changed = base::Time();
 
@@ -669,10 +691,10 @@
   // Check that the override didn't unlock the device when the time usage limit
   // started, and that it will be locked until the time usage limit reset time,
   // and not when the time window limit ends.
-  base::Time time_two = TimeFromString("Mon, 1 Jan 2018 22:30");
+  base::Time time_two = TimeFromString("Mon, 1 Jan 2018 22:30 PST");
   State state_two =
       GetState(time_limit_dictionary, base::TimeDelta::FromMinutes(60),
-               time_two, time_two, state_one);
+               time_two, time_two, timezone.get(), state_one);
 
   State expected_state_two;
   expected_state_two.is_locked = true;
@@ -681,9 +703,10 @@
   expected_state_two.remaining_usage = base::TimeDelta::FromMinutes(0);
   expected_state_two.time_usage_limit_started = time_two;
   expected_state_two.next_state_change_time =
-      TimeFromString("Tue, 2 Jan 2018 8:00");
+      TimeFromString("Tue, 2 Jan 2018 8:00 PST");
   expected_state_two.next_state_active_policy = ActivePolicies::kNoActivePolicy;
-  expected_state_two.next_unlock_time = TimeFromString("Tue, 2 Jan 2018 8:00");
+  expected_state_two.next_unlock_time =
+      TimeFromString("Tue, 2 Jan 2018 8:00 PST");
   expected_state_two.last_state_changed = time_two;
 
   AssertEqState(expected_state_two, state_two);
@@ -691,6 +714,8 @@
 
 // Test GetExpectedResetTime with an empty policy.
 TEST_F(UsageTimeLimitProcessorTest, GetExpectedResetTimeWithEmptyPolicy) {
+  std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("GMT"));
+
   // Setup policy.
   std::unique_ptr<base::Value> time_limit =
       std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
@@ -698,13 +723,16 @@
       base::DictionaryValue::From(std::move(time_limit));
 
   base::Time time_one = TimeFromString("Mon, 1 Jan 2018 22:00");
-  base::Time reset_time = GetExpectedResetTime(time_limit_dictionary, time_one);
+  base::Time reset_time =
+      GetExpectedResetTime(time_limit_dictionary, time_one, timezone.get());
 
   ASSERT_EQ(reset_time, TimeFromString("Tue, 2 Jan 2018 0:00"));
 }
 
 // Test GetExpectedResetTime with a custom time usage limit reset time.
 TEST_F(UsageTimeLimitProcessorTest, GetExpectedResetTimeWithCustomPolicy) {
+  std::unique_ptr<icu::TimeZone> timezone(icu::TimeZone::createTimeZone("EST"));
+
   // Setup time usage limit.
   base::Value time_usage_limit = base::Value(base::Value::Type::DICTIONARY);
   time_usage_limit.SetKey("reset_at", CreateTime(8, 0));
@@ -717,18 +745,18 @@
       base::DictionaryValue::From(std::move(time_limit));
 
   // Check that it resets in the same day.
-  base::Time time_one = TimeFromString("Tue, 2 Jan 2018 6:00");
+  base::Time time_one = TimeFromString("Tue, 2 Jan 2018 6:00 EST");
   base::Time reset_time_one =
-      GetExpectedResetTime(time_limit_dictionary, time_one);
+      GetExpectedResetTime(time_limit_dictionary, time_one, timezone.get());
 
-  ASSERT_EQ(reset_time_one, TimeFromString("Tue, 2 Jan 2018 8:00"));
+  ASSERT_EQ(reset_time_one, TimeFromString("Tue, 2 Jan 2018 8:00 EST"));
 
   // Checks that it resets on the following day.
-  base::Time time_two = TimeFromString("Tue, 2 Jan 2018 10:00");
+  base::Time time_two = TimeFromString("Tue, 2 Jan 2018 10:00 EST");
   base::Time reset_time_two =
-      GetExpectedResetTime(time_limit_dictionary, time_two);
+      GetExpectedResetTime(time_limit_dictionary, time_two, timezone.get());
 
-  ASSERT_EQ(reset_time_two, TimeFromString("Wed, 3 Jan 2018 8:00"));
+  ASSERT_EQ(reset_time_two, TimeFromString("Wed, 3 Jan 2018 8:00 EST"));
 }
 
 }  // namespace usage_time_limit