Reputation: 141
I'm experiencing a problem when converting strings to a UTC data, and then to various timezones. It appears that my program behaves differently depending on whether I convert to EST or PST. Here is my code:
SimpleDateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
utcFormat.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
Date date = utcFormat.parse("2014-08-18 17:00:17");
SimpleDateFormat localFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
localFormat.setTimeZone(java.util.TimeZone.getTimeZone("PST"));
System.out.println(localFormat.format(date));
If I run the code above, here is my output:
2014-08-18 10:00:17
This reflects a 7 hour offset from the UTC time provided: 2014-08-18 17:00:17. This is what I would have expected. Now if I change that date to 2014-11-18 17:00:17 (changed the month from August to November), here is the output produced:
2014-11-18 09:00:17
This is fine too as far as I can tell. The output reflects an 8 hour offset from UTC, and I believe this is due to the fact that November is not in Daylight Savings time, while August is.
The problem I'm having is that the same code above works differently if I change the time zone from "PST" to "EST". When I change to EST I get the same time output no matter whether my date is in August or November.
Here is the output using EST and 2014-08-18 17:00:17
2014-08-18 12:00:17
Here is the output using EST and 2014-11-18 17:00:17
2014-11-18 12:00:17
In both cases, the output represents a 5 hour offset from UTC which makes sense only during November, not during August.
Can anyone explain to me what I am doing wrong?
Upvotes: 1
Views: 1415
Reputation: 340178
The answer by Dave Morrissey is correct.
Can anyone explain to me what I am doing wrong?
Yes. You are using a terrible and confusing date-time library.
java.util.Date
The java.util.Date and .Calendar classes are notoriously troublesome, flawed in both design and implementation. Use a decent library. In Java that means either Joda-Time or the new java.time package in Java 8 (inspired by Joda-Time, defined by JSR 310).
While a j.u.Date has no time zone, in both Joda-Time and java.time a date-time object does indeed know its own assigned time zone. Makes this work much easier and more sensible.
Use proper time zone names. Avoid the 2, 3, or 4 letter codes as they are neither standardized nor unique. Most of those proper names are Continent/CityOrRegion
.
You should not worry about Daylight Saving Time. Let the date-time library do the heavy lifting there. All you need to do is be sure your library is using a fresh version of the time zone database. Politicians enjoy redefining DST.
Both Joda-Time and java.time support ISO 8601 formats as their defaults in parsing and generating string representations of date-time values.
Here is some example code in Joda-Time 2.4. All of the DateTime objects in this example represent the same simultaneous moment in the history of the Universe but adjusted to show the wall-clock time as seen by a person in each locality.
String inputRaw = "2014-08-18 17:00:17"; // Nearly in [ISO 8601][7] format.
String input = inputRaw.replace( " ", "T" );
DateTime dateTimeUtc = DateTime.parse( input, DateTimeZone.UTC );
DateTime dateTimeLosAngeles = dateTimeUtc.withZone( DateTimeZone.forID( "America/Los_Angeles" ) );
DateTime dateTimeNewYork = dateTimeUtc.withZone( DateTimeZone.forID( "America/New_York" ) );
DateTime dateTimeMontréal = dateTimeUtc.withZone( DateTimeZone.forID( "America/Montreal" ) );
DateTime dateTimeKolkata = dateTimeUtc.withZone( DateTimeZone.forID( "Asia/Kolkata" ) );
Upvotes: 0
Reputation: 7764
@Compass is right. Here is the code you would use:
public static void main(String[] args) {
SimpleDateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
utcFormat.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
Date date = null;
try {
date = utcFormat.parse("2014-08-18 17:00:17");
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SimpleDateFormat localFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
localFormat.setTimeZone(java.util.TimeZone.getTimeZone("US/Eastern"));
System.out.println(localFormat.format(date));
}
Upvotes: 0
Reputation: 5937
From the Documentation for TimeZone
For compatibility with JDK 1.1.x, some other three-letter time zone IDs (such as "PST", "CTT", "AST") are also supported. However, their use is deprecated because the same abbreviation is often used for multiple time zones (for example, "CST" could be U.S. "Central Standard Time" and "China Standard Time"), and the Java platform can then only recognize one of them.
Instead of "EST"
, "US/Eastern"
will be much clearer as to your intent.
These are the supported US aliases.
Upvotes: 2
Reputation: 4421
Instead of using EST
, you should use America/New_York
or US/Eastern
(these are aliases). The three letter timezone abbreviations are ambiguous and you can't be sure what you're getting.
Upvotes: 3