Dave
Dave

Reputation: 19320

java Date conversion confusion regarding timezones

I'm using Java 6. Our servers are on Eastern Standard Time (GMT-5), and I'm trying to store a value that should be interpreted as such but I'm confused about how to convert it. I have

    String dateStr = "1368921600000";       // This is 5/19/2013 00:00:00
    final Calendar cal = Calendar.getInstance();
    cal.setTimeZone(TimeZone.getTimeZone("GMT-5"));
    cal.setTimeInMillis(Long.parseLong(dateStr));
    final java.util.Date dateObj = cal.getTime();
    System.out.println(dateObj.toString());

but right now this prints out "Sat May 18 19:00:00 CDT 2013" (since my local machine is on CDT) but I want the result to be "Sat May 18 24:00:00 CDT 2013". How can i interpret the date string "1368921600000" as an EST date? Thanks, - Dave

Upvotes: 1

Views: 347

Answers (4)

scottb
scottb

Reputation: 10084

It is often not necessary to use the Joda Time library to get historically accurate time-zone- and daylight-savings-aware local time mappings, although this is the common go to response for many.

If you have a database of timestamps that require local time conversion, then here are some principles that have served me well:

  • Store date/times (Instants, in the parlance of Joda; Dates, in the parlance of the Java Calendar API) in UTC time. UTC does not care about DST. It does not care about time zones. UTC simply represents a universally representable moment in time. This step alone can save a lot of date/time headaches.

  • Database records should contain TimeZone and/or Locale fields so that mapping from UTC can be performed. Think about your data. Every timestamp in your database does not need time zone information associated with it. Instead, associate the time zone data with a part of your data model that provides appropriate granularity. If your app will only ever be localized in one time zone, then you needn't store this infor at all. In my recent project, I created a Locale table that contains the TZ ID for timestamps in my Encounters table. All other timestamps are subordinate to these records, so it made sense to associate it there.

  • Use the Java API GregorianCalendar to map UTC Dates to local time. And that's all I ever use it for. I almost never use GregorianCalendars to do date arithmetic or other date operations. Here is the paradigm that I've been working with:

    public static void main(String[] args) {
    
    m_GregorianCalendar = new GregorianCalendar(TimeZone.getTimeZone(
        "America/Chicago"));
     Date d = new Date();
     String fmt = "dd-MMM-yyyy @ HH:mm";
     :
     :
     String myDate = mapToLocalTime(d, fmt, gc);
     :
     :
     }
    
     public String mapToLocalTime(Date utc, String format, GregorianCalendar gc) {
    
     gc.setTime(utc);  // this calendar is already timezone aware (constructed
                       // with time zone id (DST too))
    
     SimpleDateFormat sdf = new SimpleDateFormat();
     sdf.setCalendar(gc);               // formatter uses conventions of calendar
     sdf.applyPattern(fmt);             // pattern for formatter
    
     return sdf.format(utc);
     }
    
  • Consider representing timestamps internally in a numeric format (longs, doubles). This greatly simplifies date comparisons and date arithmetic. The only downside is that conversions must be done to format the data into a human recognizable form, but if you use functions for these conversions it need not be a big deal at all.

Upvotes: 1

William Price
William Price

Reputation: 4102

1368921600000 is an instant in time, the same instant, everywhere in the world. To convert this to a date and time, you have to specify where in the world you want to know the date/time at that instant. It just so happens that the timestamp is relative to UTC, and is Sun, 19 May 2013 00:00:00 GMT.

If you want the time of this instant (the same instant) somewhere else in the world, you can use the Calendar as you did and extract the individual field values (e.g. HOUR_OF_DAY). If all you care about is getting a text string, you use a DateFormat instance such as SimpleDateFormat:

DateFormat df = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z");
df.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String timeOnUSEastCoast = df.format(new Date(1368921600000L));
// will be GMT-5 or GMT-4 depending on DST

In this example, the output would be GMT-4: Sat, 18 May 2013 20:00:00 EDT (not only has the hour changed, but it's still the previous day on the US east coast).

If you want to output the UTC time but just want to pretend it's EST then it's just easier to tell the DateFormat to leave off the time zone field (remove the "z") in the text output and call it whatever you want, but understand that the timestamp value is always UTC.

Upvotes: 2

mzywiol
mzywiol

Reputation: 436

When you're printing Date.toString(), the Calendar's time zone is not taken into consideration at all. After you do a cal.getTime(), whatever was set in Calendar is no longer relevant.

What is is TimeZone's default time zone.

So right before printing the date, set the default time zone to the one you want to print in, e.g.:

String dateStr = "1368921600000";       // This is 5/19/2013 00:00:00
final Calendar cal = Calendar.getInstance();
TimeZone gmtZero = TimeZone.getTimeZone("GMT");
cal.setTimeInMillis(Long.parseLong(dateStr));
final java.util.Date dateObj = cal.getTime();
TimeZone.setDefault(gmtZero);
System.out.println(dateObj.toString());

This will print the date in GMT regardless of your system time zone.

Just remember to bring back the original default TimeZone afterwards!

Upvotes: 0

Tassos Bassoukos
Tassos Bassoukos

Reputation: 16152

Use either a new java.util.SimpleDateFormat(format) or java.util.DateFormat.getDateTimeInstance(int,int), then use #setTimeZone(timezone).

Upvotes: 0

Related Questions