You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2009/01/28 08:23:02 UTC

svn commit: r738384 [1/6] - in /myfaces/trinidad/trunk/trinidad-impl/src: main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/ main/javascript/META-INF/adf/jsLibs/ test/resources/org/apache/myfaces/trinidadinternal/renderkit/golden/

Author: matzew
Date: Wed Jan 28 07:23:01 2009
New Revision: 738384

URL: http://svn.apache.org/viewvc?rev=738384&view=rev
Log:
TRINIDAD-1349 - InputDate: wrong date-time selected when browser in summer time and server in winter time

Thanks to Yee-Wah Lee for her patch

Modified:
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/ChooseDateRenderer.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/DateField.js
    myfaces/trinidad/trunk/trinidad-impl/src/test/resources/org/apache/myfaces/trinidadinternal/renderkit/golden/chooseDate-minimal-golden.xml
    myfaces/trinidad/trunk/trinidad-impl/src/test/resources/org/apache/myfaces/trinidadinternal/renderkit/golden/chooseDate-minimalIE-golden.xml
    myfaces/trinidad/trunk/trinidad-impl/src/test/resources/org/apache/myfaces/trinidadinternal/renderkit/golden/chooseDate-minimalIERtl-golden.xml
    myfaces/trinidad/trunk/trinidad-impl/src/test/resources/org/apache/myfaces/trinidadinternal/renderkit/golden/chooseDate-minimalInacc-golden.xml
    myfaces/trinidad/trunk/trinidad-impl/src/test/resources/org/apache/myfaces/trinidadinternal/renderkit/golden/chooseDate-minimalSaf-golden.xml

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/ChooseDateRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/ChooseDateRenderer.java?rev=738384&r1=738383&r2=738384&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/ChooseDateRenderer.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/ChooseDateRenderer.java Wed Jan 28 07:23:01 2009
@@ -24,6 +24,8 @@
 import java.util.Date;
 import java.util.GregorianCalendar;
 
+import java.util.TimeZone;
+
 import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.context.ResponseWriter;
@@ -113,6 +115,15 @@
     if (isInline && !isInlineSupported(arc))
       return;
 
+    // TRINIDAD-1349: The client converter assumes a fixed timezone offset
+    // between the server and itself. It calculates that by passing the
+    // server's timezone offset at the current date-time, as _uixLocaleTZ. 
+    // However, if we are rendering a month in which daylight savings occurs in 
+    // the application timezone, the offset value may be different. In that case
+    // pass the new offset value for the client to use. 
+    TimeZone tz = arc.getLocaleContext().getTimeZone();
+    int baseTZOffsetMinutes = tz.getOffset(System.currentTimeMillis())/(1000*60);
+
     boolean isDesktop = isDesktop(arc);
     ResponseWriter writer = context.getResponseWriter();
     writer.startElement("table", component);
@@ -135,7 +146,7 @@
 
     // get the currently selected Time
     long selectedTime = _getSelectedTime(arc, bean, minTime, maxTime);
-
+    
     // get the id
     String id = getClientId(context, component);
 
@@ -156,19 +167,22 @@
                                                        maxTime,
                                                        selectedTime);
 
-    long displayedTime = displayedCalendar.getTime().getTime();
-
-    // determine the day of this month that is selected
-    int dom = displayedCalendar.get(Calendar.DAY_OF_MONTH);
-
     int firstDOM = _getActualMinimumDayOfMonth(displayedCalendar);
     int lastDOM  = _getActualMaximumDayOfMonth(displayedCalendar);
-
+    
     // determine the the starting times and ending times of the first and
     // last days of the month
-    long firstDOMTime = displayedTime + (firstDOM - dom) * _MILLIS_IN_DAY;
-    long lastDOMTime = displayedTime +
-                       ((long)(lastDOM + 1 - dom)) * _MILLIS_IN_DAY - 1;
+    // Create a copy of the calendar so we don't hammer the current values
+    Calendar calcCal = (Calendar) displayedCalendar.clone();
+    // First is easy
+    calcCal.set(Calendar.DAY_OF_MONTH, firstDOM);
+    long firstDOMTime = calcCal.getTimeInMillis();
+
+    // Last not just the last day of this month, it's the first day of next
+    // month minus a millisecond.
+    calcCal.set(Calendar.DAY_OF_MONTH, lastDOM);
+    calcCal.add(Calendar.DATE, 1);
+    long lastDOMTime = calcCal.getTimeInMillis() - 1;
 
     DateFormatSymbols dateSymbols = _getDateFormatSymbols(arc);
 
@@ -325,7 +339,8 @@
 
     int  currDOM    = firstDOM;
     long currTime   = firstDOMTime;
-    long nextTime   = currTime + _MILLIS_IN_DAY;
+    displayedCalendar.add(Calendar.DAY_OF_MONTH, 1);
+    long nextTime   = displayedCalendar.getTimeInMillis();
     int currLastDOW = firstDOWInMonth + dowCount;
 
     String[] keysAndValues = new String[]{
@@ -376,10 +391,12 @@
           // a date in the date field. (see bug #1482511)
           //
           writer.startElement("a", null);
-          renderSelectDayAttributes(context,
+          renderSelectDayAttributes(arc,
+                                    context,
                                     keysAndValues,
                                     id,
                                     currTime,
+                                    baseTZOffsetMinutes,
                                     isInline,
                                     isDesktop,
                                     destString);
@@ -407,7 +424,8 @@
 
         // move to the next day in time
         currTime = nextTime;
-        nextTime += _MILLIS_IN_DAY;
+        displayedCalendar.add(Calendar.DAY_OF_MONTH, 1);
+        nextTime = displayedCalendar.getTimeInMillis();
       }
 
       if (currDOM <= lastDOM)
@@ -425,6 +443,9 @@
         break;
       }
     } while (true);
+    
+    // Reset the calendar
+    displayedCalendar.set(Calendar.DAY_OF_MONTH, firstDOM);
 
     //
     // output the days from the next month in the last week
@@ -465,18 +486,24 @@
 
 
   protected void renderSelectDayAttributes(
+    RenderingContext arc,
     FacesContext context,
     String[] keysAndValues,
     String id,
     long currTime,
+    int baseTZOffsetMinutes,
     boolean isInline,
     boolean isDesktop,
     String destString
     ) throws IOException
   {
     ResponseWriter writer = context.getResponseWriter();
+    
     if (isDesktop)
     {
+      TimeZone tz = arc.getLocaleContext().getTimeZone();
+      int tzOffsetMinutes = tz.getOffset(currTime)/(1000*60);
+
       StringBuilder clickRef = new StringBuilder(30);
       writer.writeURIAttribute("href", "#", null);
 
@@ -502,6 +529,8 @@
       }
 
       clickRef.append(currTime);
+      if (tzOffsetMinutes != baseTZOffsetMinutes)
+        clickRef.append (", " + tzOffsetMinutes);
       clickRef.append(')');
       writer.writeAttribute("onclick", clickRef, null);
     }
@@ -817,7 +846,7 @@
       currentTime.set(Calendar.MONTH, currMonth);
 
 
-      String value = String.valueOf(currentTime.getTime().getTime() - offset);
+      String value = String.valueOf(currentTime.getTimeInMillis() - offset);
       writer.writeAttribute("value", value, null );
 
       writer.writeText(months[currMonth], null);
@@ -982,7 +1011,7 @@
     currentTime.set(Calendar.YEAR, year);
 
     writer.writeAttribute("value",
-                          String.valueOf(currentTime.getTime().getTime()),
+                          String.valueOf(currentTime.getTimeInMillis()),
               null);
 
     // output the label for the after item

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/DateField.js
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/DateField.js?rev=738384&r1=738383&r2=738384&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/DateField.js (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/javascript/META-INF/adf/jsLibs/DateField.js Wed Jan 28 07:23:01 2009
@@ -20,24 +20,45 @@
 // _dfsv(): Date Field Set Value function.  
 function _dfsv(
   dateField,
-  newValue
+  newValue,
+  serverOffsetInMins
   )
 {
   // Make sure we have valid values
   if ((dateField == (void 0)) || (newValue == (void 0)))
     return;
+
+  // Hold on to the initial date value
+  var baseDate = new Date(newValue);
+  
+  // We need to compare the time zone that is on the client with the time
+  // zone that came from the localeContext on the server and adjust if
+  // necessary
+  var tzd = _getLocaleTimeZoneDifference2(baseDate, serverOffsetInMins);
+    
+  // _getTimePortion below expects that newValue is time zero (midnight) on the given
+  // day. The code changes to handle the new Daylight Savings Time dates (as of
+  // 2007, DST was extended by a couple of weeks) broke the calculations for
+  // 2006 and prior on Windows. This yields an off-by-one-hour problem on the
+  // day after the DST switch. Here we adjust for that.
+   newValue = _dfGetMidnight(newValue + tzd);  
     
   // Add back in the time
   // offset,since we don't want to overwrite the user's time when 
   // they pick a new date from the calendar. 
   newValue += _getTimePortion(dateField);
-  
-  // compare the time zone that is on the client with the time zone that
-  // came from the localeContext on the server and adjust if necessary.
-  // bug 3167883
-  newValue += _getLocaleTimeZoneDifference2();
 
   var newDate = new Date(newValue);
+  
+  // If the date used for the time-of-day calculation is different from the
+  // timezone (daylight savings or standard time) of the base date, then we'll
+  // be off by an hour. Here we adjust for that hour. Note this is different
+  // from the check in the _getTimePortion method, that only checks for a
+  // timezone change on the particular day used for the calculation. Both
+  // checks are needed.
+  var tzDiffOffset = _getTimezoneDiff(baseDate, newDate);
+  if (tzDiffOffset != 0)
+    newDate = new Date (newValue - tzDiffOffset);
 
   //
   // get the format to use to format the result
@@ -139,7 +160,11 @@
       dateField = _savedField1879034;
     }
 
-    _dfsv(dateField, newValue);
+    var serverOffset = closingWindow.serverOffsetInMins;
+    if (serverOffset != (void 0))
+      _dfsv(dateField, newValue, serverOffset);
+    else
+      _dfsv(dateField, newValue);    
   }
 }
 
@@ -227,8 +252,10 @@
   }
   
   // add the current time in Millis since 1970
-  destination += "&value=" + oldValue.getTime();
+  var timeval = oldValue.getTime() - _getLocaleTimeZoneDifference(oldValue);
+  destination += "&value=" + timeval
   
+    
   // add the locale
   destination += "&loc=" + _locale;
     
@@ -329,8 +356,14 @@
                                     oldValue.getDate());
       
   // get only the time portion of the date in the field.
+  var diff = oldValue-oldValueDateOnly;
+
+  // If the timezone changed today, subtract out the offset.
+  // This will only happen on the day that we switch from standard time to
+  // daylight savings time, or back again.
+  diff -= _getTimezoneDiff(oldValue, oldValueDateOnly);
 
-  return oldValue-oldValueDateOnly;
+  return diff;
 }
 
 /**
@@ -340,22 +373,60 @@
  * the date field to use the timezone set on the locale context on the 
  * server instead of the timezone we get from javascript's getTimezoneOffset.
  * see bug 3167883
+ * TRINIDAD-1349:_uixLocaleTZ stores the timezone offset of the server at
+ * the time the page was displayed (Current time), and currentDateTZOffset
+ * is the timezone offset of client at the current time as well. However,
+ * the timezone offsets for both client and server can differ for the
+ * date that was picked due to daylight savings rules. For example, the
+ * current time is 3 Dec 2008 and the server is in PST (UTC -8) and 
+ * client is in Perth (AWDT, UTC + 9) so the difference is 17h. But if 
+ * the user picks Apr 25, the server is actually in PDT then (UTC-7) and
+ * the client in AWST (UTC +8) so the difference is actually 15h. The original 
+ * code would subtract 17h, which would cause the resulting date to move
+ * to the previous day. * 
  */
-function _getLocaleTimeZoneDifference2()
+function _getLocaleTimeZoneDifference2(clientDate, serverOffset)
 {
-  var currentDate = new Date();
   // timeZoneOffset in javascript appears to give
   // the wrong sign, so I am switching it.
   // the timeZoneOffset is in minutes.
-  var currentDateTzOffset = currentDate.getTimezoneOffset() * -1;
+  var clientOffset = clientDate.getTimezoneOffset() * -1;
   var tzOffsetDiff = 0;
-  if (_uixLocaleTZ)
-    tzOffsetDiff = (_uixLocaleTZ - currentDateTzOffset)*60*1000;
+  if (serverOffset != void(0))
+    tzOffsetDiff = (serverOffset - clientOffset)*60*1000;
+  else if (_uixLocaleTZ != (void(0)))
+    tzOffsetDiff = (_uixLocaleTZ - clientOffset)*60*1000;
   
   return tzOffsetDiff;
 }
 
 /**
+ * Just find the difference in millis between the timezone of two dates
+ */
+function _getTimezoneDiff(oldDate, newDate)
+{
+  return (oldDate.getTimezoneOffset() - newDate.getTimezoneOffset()) * 60000;
+}
+
+/**
+ * _dfGetMidnight: Date Field Get Midnight
+ *                 Returns the date val for midnight on the date given by the
+ *                 input dateVal.
+ */
+function _dfGetMidnight(dateVal)
+{
+  var baseDate = new Date(dateVal);
+  // Just zero out the date
+  baseDate.setHours(0);
+  baseDate.setMinutes(0);
+  baseDate.setSeconds(0);
+  baseDate.setMilliseconds(0);
+
+  // and return the corresponding date value
+  return baseDate.getTime();
+}
+
+/**
  * _dbb(): Date Field Blur handler
  *
  * Parameters:
@@ -420,7 +491,7 @@
  * - source is the id of the calendar
  * - value is the date value to select
  */
-function _calsd(source, value)
+function _calsd(source, value, serverOffsetInMins)
 {
 
   if (window._calActiveDateFields != (void 0))
@@ -428,7 +499,7 @@
     var dateField = window._calActiveDateFields[source];
 
     if (dateField)
-      _dfsv(dateField, value);
+      _dfsv(dateField, value, serverOffsetInMins);
   }
 
   return false;
@@ -462,18 +533,20 @@
   return false;
 }
 
-function _selectDate(dateTime)
+function _selectDate(dateTime, serverOffsetInMins)
 {
   var dialog = parent.TrPopupDialog.getInstance();
   if (dialog)
   {
     dialog.returnValue = dateTime;
+    dialog.serverOffsetInMins = serverOffsetInMins;
     //TODO - Need Cleaner way to close dialogs using via getInstance()
     parent.TrPopupDialog._returnFromDialog();
   }
   else
   {
     top.returnValue = dateTime;
+    top.serverOffsetInMins = serverOffsetInMins;    
     top._unloadADFDialog(window.event);
     top.close();
   }