trentrichardson / jQuery-Timepicker-Addon

Adds a timepicker to jQueryUI Datepicker
http://trentrichardson.com/examples/timepicker/
MIT License
2.66k stars 1.05k forks source link

Issue with daylight saving time #330

Open juicedM3 opened 12 years ago

juicedM3 commented 12 years ago

Background: We have a RoR application that supports many clients across the US. The application timezone is set to UTC and all times are stored in UTC. When we go to display or edit product, we convert the times to the appropriate timezone so that the user doesn't have to do any timezone calculations. We added the timepicker-addon so that we could give administrators a user friendly interface to modifying datetimes.

Given: We have products that have a valid start and stop selling dates. The start/stop times are set as follows:

We initialize the datetimepicker using the following parameters:

  $('#product_start_time').datetimepicker({
        ampm: true,
        timeFormat: 'h:mm TT z',
        setDate: new Date("<%= start_time %>")
  });

Everything works great up to this point. However, say they want to extend the product's stop time to June 1st, 2012. We change the field accordingly but the timezone doesn't change. datetimepicker will return a stop time of: 06/01/2012 12:00 AM -0800. It should return 06/01/2012 12:00 AM -0700 which gives us 6/1/2012 12:00:00 AM PDT. A time of 6/01/2012 12:00 AM -0800 gives us 6/1/2012 1:00:00 AM PDT.

If I'm doing anything wrong, please let me know or if there's anyway to work around this. Thanks!

Additional Info:

timepicker: v0.9.9 (briefly tried 0.9.8 & 1.0.0) OS: MacOS X 10.7.3 Browser: Firefox 10.0.2 & Chrome 17.0.963.56 rails: 3.1.3 ruby 1.8.7

juicedM3 commented 12 years ago

If I'm not doing anything wrong, here's a potential patch. I doubt it covers all scenarios and it assumes the timezone format is +/-0000. The adjustment calculation feels dirty too.

Index: jquery-ui-timepicker-addon.js
===================================================================
--- jquery-ui-timepicker-addon.js   (revision 3569)
+++ jquery-ui-timepicker-addon.js   (working copy)
@@ -63,6 +63,7 @@
        second: 0,
        millisec: 0,
        timezone: '+0000',
+       pdt: null, // previous date; to help track for changes in DST
        hourMin: 0,
        minuteMin: 0,
        secondMin: 0,
@@ -796,12 +797,14 @@

        var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];

+       timezone = this._adjustTimezoneForDaylightSaving( timezone );
+
        // If the update was done in the input field, the input field should not be updated.
        // If the update was done using the sliders, update the input field.
        var hasChanged = (hour != this.hour || minute != this.minute
@@ -824,8 +827,37 @@
        this.timeDefined = true;
        if (hasChanged) this._updateDateTime();
    },
-    
+
    //########################################################################
+   // adjusts the timezone for daylight saving time.
+   // doesn't handle different TZ formats on +/-0000.
+   //########################################################################
+   _adjustTimezoneForDaylightSaving: function(timezone) {
+     dp_inst = this.inst || dp_inst;
+     var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
+       dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
+       formatCfg = $.datepicker._getFormatConfig(dp_inst),
+       timeAvailable = dt !== null && this.timeDefined;
+     var odt = this.pdt || new Date( dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay );
+     if( this.timezone != undefined && this.timezone != "+0000" ) {
+       if( -dt.getTimezoneOffset()/60 != -odt.getTimezoneOffset()/60 ) {
+         var newZoneDelta = ( -odt.getTimezoneOffset()/60 ) - ( -dt.getTimezoneOffset()/60 );
+         // calculate the offset.  if you don't remove the leading zero, it won't convert to an int.
+         var offset = parseInt( this.timezone.substring(1).replace( /^0+/, "" ) ) + ( newZoneDelta * 100 );
+         // pad offset to length of 4.
+         if( offset.toString().length != 4 )
+           offset = "0" + offset;
+         // old prefix plus new offset = new timezone
+         timezone = this.timezone.substring(0, 1) + offset;
+         // save off the previously "select" time so it's easy to calculate if we crossed another DST.
+         this.pdt = dt;
+       }
+     }
+  
+     return timezone;
+   },
+   
+   //########################################################################
    // call custom onSelect. 
    // bind to sliders slidestop, and grid click.
    //########################################################################