Archive for October, 2008

14
Oct

Dealing with Time-Zones in Javascript

Dealing with date-time information is a complex topic in any language, as the nature of date-time information is complicated itself. One has to cope with time-zones, daylight-saving-times, and time-shifts, along with dozens of different representations.

Dealing with time-zones in particular is difficult in javascipt, as the language has no build in support for time-zone conversions in it’s Date object.

Javascripts Date object only comes with support for Local Time Zone and UTC. The Local Time Zone is defined by the Host Environment of the javascript interpreter as stated in section 15.9 of the ecma-script specification. But there is no method in the Date object to query or set this Local Time Zone.

This makes date-time computations almost impossible with the build in javascript Date object. As a way out, there a tree scenarios:

  1. Try to guess the time zone of the browser. You will find a lot of crap with goolge trying to figure out a time zone by a single time zone offset. I only found a few implementations like discussed here, which try to guess the browser time zone in correctly. The Problem with this approach is, that you would need a huge set of DST data in the client to get reliable results. And even if you know the browsers time zone, you won’t be able to let the user switch time zones, as it’s not possible to set a time zone.
  2. Write your own Date object which is time zone capable. This would presumably be the most elegant way for dealing with date-time information in javascript. However such a class would consume much data and computation time and besides having time to write it, i fear that it would have a notable impact on the applications performance.
  3. Don’t do any date-time computations in javascript. You may guess the browsers time zone to define it, but the definition itself and all date-time computations must be made in a time-zone aware system. This is the approach we chose for Tine 2.0. PHP 5.2 introduced a great time-zone aware Date class which we use for all related computations.

But even after the judgement not to use the javascript date object for date-time computations there are some difficulties to cope with.

When creating Date objects from the common ISO8601 representation like:
var t = new Date('10/14/2008 22:00:00 +05:00');
the date object substracts the GMT+5 and internally stores the number of milliseconds from 1/1/1970 in UTC to that date. This means actually the information ’10/14/2008 22:00:00 in the users time’ gets lost.
t.toString(), wich is a alias for t.toLocalString() returns:
Tue Oct 14 2008 19:00:00 GMT+0200 (CEST)
in my browser and t.toUTCString() returns:
Tue, 14 Oct 2008 17:00:00 GMT
which is correct, but not what the the protocol communication in the user time zone expects!

To really use the javascript date object as a simple value store, you must make sure to cut the time zone indicator before parsing the date.
new Date('10/14/2008 22:00:00').toString();
returns:
Tue Oct 14 2008 22:00:00 GMT+0200 (CEST)
At least the values are correct. Before sending, or at least on server side you need to cut the offset and time zone of course, as they are obviously crap in this scenario.

Taking all this into account, it’s possible to circumvent the problematic aspects of the javascript date object (we haven’t talked about its DST implementation ;-) ) and to deliver a multi time zone capable javascript application.

08
Oct

Multi Time-Zone Fix for Ext.form.DateField

When testing the multi time-zone capabilities of Tine 2.0 I came across an interesting problem with the Ext.form.DateField.

The basic form handling in Extjs in like this.

  1. Render the from (e.g. the contact edit dialog).
  2. Get a Ext.data.Record (e.g. representing a contact).
  3. Update the form with the record data: All form properties having a corresponding property in the record will be set/updated.
  4. The user does his changes in the form (e.g. updating the name).
  5. Update the record from the form values: All record properties having a corresponding property in the form will be updated with the form data.

The last step always copies all the form values into the record, regardless of which properties actually got changes by the user. Normally this is no problem, as the value only changes if the user relay did changes. But the implementation of the DateField has a problem in a multi time-zone environment.

Imagine I myself update my birthday in my contact record. This is 1979/06/05. In fact this means by birthday was from 1979/06/05 00:00:00 to 1979/06/05 23:59:59 in the time-zone Europe/Berlin.

So what Tine 2.0 stores in its database is: 1979/06/04 22:00:00 UTC cause Europe/Berlin is UTC+2 when daylight saving time is active. This means in UTC my birthday was from 1979/06/04 22:00:00 to 1979/06/05 21:59:59.

Unfortunately the Ext.dateField has no clue about time-zones or time-shifts. It just deals with dates, e.g. (Y-m-d).

So when my contact record gets updated from someone living in UTC time-zone, the DateField gets filled with 1979/06/04 22:00:00 (step 3). When user changes something and saves changes (step 4) it just return 1979/06/04 (step 5) even though the user didn’t actually change my birthday.

As result, the Tine 2.0 server sees a change in the birthday property from

1979/06/04 22:00:00 UTC to 1979/06/05 00:00:00 UTC which is obviously wrong, as this is not my correct birthday!

As a quick fix for the Ext.form.DateField we now preserve the time when the user does not change the date field. This is the fix I added to our Ext fixes code. Note, you need to include this after the Extjs library, but before your application code.

  1. /**
  2.  * fix timezone handling for date picker
  3.  *
  4.  * The getValue function always returns 00:00:00 as time. So if a form
  5.  * got filled with a date like 2008-10-01T21:00:00 the form returns
  6.  * 2008-10-01T00:00:00 although the user did not change the fieled.
  7.  *
  8.  * In a multi timezone context this is fatal! When a user in a certain
  9.  * timezone set a date (just a date and no time information), this
  10.  * means in his timezone the time range from 2008-10-01T00:00:00
  11.  * to 2008-10-01T23:59:59. _BUT_ for an other user sitting in a
  12.  * different timezone it means e.g. the time range from
  13.  * 2008-10-01T02:00:00 to 2008-10-02T21:59:59.
  14.  *
  15.  * So on the one hand we need to make shure, that the date picker
  16.  * only returns changed datetime information when the user did a
  17.  * change.
  18.  */
  19.  
  20. /**
  21.  * @private
  22.  */
  23. Ext.form.DateField.prototype.setValue = function(date){
  24.     // preserv original datetime information
  25.     this.fullDateTime = date;
  26.     Ext.form.DateField.superclass.setValue.call(this,
  27.     this.formatDate(this.parseDate(date)));
  28. };
  29.  
  30. /**
  31.  * @private
  32.  */
  33.     Ext.form.DateField.prototype.getValue = function(){
  34.     //var value = this.parseDate(Ext.form.DateField.superclass.getValue.call(this));
  35.  
  36.     // return the value that was set (has time information when unchanged in client)
  37.     // and not just the date part!
  38.     value =  this.fullDateTime;
  39.     return value || "";
  40. };