Java日期转换 - UTC到本地 - 根据时区的不同而不同

时间:2014-09-19 19:07:20

标签: java date utc

我在将字符串转换为UTC数据,然后转换为各种时区时遇到问题。根据我是否转换为EST或PST,我的程序似乎表现不同。这是我的代码:

    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));

如果我运行上面的代码,这是我的输出:

    2014-08-18 10:00:17

这反映了与提供的UTC时间相差7小时:2014-08-18 17:00:17。这是我所期待的。现在,如果我将该日期更改为2014-11-18 17:00:17(从8月更改为11月),则输出结果如下:

    2014-11-18 09:00:17

据我所知,这也很好。输出反映了与UTC的8小时偏移,我相信这是因为11月不是夏令时,而8月是。

我遇到的问题是,如果我从" PST"更改时区,则上述相同代码的工作方式会有所不同。到" EST"。当我改为EST时,无论我的日期是8月还是11月,我都会获得相同的时间输出。

以下是使用EST和2014-08-18 17:00:17的输出

    2014-08-18 12:00:17

以下是使用EST和2014-11-18 17:00:17的输出

    2014-11-18 12:00:17

在这两种情况下,输出表示距离UTC的5小时偏移,这仅在11月期间有意义,而不是在8月期间。

任何人都可以向我解释我做错了什么吗?

5 个答案:

答案 0 :(得分:3)

您应该使用ESTAmerica/New_York(这些是别名),而不是使用US/Eastern。三个字母的时区缩写是不明确的,你不能确定你得到了什么。

答案 1 :(得分:1)

来自TimeZone的文档

  

为了与JDK 1.1.x兼容,还支持其他一些三字母时区ID(例如“PST”,“CTT”,“AST”)。但是,它们的使用已被弃用,因为相同的缩写通常用于多个时区(例如,“CST”可能是美国“中央标准时间”和“中国标准时间”),然后Java平台只能识别其中一个它们。

而不是"EST""US/Eastern"将更清楚你的意图。

这些是受支持的美国别名。

  • 美国/阿拉斯加
  • US / Aleutian
  • 美国/亚利桑那州
  • 美国/中部
  • 美国/东印第安纳
  • 美国/东方
  • 美国/夏威夷
  • US / Indiana-Starke
  • 美国/密歇根州
  • US /山
  • 美国/太平洋地区
  • 美国/太平洋 - 新
  • US /萨摩亚

答案 2 :(得分:0)

@Compass是对的。 以下是您将使用的代码:

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 :(得分:0)

answer by Dave Morrissey是正确的。

  

任何人都可以向我解释我做错了吗?

是。您使用的是一个糟糕且令人困惑的日期时间库。

避免java.util.Date

java.util.Date和.Calendar类非常麻烦,在设计和实现方面都存在缺陷。使用体面的图书馆。在Java中,这意味着Joda-Timejava.time package中的新Java 8(受Joda-Time启发,由JSR 310定义)。

时区

虽然j.u.Date没有时区,但在Joda-Time和java.time中,日期时间对象确实知道自己指定的时区。使这项工作更容易,更明智。

时区名称

使用proper time zone names。避免使用2个,3个或4个字母代码,因为它们既不标准也不唯一。大多数专有名称都是Continent/CityOrRegion

夏令时

您不必担心夏令时。让日期时间库在那里进行繁重的工作。您需要做的就是确保您的磁带库使用时区数据库的新版本。政客们喜欢重新定义夏令时。

ISO 8601

Joda-Time和java.time都支持ISO 8601格式作为解析和生成日期时间值的字符串表示的默认值。

Joda-Time示例

以下是Joda-Time 2.4中的一些示例代码。此示例中的所有DateTime对象表示Universe历史记录中的相同时刻,但经过调整以显示每个地点的人员所看到的wall-clock time

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" ) );

答案 4 :(得分:-1)

这是因为EST在保存之外是ET,其转变是不变的,夏令时的补充区域为EDT

你应该使用ET来获得预期的行为。 更多关于Wikipedia