Revision: 6676
Author: r...@google.com
Date: Wed Nov  4 14:08:43 2009
Log: Merge tr...@6674 into the branch
Fix dates that fall into non-existent time ranges due to daylight savings
svn merge --ignore-ancestry -c 6674  
https://google-web-toolkit.googlecode.com/svn/trunk/ .


http://code.google.com/p/google-web-toolkit/source/detail?r=6676

Modified:
  /releases/2.0/branch-info.txt
  /releases/2.0/user/super/com/google/gwt/emul/java/util/Date.java
  /releases/2.0/user/test/com/google/gwt/emultest/java/util/DateTest.java

=======================================
--- /releases/2.0/branch-info.txt       Wed Nov  4 13:43:21 2009
+++ /releases/2.0/branch-info.txt       Wed Nov  4 14:08:43 2009
@@ -307,3 +307,7 @@
    Hosted mode fixes for SingleJsoImpl
    svn merge --ignore-ancestry -c6669,6670  
https://google-web-toolkit.googlecode.com/svn/trunk/ .

+tr...@6674 was merged into the branch
+  Fix dates that fall into non-existent time ranges due to daylight savings
+  svn merge --ignore-ancestry -c 6674  
https://google-web-toolkit.googlecode.com/svn/trunk/ .
+
=======================================
--- /releases/2.0/user/super/com/google/gwt/emul/java/util/Date.java    Thu  
Aug 13 12:43:26 2009
+++ /releases/2.0/user/super/com/google/gwt/emul/java/util/Date.java    Wed  
Nov  4 14:08:43 2009
@@ -105,7 +105,7 @@
        int min, int sec) /*-{
      return Date.UTC(year + 1900, month, date, hrs, min, sec);
    }-*/;
-
+
    /**
     * JavaScript Date instance.
     */
@@ -206,7 +206,7 @@

    public native int getYear() /*-{
      th...@java.util.date::checkJsDate()();
-    return th...@java.util.date::jsdate.getFullYear()-1900;
+    return th...@java.util.date::jsdate.getFullYear() - 1900;
    }-*/;

    @Override
@@ -216,27 +216,36 @@

    public native void setDate(int date) /*-{
      th...@java.util.date::checkJsDate()();
+    var hours = th...@java.util.date::jsdate.getHours()
      th...@java.util.date::jsdate.setDate(date);
+    th...@java.util.date::fixDaylightSavings(I)(hours);
    }-*/;

    public native void setHours(int hours) /*-{
      th...@java.util.date::checkJsDate()();
      th...@java.util.date::jsdate.setHours(hours);
+    th...@java.util.date::fixDaylightSavings(I)(hours);
    }-*/;

    public native void setMinutes(int minutes) /*-{
      th...@java.util.date::checkJsDate()();
+    var hours = th...@java.util.date::jsdate.getHours() + minutes / 60;
      th...@java.util.date::jsdate.setMinutes(minutes);
+    th...@java.util.date::fixDaylightSavings(I)(hours);
    }-*/;

    public native void setMonth(int month) /*-{
      th...@java.util.date::checkJsDate()();
+    var hours = th...@java.util.date::jsdate.getHours();
      th...@java.util.date::jsdate.setMonth(month);
+    th...@java.util.date::fixDaylightSavings(I)(hours);
    }-*/;

    public native void setSeconds(int seconds) /*-{
      th...@java.util.date::checkJsDate()();
+    var hours = th...@java.util.date::jsdate.getHours() + seconds / (60 *  
60);
      th...@java.util.date::jsdate.setSeconds(seconds);
+    th...@java.util.date::fixDaylightSavings(I)(hours);
    }-*/;

    public void setTime(long time) {
@@ -245,7 +254,9 @@

    public native void setYear(int year) /*-{
      th...@java.util.date::checkJsDate()();
+    var hours = th...@java.util.date::jsdate.getHours()
      th...@java.util.date::jsdate.setFullYear(year + 1900);
+    th...@java.util.date::fixDaylightSavings(I)(hours);
    }-*/;

    public native String toGMTString() /*-{
@@ -306,6 +317,57 @@
            + th...@java.util.date::jsdate);
      }
    }-*/;
+
+  /*
+   * Some browsers have the following behavior:
+   *
+   * // Assume a U.S. time zone with daylight savings
+   * // Set a non-existent time: 2:00 am Sunday March 8, 2009
+   * var date = new Date(2009, 2, 8, 2, 0, 0);
+   * var hours = date.getHours(); // returns 1
+   *
+   * The equivalent Java code will return 3. To compensate, we determine  
the
+   * amount of daylight savings adjustment by comparing the time zone  
offsets
+   * for the requested time and a time one day later, and add the  
adjustment to
+   * the hours and minutes of the requested time.
+   */
+
+  /**
+   * Detects if the requested time falls into a non-existent time range  
due to
+   * local time advancing into daylight savings time. If so, push the  
requested
+   * time forward out of the non-existent range.
+   */
+  @SuppressWarnings("unused") // called by JSNI
+  private native void fixDaylightSavings(int hours) /*-{
+    if ((th...@java.util.date::jsdate.getHours() % 24) != (hours % 24)) {
+      // Find the change in time zone offset between the current
+      // time and the same time the following day
+      var d = new Date();
+      d.setTime(th...@java.util.date::jsdate.getTime());
+      var noff = d.getTimezoneOffset();
+      d.setDate(d.getDate() + 1);
+      var loff = d.getTimezoneOffset();
+      var timeDiff = noff - loff;
+
+      // If the time zone offset is changing, advance the hours and
+      // minutes from the initially requested time by the change amount
+      if (timeDiff > 0) {
+        var year = th...@java.util.date::jsdate.getYear() + 1900;
+        var month = th...@java.util.date::jsdate.getMonth();
+        var day = th...@java.util.date::jsdate.getDate();
+        var badHours = th...@java.util.date::jsdate.getHours();
+        var minute = th...@java.util.date::jsdate.getMinutes();
+        var second = th...@java.util.date::jsdate.getSeconds();
+        if (badHours + timeDiff / 60 >= 24) {
+          day++;
+        }
+        var newTime = new Date(year, month, day,
+            hours + timeDiff / 60,
+            minute + timeDiff % 60, second);
+        th...@java.util.date::jsdate.setTime(newTime.getTime());
+      }
+    }
+  }-*/;

    private native double getTime0() /*-{
      th...@java.util.date::checkJsDate()();
@@ -326,6 +388,9 @@
      th...@java.util.date::checkJsDate()();
      th...@java.util.date::jsdate.setFullYear(year + 1900, month, date);
      th...@java.util.date::jsdate.setHours(hrs, min, sec, 0);
+
+    // Set the expected hour.
+    th...@java.util.date::fixDaylightSavings(I)(hrs);
    }-*/;

    private native void setTime0(double time) /*-{
=======================================
--- /releases/2.0/user/test/com/google/gwt/emultest/java/util/DateTest.java     
 
Mon Jun  1 22:59:06 2009
+++ /releases/2.0/user/test/com/google/gwt/emultest/java/util/DateTest.java     
 
Wed Nov  4 14:08:43 2009
@@ -18,6 +18,7 @@
  import com.google.gwt.core.client.GWT;
  import com.google.gwt.junit.client.GWTTestCase;

+import java.util.ArrayList;
  import java.util.Date;

  /**
@@ -638,6 +639,218 @@
      int arg35 = 0;
      long a2 = accum2.UTC(arg30, arg31, arg32, arg33, arg34, arg35);
    }
+
+  // Month and date of days with time shifts
+  private ArrayList<Integer> timeShiftMonth = new ArrayList<Integer>();
+  private ArrayList<Integer> timeShiftDate = new ArrayList<Integer>();
+
+  private boolean containsTimeShift(Date start, int days) {
+    long startTime = start.getTime();
+    Date end = new Date();
+    end.setTime(startTime);
+    end.setDate(start.getDate() + days);
+    long endTime = end.getTime();
+    return (endTime - startTime) != ((long) days * 24 * 60 * 60 * 1000);
+  }
+
+  private void findTimeShift(Date start, int days) {
+    assertTrue(days != 0);
+
+    // Found a shift day
+    if (days == 1) {
+      timeShiftMonth.add(start.getMonth());
+      timeShiftDate.add(start.getDate());
+      return;
+    }
+
+    // Recurse over the first half of the period
+    if (containsTimeShift(start, days / 2)) {
+      findTimeShift(start, days / 2);
+    }
+
+    // Recurse over the second half of the period
+    Date mid = new Date();
+    mid.setTime(start.getTime());
+    mid.setDate(start.getDate() + days / 2);
+    if (containsTimeShift(mid, days - days / 2)) {
+      findTimeShift(mid, days - days / 2);
+    }
+  }
+
+  private void findTimeShifts(int year) {
+    timeShiftMonth.clear();
+    timeShiftDate.clear();
+    Date start = new Date(year - 1900, 0, 1, 12, 0, 0);
+    Date end = new Date(year + 1 - 1900, 0, 1, 12, 0, 0);
+    int days = (int) ((end.getTime() - start.getTime()) /
+        (24 * 60 * 60 * 1000));
+    findTimeShift(start, days);
+  }
+
+  private boolean findClockBackwardTime(int year, int[] monthDayHour) {
+    findTimeShifts(year);
+    int numShifts = timeShiftMonth.size();
+    for (int i = 0; i < numShifts; i++) {
+      int month = timeShiftMonth.get(i);
+      int day = timeShiftDate.get(i);
+
+      long start = new Date(year - 1900, month, day, 0, 30, 0).getTime();
+      long end = new Date(year - 1900, month, day + 1, 23, 30,  
0).getTime();
+      int lastHour = -1;
+      for (long time = start; time < end; time += 60 * 60 * 1000) {
+        Date d = new Date();
+        d.setTime(time);
+        int hour = d.getHours();
+        if (hour == lastHour) {
+          monthDayHour[0] = d.getMonth();
+          monthDayHour[1] = d.getDate();
+          monthDayHour[2] = d.getHours();
+          return true;
+        }
+        lastHour = hour;
+      }
+    }
+
+    return false;
+  }
+
+  private boolean findClockForwardTime(int year, int[] monthDayHour) {
+    findTimeShifts(year);
+    int numShifts = timeShiftMonth.size();
+    for (int i = 0; i < numShifts; i++) {
+      int month = timeShiftMonth.get(i);
+      int startDay = timeShiftDate.get(i);
+
+      for (int day = startDay; day <= startDay + 1; day++) {
+        for (int hour = 0; hour < 24; hour++) {
+          Date d = new Date(year - 1900, month, day, hour, 0, 0);
+          int h = d.getHours();
+          if ((h % 24) == ((hour + 1) % 24)) {
+            monthDayHour[0] = month;
+            monthDayHour[1] = day;
+            monthDayHour[2] = hour;
+            return true;
+          }
+        }
+      }
+    }
+
+    return false;
+  }
+
+  public void testClockBackwardTime() {
+    int[] monthDayHour = new int[3];
+    if (!findClockBackwardTime(2009, monthDayHour)) {
+      return;
+    }
+
+    Date d;
+    int month = monthDayHour[0];
+    int day = monthDayHour[1];
+    int hour = monthDayHour[2];
+
+    // Check that this is the later of the two times having the
+    // same hour:minute:second
+    d = new Date(2009 - 1900, month, day, hour, 30, 0);
+    assertEquals(hour, d.getHours());
+    d.setTime(d.getTime() - 60 * 60 * 1000);
+    assertEquals(hour, d.getHours());
+  }
+
+  public void testClockForwardTime() {
+    int[] monthDayHour = new int[3];
+    if (!findClockForwardTime(2009, monthDayHour)) {
+      return;
+    }
+
+    Date d;
+    int month = monthDayHour[0];
+    int day = monthDayHour[1];
+    int hour = monthDayHour[2];
+
+    d = new Date(2009 - 1900, month, day, hour, 0, 0);
+    assertEquals(hour + 1, d.getHours());
+
+    // Test year change -- assume the previous year changes on a different  
day
+    d = new Date(2008 - 1900, month, day, hour, 0, 0);
+    assertEquals(hour, d.getHours());
+    d.setYear(2009 - 1900);
+    assertEquals(hour + 1, d.getHours());
+
+    // Test month change
+    d = new Date(2009 - 1900, month + 1, day, hour, 0, 0);
+    assertEquals(hour, d.getHours());
+    d.setMonth(month);
+    assertEquals(3, d.getHours());
+
+    // Test day change
+    d = new Date(2009 - 1900, month, day + 1, hour, 0, 0);
+    assertEquals(hour, d.getHours());
+    d.setDate(day);
+    assertEquals(hour + 1, d.getHours());
+
+    // Test hour setting
+    d = new Date(2009 - 1900, month, day, hour + 2, 0, 0);
+    assertEquals(hour + 2, d.getHours());
+    d.setHours(hour);
+    assertEquals(hour + 1, d.getHours());
+
+    // Test changing hour by minutes = +- 60
+    d = new Date(2009 - 1900, month, day, hour + 2, 0, 0);
+    assertEquals(hour + 2, d.getHours());
+    d.setMinutes(-60);
+    assertEquals(hour + 1, d.getHours());
+
+    d = new Date(2009 - 1900, month, day, hour - 1, 0, 0);
+    assertEquals(hour - 1, d.getHours());
+    d.setMinutes(60);
+    assertEquals(hour + 1, d.getHours());
+
+    // Test changing hour by minutes = +- 120
+    d = new Date(2009 - 1900, month, day, hour + 2, 0, 0);
+    assertEquals(hour + 2, d.getHours());
+    d.setMinutes(-120);
+    assertEquals(hour + 1, d.getHours());
+
+    d = new Date(2009 - 1900, month, day, hour - 2, 0, 0);
+    assertEquals(hour - 2, d.getHours());
+    d.setMinutes(120);
+    assertEquals(hour + 1, d.getHours());
+
+    // Test changing hour by seconds = +- 3600
+    d = new Date(2009 - 1900, month, day, hour + 2, 0, 0);
+    assertEquals(hour + 2, d.getHours());
+    d.setSeconds(-3600);
+    assertEquals(hour + 1, d.getHours());
+
+    d = new Date(2009 - 1900, month, day, hour - 1, 0, 0);
+    assertEquals(hour - 1, d.getHours());
+    d.setSeconds(3600);
+    assertEquals(hour + 1, d.getHours());
+
+    // Test changing hour by seconds = +- 7200
+    d = new Date(2009 - 1900, month, day, hour + 2, 0, 0);
+    assertEquals(hour + 2, d.getHours());
+    d.setSeconds(-7200);
+    assertEquals(hour + 1, d.getHours());
+
+    d = new Date(2009 - 1900, month, day, hour - 2, 0, 0);
+    assertEquals(hour - 2, d.getHours());
+    d.setSeconds(7200);
+    assertEquals(hour + 1, d.getHours());
+
+    d = new Date(2009 - 1900, month, day, hour + 2, 0, 0);
+    d.setHours(hour);
+    d.setMinutes(30);
+    assertEquals(hour + 1, d.getHours());
+    assertEquals(30, d.getMinutes());
+
+    d = new Date(2009 - 1900, month, day, hour + 2, 0, 0);
+    d.setMinutes(30);
+    d.setHours(hour);
+    assertEquals(hour + 1, d.getHours());
+    assertEquals(30, d.getMinutes());
+  }

    Date create() {
      return (Date) theDate.clone();

--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---

Reply via email to