views:

248

answers:

3

I have a date stored as a java.sql.Timestamp in a database. The date is "2010-01-20T19:10:35.000Z" and is equivalent to 1264014635743 ms.

Somehow, the date is formatted differently on the prod machine compared to the dev machine.

The code to format the date is:

private final static String DATE_FORMAT = "yyyy-MM-dd";
public final static SimpleDateFormat APP_DATE_FORMATER = new SimpleDateFormat(DATE_FORMAT);
private static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("Etc/UTC");
APP_DATE_FORMATER.setTimeZone(UTC_TIMEZONE);
DateTimeZone.setDefault(DateTimeZone.UTC);

String output = APP_DATE_FORMATER.format(date)

The generated output in dev is the correct "2010-01-20". But in prod I have "2010-01-21", one day later!

Of course, since the error occurs on the prod server, I'm limited in my debugging options...

I have double checked, and both server have the same time and timezone. Both clock are synchronized with an ntp server.


[UPDATE] The database in prod has the value: "10-01-20 19:10:35,743000000" for the date field

+2  A: 

While the machines have the same time zone, what about database settings? Is it possible that the database is set to a different time zone than the machine?

digitaljoel
+3  A: 

My first thought is that this is a concurrency issue. SimpleDateFormat is not thread-safe, yet you're sharing a static instance. If you need to use java.text formatters in a multi-threaded environment, you should use a ThreadLocal to hold them:

private static ThreadLocal<DateFormat> _datetimeFormatter = new ThreadLocal<DateFormat>();

private static DateFormat getDatetimeFormatter()
{
    DateFormat format = _datetimeFormatter.get();
    if (format == null)
    {
        format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        _datetimeFormatter.set(format);
    }
    return format;
}

public static String formatDatetime(Date date)
{
    return getDatetimeFormatter().format(date);
}

It's also possible (but unlikely) that "Etc/UTC" is not found on the server. Do you log the value from getTimeZone()?

And the third option is, to paraphrase Inigo Montoya, "you are not running the code that you think that you are running." It could be because your presentation code didn't properly unload on the server, or there's another date formatter floating around.

kdgregory
Thanks for the threading suggestions. But I doubt the cause of the problem is threading because each time I refresh the page, the date is recalculated and shown as 2010-01-21...
Thierry-Dimitri Roy
In that case, you're looking at a timezone issue. Can you get the sysadmins to run a SSCEP that simply formats and prints the specific timestamp value?
kdgregory
I have access to the prod server, but I do not know what "SSCEP" is (it's a Windows Server 2008 machine). I checked the timezone setting on both machine by double-clicking on the date/time in the taskbar and they are the same.Thanks by the way for the ThreadLocal code!
Thierry-Dimitri Roy
An SSCEP is a small, self-contained example program. It should be a single class that contains the code from your original post, and simply formats and prints the known date value. You could also add in a print statement for the timezone value. If it works (formats the date correctly), then you'll know to look elsewhere in your code (maybe you have something that isn't using the date format, or is using a different format). If it doesn't work, you'll be able to figure out why without touching server code.
kdgregory
You might also be interested in a series of debugging articles that I've posted on my blog: http://blog.kdgregory.com/2009/12/debugging-101-assumptions.html
kdgregory
It's actually called SSCCE: http://sscce.org
BalusC
I now use ThreadLocal, and it seems to work fine. Thanks!
Thierry-Dimitri Roy
A: 

Have you checked that the JVM settings are the same on the Production and Development machines? The times may be in sync at the server level, but maybe the way the JVM is set up is has some confusion about what time zone it is in.

Spike Williams