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

使用Java 8 Time将时间从一个时区转换为另一个时区,java,timezone,Java,Timezone,我正在尝试使用java 8ZoneDateTime将GMT+5:30的日期转换为EST String inputDate = "2015/04/30 13:00"; DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm", Locale.US); LocalDateTime local = LocalDateTime.parse(inputDate, sourceFormatter);

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

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,但我得到的是东部时间凌晨2:30,因为东部时间下午1点IST=3:30。我遗漏了什么?

当您指定东部标准时间(EST)时,您发现的任何服务似乎都过分有助于解释您的意思和假设的北美东部夏时制(EDT)。大多数使用EST作为标准时间的地方都使用夏时制,因此在您使用的日期2015年4月30日是EDT或偏移UTC-04:00

如果在你的情况下有意义的话,你应该总是选择区域/城市格式的时区,如亚洲/加尔各答和美洲/纽约。如果你打算在纽约或蒙特勒尔使用东部时间,你可能会说你的“时区”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
中的现代类时,也没有必要使用过时的
TimeZone
类,所以我去掉了它。代码稍微简单一点,更重要的是,
ZoneId.of(String)
包括对时区字符串的验证,这样您就可以发现时区名称中的任何拼写错误(比如我刚刚碰巧键入了一个
而不是亚洲/加尔各答的
/
,这种情况经常发生)


乔恩·斯基特(Jon Skeet)和其他人在评论中已经提到了上述大部分内容。我认为应该给出一个答案,因此很明显,这个问题已经得到了回答。

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

ZonedDateTime
OffsetDateTime
不同

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]
我更喜欢使用
ZonedDateTime
当我获得特定位置的时间时,如“亚洲/加尔各答”、“亚洲/上海”、“美国/太平洋”(由于夏令时,该时区将根据一年中的日期而变化)

举例说明,

var pacific = ZonedDateTime.of(2020,11,01,1,59,0,0,ZoneId.of("US/Pacific"))
var afterAnHour = pacific.plusHours(1)
这将给我一段时间的休息

2020-11-01 01:59:00.000 AM-07:00[美国/太平洋]

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

2020-11-01 01:59:00.000 AM-08:00[美国/太平洋]

您可以看到,即使在时间中添加了一个小时,小时的组成仍然是相同的。这是因为夏令时已经开始,时区从-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)
现在的补偿是

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

再加上一个小时

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

您可以看到,添加小时后,小时组件已变为
2

关键点是
zoneDateTime
使用
ZoneRules
计算重要属性,如夏令时,以便相应地调整时区


OffsetDateTime
不会改变任何区域的偏移量。

嗯,这在我看来是正确的。13:00+05:30=07:30 UTC=02:30-05:00。在+05:30和-05:00之间有10:30的差异,而13:00-10:30是02:30…为什么预期凌晨3:30?请注意,东部时间现在是UTC-4,因为它是EDT而不是EST。例如,纽约当时的时间是03:30。@JonSkeet当我在谷歌上搜索时间EST时,它显示我是东部时间凌晨3:30,而不是东部时间下午1:00。这是因为夏令时?如果你显示的是东部时间凌晨3:30,那么它就不准确了。它可能是指东部时间凌晨3:30,而不是东部时间(事实上,谷歌搜索告诉我的是)…东部时间总是UTC-5,而东部时间在东部时间(UTC-5)和东部时间(UTC-4)之间变化。如果你想要东部时间,你应该使用区域ID“America/New_York”。(我通常建议使用基于地点的区域ID,而不是一般的偏移区域ID…)@JonSkeet。感谢您从@Zeeshan课程的答案中获得解决方案:避免使用3-4个字母的代码。使用。示例:
America/New_York
America/Montreal