Working with Dates/Timezones

3,056 views
Skip to first unread message

Jens

unread,
Aug 1, 2012, 11:12:46 AM8/1/12
to google-we...@googlegroups.com
Hi,

how do you work with dates/timezones in your apps? I have the following situation:

(Client browser, app server, database server live in Germany and we have UTC+1 or UTC+2 when daylight saving time is active)

A user chooses a Date + Time (e.g. from GWT's DateBox) and we send that date object to the server and store it in database. On the client side everything is visually consistent until we want to print something. The report is generated on the server and the date that the user has entered can be off by 1 hour on the server which results in wrong dates in the report compared to the information visible inside the client app. Also if you use DateBox and only display the day portion of a date the date will still be off by one hour but to the user it is visible as being off by one day in the report because the date contains 00:00:00 as time portion which will become 23:00:00 for the previous day on the server.

As an example the user may chooses 26.10.1951 12:00:00 via the GWT DateBox. Chrome, Safari, IE and Opera think (java.util.Date delegates to JsDate class in compiled app) that daylight saving time is active for that date (UTC+2 and thus date.getTimezoneOffset() returns -120 minutes). Unfortunately we don't have daylight saving time from 1950 to 1979 at all in Germany and our app server (= JVM) / database server knows this fact which results in a differently rendered date on the server. So if we render that date on the server its off by one hour (UTC+2 on client vs. UTC+1 on server). Firefox does correctly treat the date as UTC+1. On the other hand there are other dates where Firefox fails but other browsers do it correctly.

As the GWT DateBox uses a DefaultFormat that uses DateTimeFormat and calls dtf.format(date) without a timezone I provided a custom Formatter that explicitly uses GWT's europeBerlin timezone. Now the GWT DateBox shows 26.10.1951 11:00:00 because GWT's timezone provided to the DateTimeFormat detects that no day light saving time is active at this date. Now client and server render the date the same although the browser created it incorrectly with UTC+2. BUT sadly there are other dates where GWT's timezone information also failes and differs from the server timezone information.

So short story: Its currently impossible to create a consistent behavior between client and server for certain dates. It seems like that GWT's timezone info and the browsers native timezone infos have different data than the tz database used by Unix / Linux / Java / database server. There are also differences between browsers itself.

So how do you guy work with dates in your app? I mean as an example it can be as easy as selecting a birthday (without time => 00:00:00) and use that birthday on server side in a report. Now you are maybe a day older in the report if you live in germany :-)

The only "partial" solution we can think of is to always use 12:00:00 as time if you are only interested in the day portion of date (to avoid off by one day problem) and to use a fixed non DST day (maybe 01.01.1970) which is safe in all browsers if you are only interested in the time portion of date (to make sure its rendered the same on client/server). Obviously this also means that we can never store day and time in a single date instance.

So whats your experience with timezones and/or do you have other possible solutions? Or have you never noticed this discrepancy in your timezone? In Dev mode everything works fine, because its Java like on the app server.

-- J.

Rob Coops

unread,
Aug 1, 2012, 11:24:37 AM8/1/12
to google-we...@googlegroups.com
Hi,

Is it not possible when the client requests to print a document to make the client timezone part of the request? In that case you can server side very easily convert from the stored TZ to the client TZ before printing...

You should simply be able to ask the client what it's timezone is. In pure Javascript it would be: var offset = new Date().getTimezoneOffset(); which will return you the amount of minutes you are offset so a UTC+2 would return 120 where UTC-10 would result in -600 etc...

You could even allow your client to override their system TZ and print the document as if it where printed in a TZ of their choice.

Regards,

Rob



-- J.

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/q04nxG_F8BkJ.
To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Joseph Lust

unread,
Aug 1, 2012, 5:52:03 PM8/1/12
to google-we...@googlegroups.com
This is a classic problem. For starters, we (also operate in Germany :/ ) store just Dates where possible in Oracle and pull these out using java.sql.Date so there is no H/M/S information at all. We also use custom date serializers between Client/Server in GWT so that again, just the day is passed. We found that while there are many dates in our application, 95% of them don't need H:M:S, and further that the source date does not have TZ info, so we cannot even assume that the source H:M:S information is correct. Given this, all dates are stored UTC and the UI promulgates this fact.

This gets around the midnight issue for a 12:00:00 getting flipped to the next/previous date due to TZ.

However, in my personal applications (RunPartner.com) logged run time of day does matter. For this the user TZ is harvested from the browser, as well as if it is DST or not, all just using a hidden JS block. Then all values going in/out of the server are converted to/from the server TZ to the browser zone. I have not tested this however with historical DST changes like with Indiana changed their DST practices a few years ago.

I hope that helps.

Sincerely,
Joseph

Richard

unread,
Aug 2, 2012, 2:40:22 AM8/2/12
to google-we...@googlegroups.com
I use a timezone-agnostic value for the user's intent (X time on Y day), e.g. a string or long value that I create with my own format (e.g. 201207052030, which has date and time).  I store that, and translate it into server-understandable values.  I store the account's default timezone, and the users timezone if they have a different one to the account, and do all important calcs on the server.

This way, if the user timezone changes, or an entity is re-assigned to a new user, the original intent is maintained and simply translated into that users timezone.

Jens

unread,
Aug 3, 2012, 2:42:30 PM8/3/12
to google-we...@googlegroups.com
Thank you guys. As we currently operate in Germany only we have implemented a custom date serializer that does not de/serialize a date by using its milliseconds (date.getTime()) but instead uses the real date information (date.getYear(), date.getMonth(), ...). So its somewhat similar to Richard's approach.

-- J.

Joseph Lust

unread,
Aug 3, 2012, 3:06:39 PM8/3/12
to google-we...@googlegroups.com
I hope that works for you. That is pretty much what we did when Germany started to cause issues. I put the code for it up in an earlier post:


viel Glück,
Joseph

Jens

unread,
Aug 3, 2012, 3:15:36 PM8/3/12
to google-we...@googlegroups.com
However, in my personal applications (RunPartner.com) logged run time of day does matter. For this the user TZ is harvested from the browser, as well as if it is DST or not, all just using a hidden JS block. 

How do you get that information? From my understanding you cant do that reliably.

-- J.

Jens

unread,
Aug 3, 2012, 3:28:05 PM8/3/12
to google-we...@googlegroups.com
I hope that works for you. That is pretty much what we did when Germany started to cause issues. I put the code for it up in an earlier post:

Yeah thats exactly the same class. Although I first used instance.getDay() instead of instance.getDate() and was a bit confused about the result :-)

Currently the only confusion that could happen is if a customer is on vacation in a different timezone and starts an action that causes the server to create a date and then send it back to the client to display it. The date will be a german date. But thats fine, as its pretty much like "working remotely in Germany from outside Germany" for now.

Joseph Lust

unread,
Aug 4, 2012, 12:33:43 AM8/4/12
to google-we...@googlegroups.com
Jens,

Here is the TZ script from my hobby running site. It is a tad hackish (from 4 years ago), set to update a hidden select menu in forms. I have not yet had any complaints about it's output, but I don't promise anything either. Hopefully you might find it helpful and can make a JSNI derivative if it meets your needs.


Sincerely,
Joseph
// original script by Josh Fraser (http://www.onlineaspect.com)
function calculate_time_zone() {
    var rightNow = new Date();
    var jan1 = new Date(rightNow.getFullYear(), 0, 1, 0, 0, 0, 0);  // jan 1st
    var june1 = new Date(rightNow.getFullYear(), 6, 1, 0, 0, 0, 0); // june 1st
    var temp = jan1.toGMTString();
    var jan2 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
    temp = june1.toGMTString();
    var june2 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
    var std_time_offset = (jan1 - jan2) / (1000 * 60 * 60);
    var daylight_time_offset = (june1 - june2) / (1000 * 60 * 60);
    var dst;
    if (std_time_offset == daylight_time_offset) {
        dst = "0"; // daylight savings time is NOT observed
    } else {
        // positive is southern, negative is northern hemisphere
        var hemisphere = std_time_offset - daylight_time_offset;
        if (hemisphere >= 0)
            std_time_offset = daylight_time_offset;
        dst = "1"; // daylight savings time is observed
    }
    var i;
    // check just to avoid error messages (hidden select posted with forms)
    if (document.getElementById('timezone_name')) {
        for (i = 0; i < document.getElementById('timezone_name').options.length; i++) {
            if (document.getElementById('timezone_name').options[i].value == convert(std_time_offset)+","+dst) {
                document.getElementById('timezone_name').selectedIndex = i;
                break;
            }
        }
    }
}

function convert(value) {
    var hours = parseInt(value);
       value -= parseInt(value);
    value *= 60;
    var mins = parseInt(value);
       value -= parseInt(value);
    value *= 60;
    var display_hours = hours;
    // handle GMT case (00:00)
    if (hours == 0) {
        display_hours = "00";
    } else if (hours > 0) {
        // add a plus sign and perhaps an extra 0
        display_hours = (hours < 10) ? "+0"+hours : "+"+hours;
    } else {
        // add an extra 0 if needed 
        display_hours = (hours > -10) ? "-0"+Math.abs(hours) : hours;
    }

    mins = (mins < 10) ? "0"+mins : mins;
    return display_hours+":"+mins;
}
Message has been deleted

Jens

unread,
Aug 5, 2012, 2:52:58 PM8/5/12
to google-we...@googlegroups.com
Here is the TZ script from my hobby running site. It is a tad hackish (from 4 years ago), set to update a hidden select menu in forms. I have not yet had any complaints about it's output, but I don't promise anything either. Hopefully you might find it helpful and can make a JSNI derivative if it meets your needs.

Thanks! I'll take a look at it.

-- J.

Andy

unread,
Apr 23, 2013, 11:46:40 AM4/23/13
to google-we...@googlegroups.com
A bit late, but I would recommend you check out our UTCDateBox at http://code.google.com/p/gwt-traction/

I'm justing leaving this comment here so that people discovering this thread later have an easy solution.

-Andy
Reply all
Reply to author
Forward
0 new messages