Java Date Conversion - UTC to Local - works differ

2019-07-31 07:52发布

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?

标签: java date utc
5条回答
姐就是有狂的资本
2楼-- · 2019-07-31 08:03

@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));
}
查看更多
来,给爷笑一个
3楼-- · 2019-07-31 08:08

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.

  • US/Alaska
  • US/Aleutian
  • US/Arizona
  • US/Central
  • US/East-Indiana
  • US/Eastern
  • US/Hawaii
  • US/Indiana-Starke
  • US/Michigan
  • US/Mountain
  • US/Pacific
  • US/Pacific-New
  • US/Samoa
查看更多
淡お忘
4楼-- · 2019-07-31 08:15

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.

查看更多
姐就是有狂的资本
5楼-- · 2019-07-31 08:19

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.

Avoid 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).

Time Zone

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.

Time Zone Names

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.

Daylight Saving Time

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.

ISO 8601

Both Joda-Time and java.time support ISO 8601 formats as their defaults in parsing and generating string representations of date-time values.

Joda-Time Example

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" ) );
查看更多
做自己的国王
6楼-- · 2019-07-31 08:26

That's because EST is ET outside of saving and its shift is constant and it complementary zone for daylight saving period is EDT.

Ergo you should use ET to get the expected behavior. More on Wikipedia

查看更多
登录 后发表回答