Bug 926777 - B2G system time: |time.timezone| should save the UTC value with the correct sign. r=gene
authorShao Hang Kao <skao@mozilla.com>
Tue, 15 Oct 2013 16:43:53 +0800
changeset 165020 e2b2297d5c1e03619f19b92fc08b236411f7a1e0
parent 165019 7b73d5834399753220e5ee70d7eea7e36d5b4ac6
child 165021 b5601b5421ca7a32add10c9daef57a9e097c08a7
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgene
bugs926777
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 926777 - B2G system time: |time.timezone| should save the UTC value with the correct sign. r=gene
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/TimeZoneSettingObserver.cpp
hal/Hal.cpp
hal/Hal.h
hal/fallback/FallbackTime.cpp
hal/gonk/GonkHal.cpp
hal/sandbox/PHal.ipdl
hal/sandbox/SandboxHal.cpp
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -1923,24 +1923,24 @@ RadioInterface.prototype = {
   },
 
   /**
    * Set the system time zone by NITZ.
    */
   setTimezoneByNitz: function setTimezoneByNitz(message) {
     // To set the sytem timezone. Note that we need to convert the time zone
     // value to a UTC repesentation string in the format of "UTC(+/-)hh:mm".
-    // Ex, time zone -480 is "UTC-08:00"; time zone 630 is "UTC+10:30".
+    // Ex, time zone -480 is "UTC+08:00"; time zone 630 is "UTC-10:30".
     //
     // We can unapply the DST correction if we want the raw time zone offset:
     // message.networkTimeZoneInMinutes -= message.networkDSTInMinutes;
     if (message.networkTimeZoneInMinutes != (new Date()).getTimezoneOffset()) {
       let absTimeZoneInMinutes = Math.abs(message.networkTimeZoneInMinutes);
       let timeZoneStr = "UTC";
-      timeZoneStr += (message.networkTimeZoneInMinutes >= 0 ? "+" : "-");
+      timeZoneStr += (message.networkTimeZoneInMinutes > 0 ? "-" : "+");
       timeZoneStr += ("0" + Math.floor(absTimeZoneInMinutes / 60)).slice(-2);
       timeZoneStr += ":";
       timeZoneStr += ("0" + absTimeZoneInMinutes % 60).slice(-2);
       gSettingsService.createLock().set("time.timezone", timeZoneStr, null);
     }
   },
 
   /**
--- a/dom/system/gonk/TimeZoneSettingObserver.cpp
+++ b/dom/system/gonk/TimeZoneSettingObserver.cpp
@@ -16,16 +16,17 @@
 #include "nsISettingsService.h"
 #include "nsJSUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "TimeZoneSettingObserver.h"
 #include "xpcpublic.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
+#include "nsPrintfCString.h"
 
 #undef LOG
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Time Zone Setting" , ## args)
 #define ERR(args...)  __android_log_print(ANDROID_LOG_ERROR, "Time Zone Setting" , ## args)
 
 #define TIME_TIMEZONE       "time.timezone"
 #define MOZSETTINGS_CHANGED "mozsettings-changed"
 
@@ -56,19 +57,28 @@ public:
     JSContext *cx = nsContentUtils::GetCurrentJSContext();
     NS_ENSURE_TRUE(cx, NS_OK);
 
     // If we don't have time.timezone value in the settings, we need
     // to initialize the settings based on the current system timezone
     // to make settings consistent with system. This usually happens
     // at the very first boot. After that, settings must have a value.
     if (aResult.isNull()) {
-      // Get the current system timezone and convert it to a JS string.
-      nsCString curTimezone = hal::GetTimezone();
-      NS_ConvertUTF8toUTF16 utf16Str(curTimezone);
+      // Get the current system time zone offset. Note that we need to
+      // convert the value to a UTC representation in the format of
+      // "UTC{+,-}hh:mm", so that the Gaia end can know how to interpret.
+      // E.g., -480 is "UTC+08:00"; 630 is "UTC-10:30".
+      int32_t timeZoneOffset = hal::GetTimezoneOffset();
+      nsPrintfCString curTimeZone("UTC%+03d:%02d",
+                                  -timeZoneOffset / 60,
+                                  abs(timeZoneOffset) % 60);
+
+      // Convert it to a JS string.
+      NS_ConvertUTF8toUTF16 utf16Str(curTimeZone);
+
       JSString *jsStr = JS_NewUCStringCopyN(cx, utf16Str.get(), utf16Str.Length());
 
       // Set the settings based on the current system timezone.
       nsCOMPtr<nsISettingsServiceLock> lock;
       nsCOMPtr<nsISettingsService> settingsService =
         do_GetService("@mozilla.org/settingsService;1");
       if (!settingsService) {
         ERR("Failed to get settingsLock service!");
@@ -122,23 +132,36 @@ TimeZoneSettingObserver::TimeZoneSetting
   settingsService->CreateLock(getter_AddRefs(lock));
   nsCOMPtr<nsISettingsServiceCallback> callback = new TimeZoneSettingCb();
   lock->Get(TIME_TIMEZONE, callback);
 }
 
 nsresult TimeZoneSettingObserver::SetTimeZone(const JS::Value &aValue, JSContext *aContext)
 {
   // Convert the JS value to a nsCString type.
+  // The value should be a JS string like "America/Chicago" or "UTC-05:00".
   nsDependentJSString valueStr;
   if (!valueStr.init(aContext, aValue.toString())) {
     ERR("Failed to convert JS value to nsCString");
     return NS_ERROR_FAILURE;
   }
   NS_ConvertUTF16toUTF8 newTimezone(valueStr);
 
+  // Hal expects opposite sign from general notations,
+  // so we need to flip it.
+  if (newTimezone.Find(NS_LITERAL_CSTRING("UTC+")) == 0) {
+    if (!newTimezone.SetCharAt('-', 3)) {
+      return NS_ERROR_FAILURE;
+    }
+  } else if (newTimezone.Find(NS_LITERAL_CSTRING("UTC-")) == 0) {
+    if (!newTimezone.SetCharAt('+', 3)) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+
   // Set the timezone only when the system timezone is not identical.
   nsCString curTimezone = hal::GetTimezone();
   if (!curTimezone.Equals(newTimezone)) {
     hal::SetTimezone(newTimezone);
   }
 
   return NS_OK;
 }
@@ -161,17 +184,18 @@ TimeZoneSettingObserver::Observe(nsISupp
   if (strcmp(aTopic, MOZSETTINGS_CHANGED) != 0) {
     return NS_OK;
   }
 
   // Note that this function gets called for any and all settings changes,
   // so we need to carefully check if we have the one we're interested in.
   //
   // The string that we're interested in will be a JSON string that looks like:
-  // {"key":"time.timezone","value":"America/Chicago"}
+  // {"key":"time.timezone","value":"America/Chicago"} or
+  // {"key":"time.timezone","value":"UTC-05:00"}
 
   AutoSafeJSContext cx;
 
   // Parse the JSON value.
   nsDependentString dataStr(aData);
   JS::Rooted<JS::Value> val(cx);
   if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) ||
       !val.isObject()) {
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -498,16 +498,23 @@ AdjustSystemClock(int64_t aDeltaMillisec
 
 void 
 SetTimezone(const nsCString& aTimezoneSpec)
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(SetTimezone(aTimezoneSpec));
 }
 
+int32_t
+GetTimezoneOffset()
+{
+  AssertMainThread();
+  RETURN_PROXY_IF_SANDBOXED(GetTimezoneOffset(), 0);
+}
+
 nsCString
 GetTimezone()
 {
   AssertMainThread();
   RETURN_PROXY_IF_SANDBOXED(GetTimezone(), nsCString(""));
 }
 
 void
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -255,16 +255,22 @@ void SetTimezone(const nsCString& aTimez
 
 /**
  * Get timezone
  * http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
  */
 nsCString GetTimezone();
 
 /**
+ * Get timezone offset
+ * returns the timezone offset relative to UTC in minutes (DST effect included)
+ */
+int32_t GetTimezoneOffset();
+
+/**
  * Register observer for system clock changed notification.
  * @param aObserver The observer that should be added.
  */
 void RegisterSystemClockChangeObserver(
   hal::SystemClockChangeObserver* aObserver);
 
 /**
  * Unregister the observer for system clock changed.
--- a/hal/fallback/FallbackTime.cpp
+++ b/hal/fallback/FallbackTime.cpp
@@ -19,16 +19,22 @@ SetTimezone(const nsCString& aTimezoneSp
 {}
 
 nsCString
 GetTimezone()
 {
   return EmptyCString();
 }
 
+int32_t
+GetTimezoneOffset()
+{
+  return 0;
+}
+
 void
 EnableSystemClockChangeNotifications()
 {
 }
 
 void
 DisableSystemClockChangeNotifications()
 {
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -737,17 +737,17 @@ AdjustSystemClock(int64_t aDeltaMillisec
 
   if (ioctl(fd, ANDROID_ALARM_SET_RTC, &now) < 0) {
     HAL_LOG(("ANDROID_ALARM_SET_RTC failed: %s", strerror(errno)));
   }
 
   hal::NotifySystemClockChange(aDeltaMilliseconds);
 }
 
-static int32_t
+int32_t
 GetTimezoneOffset()
 {
   PRExplodedTime prTime;
   PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prTime);
 
   // Daylight saving time (DST) will be taken into account.
   int32_t offset = prTime.tm_params.tp_gmt_offset;
   offset += prTime.tm_params.tp_dst_offset;
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -138,16 +138,18 @@ parent:
 
     sync GetScreenBrightness() returns (double brightness);
     SetScreenBrightness(double brightness);
 
     AdjustSystemClock(int64_t aDeltaMilliseconds);
     SetTimezone(nsCString aTimezoneSpec);
     sync GetTimezone()
       returns (nsCString aTimezoneSpec);
+    sync GetTimezoneOffset()
+      returns (int32_t aTimezoneOffset);
     EnableSystemClockChangeNotifications();
     DisableSystemClockChangeNotifications();
     EnableSystemTimezoneChangeNotifications();
     DisableSystemTimezoneChangeNotifications();
 
     sync SetLight(LightType light, LightConfiguration aConfig)
       returns (bool status);
     sync GetLight(LightType light)
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -207,16 +207,24 @@ SetTimezone(const nsCString& aTimezoneSp
 nsCString
 GetTimezone()
 {
   nsCString timezone;
   Hal()->SendGetTimezone(&timezone);
   return timezone;
 }
 
+int32_t
+GetTimezoneOffset()
+{
+  int32_t timezoneOffset;
+  Hal()->SendGetTimezoneOffset(&timezoneOffset);
+  return timezoneOffset;
+}
+
 void
 EnableSystemClockChangeNotifications()
 {
   Hal()->SendEnableSystemClockChangeNotifications();
 }
 
 void
 DisableSystemClockChangeNotifications()
@@ -680,16 +688,26 @@ public:
     if (!AssertAppProcessPermission(this, "time")) {
       return false;
     }
     *aTimezoneSpec = hal::GetTimezone();
     return true;
   }
 
   virtual bool
+  RecvGetTimezoneOffset(int32_t *aTimezoneOffset) MOZ_OVERRIDE
+  {
+    if (!AssertAppProcessPermission(this, "time")) {
+      return false;
+    }
+    *aTimezoneOffset = hal::GetTimezoneOffset();
+    return true;
+  }
+
+  virtual bool
   RecvEnableSystemClockChangeNotifications() MOZ_OVERRIDE
   {
     hal::RegisterSystemClockChangeObserver(this);
     return true;
   }
 
   virtual bool
   RecvDisableSystemClockChangeNotifications() MOZ_OVERRIDE