Bug 1253338 - Add DateUtil.getTimezoneOffsetInMinutes*. r=ahunt
authorMichael Comella <michael.l.comella@gmail.com>
Mon, 09 May 2016 11:41:02 -0700
changeset 321075 cc20a3a1812d0acee33cbb9382f866fe877536c1
parent 321074 0530f8d36de834b921c7c68272e6c0831bedae63
child 321076 cd0c3acb37e051c8d56961784582c060328cdb34
push id9671
push userraliiev@mozilla.com
push dateMon, 06 Jun 2016 20:27:52 +0000
treeherdermozilla-aurora@cea65ca3d0bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersahunt
bugs1253338
milestone49.0a1
Bug 1253338 - Add DateUtil.getTimezoneOffsetInMinutes*. r=ahunt I initially wrote the "ForGivenDate" variant for testing purposes - so I could verify the daylight savings time APIs worked the way I expected them to. However, I ended up using it in my next patch and leaving in the generic "for current time" variant because it seems useful. MozReview-Commit-ID: 4hNGD4uDuOj
mobile/android/base/java/org/mozilla/gecko/util/DateUtil.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestDateUtil.java
--- a/mobile/android/base/java/org/mozilla/gecko/util/DateUtil.java
+++ b/mobile/android/base/java/org/mozilla/gecko/util/DateUtil.java
@@ -5,28 +5,51 @@
  */
 
 package org.mozilla.gecko.util;
 
 import android.support.annotation.NonNull;
 
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
 import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Utilities to help with manipulating Java's dates and calendars.
  */
 public class DateUtil {
     private DateUtil() {}
 
     /**
      * @param date the date to convert to HTTP format
      * @return the date as specified in rfc 1123, e.g. "Tue, 01 Feb 2011 14:00:00 GMT"
      */
     public static String getDateInHTTPFormat(@NonNull final Date date) {
         final DateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.US);
         df.setTimeZone(TimeZone.getTimeZone("GMT"));
         return df.format(date);
     }
+
+    /**
+     * Returns the timezone offset for the current date in minutes. See
+     * {@link #getTimezoneOffsetInMinutesForGivenDate(Calendar)} for more details.
+     */
+    public static int getTimezoneOffsetInMinutes(@NonNull final TimeZone timezone) {
+        return getTimezoneOffsetInMinutesForGivenDate(Calendar.getInstance(timezone));
+    }
+
+    /**
+     * Returns the time zone offset for the given date in minutes. The date makes a difference due to daylight
+     * savings time in some regions. We return minutes because we can accurately represent time zones that are
+     * offset by non-integer hour values, e.g. parts of New Zealand at UTC+12:45.
+     *
+     * @param calendar A calendar with the appropriate time zone & date already set.
+     */
+    public static int getTimezoneOffsetInMinutesForGivenDate(@NonNull final Calendar calendar) {
+        // via Date.getTimezoneOffset deprecated docs (note: it had incorrect order of operations).
+        // Also, we cast to int because we should never overflow here - the max should be GMT+14 = 840.
+        return (int) TimeUnit.MILLISECONDS.toMinutes(calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET));
+    }
 }
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestDateUtil.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/util/TestDateUtil.java
@@ -38,9 +38,52 @@ public class TestDateUtil {
         final TimeZone kst = TimeZone.getTimeZone("Asia/Seoul"); // no daylight savings time.
         final GregorianCalendar calendar = new GregorianCalendar(kst, Locale.US);
         calendar.set(2011, Calendar.FEBRUARY, 1, 14, 0, 0);
         final String expectedDate = "Tue, 01 Feb 2011 05:00:00 GMT";
 
         final String actualDate = DateUtil.getDateInHTTPFormat(calendar.getTime());
         assertEquals("Returned date is expected", expectedDate, actualDate);
     }
+
+    @Test
+    public void testGetTimezoneOffsetInMinutes() {
+        assertEquals("GMT has no offset", 0, DateUtil.getTimezoneOffsetInMinutes(TimeZone.getTimeZone("GMT")));
+
+        // We use custom timezones because they don't have daylight savings time.
+        assertEquals("Offset for GMT-8 is correct",
+                -480, DateUtil.getTimezoneOffsetInMinutes(TimeZone.getTimeZone("GMT-8")));
+        assertEquals("Offset for GMT+12:45 is correct",
+                765, DateUtil.getTimezoneOffsetInMinutes(TimeZone.getTimeZone("GMT+12:45")));
+
+        // We use a non-custom timezone without DST.
+        assertEquals("Offset for KST is correct",
+                540, DateUtil.getTimezoneOffsetInMinutes(TimeZone.getTimeZone("Asia/Seoul")));
+    }
+
+    @Test
+    public void testGetTimezoneOffsetInMinutesForGivenDateNoDaylightSavingsTime() {
+        final TimeZone kst = TimeZone.getTimeZone("Asia/Seoul");
+        final Calendar[] calendars =
+                new Calendar[] { getCalendarForMonth(Calendar.DECEMBER), getCalendarForMonth(Calendar.AUGUST) };
+        for (final Calendar cal : calendars) {
+            cal.setTimeZone(kst);
+            assertEquals("Offset for KST does not change with daylight savings time",
+                    540, DateUtil.getTimezoneOffsetInMinutesForGivenDate(cal));
+        }
+    }
+
+    @Test
+    public void testGetTimezoneOffsetInMinutesForGivenDateDaylightSavingsTime() {
+        final TimeZone pacificTimeZone = TimeZone.getTimeZone("America/Los_Angeles");
+        final Calendar pstCalendar = getCalendarForMonth(Calendar.DECEMBER);
+        final Calendar pdtCalendar = getCalendarForMonth(Calendar.AUGUST);
+        pstCalendar.setTimeZone(pacificTimeZone);
+        pdtCalendar.setTimeZone(pacificTimeZone);
+        assertEquals("Offset for PST is correct", -480, DateUtil.getTimezoneOffsetInMinutesForGivenDate(pstCalendar));
+        assertEquals("Offset for PDT is correct", -420, DateUtil.getTimezoneOffsetInMinutesForGivenDate(pdtCalendar));
+
+    }
+
+    private Calendar getCalendarForMonth(final int month) {
+        return new GregorianCalendar(2000, month, 1);
+    }
 }