使用 Java 8 Time 将时间从一个时区转换为另一个时区

Convert Time from one time zone to another using Java 8 Time

我正在尝试将 GMT +5:30 的日期转换为 java 的 EST 8 ZonedDateTime.

String inputDate = "2015/04/30 13:00";
DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm", Locale.US);
LocalDateTime local = LocalDateTime.parse(inputDate, sourceFormatter);
// local : 2015-04-30T13:00
//Combining this local date-time with a time-zone to create a ZonedDateTime. 
ZonedDateTime zoned = local.atZone(TimeZone.getTimeZone("GMT+5:30").toZoneId());
// zoned : 2015-04-30T13:00+05:30[GMT+05:30]
ZonedDateTime zonedUS = zoned.withZoneSameInstant(TimeZone.getTimeZone("GMT-5:00").toZoneId());
// zonedUS : 2015-04-30T02:30-05:00[GMT-05:00]

我期待 3:30 AM EST 但我得到的是 2:30 AM EST1 PM IST= 3:30AM EST。我错过了什么?

您找到的任何服务似乎都对解释您的意思和在您指定 EST(东部标准时间)时假定的北美东部夏令时 (EDT) 有过度帮助。大多数(并非所有)使用 EST 作为标准时间的地方都使用夏令时,因此在您使用的日期(2015 年 4 月 30 日)处于 EDT 或偏移 UTC-04:00。

如果在您的情况下有意义,您应该始终更喜欢以 region/city 格式提供时区,如 Asia/Kolkata 和 America/New_York。如果您打算使用纽约或蒙特利尔的东部时间,有人可能会说您的“时区”GMT-5:00 是错误的,这是您意想不到的结果的原因。

因此您的代码变为例如:

    String inputDate = "2015/04/30 13:00";
    DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm", Locale.US);
    LocalDateTime local = LocalDateTime.parse(inputDate, sourceFormatter);
    // local : 2015-04-30T13:00
    //Combining this local date-time with a time-zone to create a ZonedDateTime. 
    ZonedDateTime zoned = local.atZone(ZoneId.of("Asia/Kolkata"));
    // zoned : 2015-04-30T13:00+05:30[Asia/Kolkata]
    ZonedDateTime zonedUS = zoned.withZoneSameInstant(ZoneId.of("America/Montreal"));
    // zonedUS : 2015-04-30T03:30-04:00[America/Montreal]

我做了另一项更改:当使用来自 java.time 的现代 classes 时,也没有必要同时使用过时的 TimeZone class,所以我已经把它拿出来了。代码稍微简单一些,更重要的是,ZoneId.of(String) 包含对时区字符串的验证,因此您会发现时区名称中的任何拼写错误(就像我刚好输入 ( 而不是Asia/Kolkata 中的 / — 这种情况经常发生)。

以上大部分内容已在 Jon Skeet 和其他人的评论中提及。我认为它应该得到一个答案,所以很明显看到这个问题已经被回答了。

虽然这个问题很老,但我觉得我可以在接受的答案中添加更多内容。

ZonedDateTime 不同于 OffsetDateTime

我更愿意使用 ZonedDateTime 来获取特定位置的时间,例如“Asia/Kolkata”、“Asia/Shanghai”、“US/Pacific” (由于夏令时,这个时区会根据一年中的某一天发生变化)。

举例说明,

var pacific = ZonedDateTime.of(2020,11,01,1,59,0,0,ZoneId.of("US/Pacific"))
var afterAnHour = pacific.plusHours(1)

这将给我一个

的时间

2020-November-01 01:59:00.000 AM -07:00[US/Pacific]

如果我加一个小时,它会给我一个

的时间

2020-November-01 01:59:00.000 AM -08:00[US/Pacific]

你可以看到,即使在时间上加上一个小时,小时部分还是一样的。这是因为夏令时已经开始,时区从 -07:00 转移到 -08:00.

现在如果我使用 OffsetDateTime 看看会发生什么。

var offsetNow = OffsetDateTime.of(2020,11,01,1,59,0,0,ZoneOffset.of("-07:00"))
var offsetAfterAnHour = offsetNow.plusHours(1)

offsetNow 将是,

2020-November-01 01:59:00.000 -07:00

再加上一个小时,

2020-November-01 02:59:00.000 -07:00

可以看到加了一个小时后,小时分量变成了2

关键点是 ZonedDateTime 使用 ZoneRules 计算夏令时等重要属性,以便它可以相应地调整时区。

虽然 OffsetDateTime 不会更改任何区域偏移量。