【问题标题】:How to convert ISO 8601 formatted DateTime to another time zone in Java?如何将 ISO 8601 格式的 DateTime 转换为 Java 中的另一个时区?
【发布时间】:2018-11-17 19:45:51
【问题描述】:

我现在的日期:
UTC 日期:2018-06-06T16:30:00Z(UTC 中的 ISO 8601)

日期 iso:2018-06-06T11:30:00-05:00 (ISO 8601)

日期纪元:1528302600000(纪元/Unix 时间戳)

我希望将上述日期时间转换为其他时区区域(如 GMT+5:30)。而且我不确定我会从以上三个中收到哪种时间格式。那么我可以有一个通用方法,可以将上面转换为另一个时区,在 Java 8 中返回 java.util.Date 吗?

我做了类似的事情,但没有成功

public Date convertDateToLocalTZ(Date iso8601, ZoneId toZoneId) {
    Date dateTime = null;
    if (iso8601 != null && toZoneId != null) {
        Instant instant = iso8601.toInstant();
        LocalDateTime localDateTime = instant.atZone(toZoneId).toLocalDateTime();
        dateTime = Date.from(localDateTime.atZone(toZoneId).toInstant());
        return dateTime;
    }
    return dateTime;
}

【问题讨论】:

  • Timezone conversion的可能重复
  • 取决于您使用的 API。你说的是java.util.Date吗?您想使用新的 java-8 API 还是 SimpleDateFormatter 足够?
  • @John 不是重复的,因为该重复只涵盖时区转换,而不是使用两个给定值的方式。
  • @John 正如 Andreas 评论的那样,这个问题不是与您的链接问题重复。我想这是重复的,但我找不到将解析问题与区域调整问题结合起来的原件。
  • 好吧,这个问题很微妙,我最近自己调查过,并没有意识到这种区别(为什么有人会为了新鲜而想要新的?)。最糟糕的是问题中给出的研究问题被无益地反刍为重复标志。

标签: java date datetime java-8 utc


【解决方案1】:

由于问题被标记为java-8,请使用java.time API。


更新:对于问题的版本 4,其中添加了 2018-06-06T11:30:00-05:00

要解析1528302600000,请将其解析为long,然后使用Instant.ofEpochMilli()

要解析2018-06-06T11:30:00-05:00 之类的格式,您可以使用OffsetDateTimeZonedDateTime。两者都可以解析2018-06-06T16:30:00Z

要将时区专门更改为特定的偏移量,例如 GMT+5:30,请使用 ZoneOffset,例如ZoneOffset.of("+05:30"),或ZoneId,例如ZoneId.of("GMT+05:30")
注 1:GMT+5:30 无效。
注 2: 更改为地区的时区,遵守夏令时时间,使用例如ZoneId.of("Asia/Kolkata").

要解析所有 3 种输入格式,甚至支持 2018-06-06T11:30-05:00[America/Chicago] 之类的扩展格式,请使用 ZonedDateTime,并对 epoch 编号进行特殊处理。

public static ZonedDateTime parseToZone(String text, ZoneId zone) {
    if (text.indexOf('-') == -1)
        return Instant.ofEpochMilli(Long.parseLong(text)).atZone(zone);
    return ZonedDateTime.parse(text).withZoneSameInstant(zone);
}

然后,调用者可以通过使用toOffsetDateTime() 将其转换为OffsetDateTime 来决定是否应该只使用偏移量而不是完整时区。

测试

ZoneId india = ZoneId.of("Asia/Kolkata");

System.out.println(parseToZone("2018-06-06T16:30:00Z", india));
System.out.println(parseToZone("2018-06-06T11:30:00-05:00", india));
System.out.println(parseToZone("1528302600000", india));

System.out.println(parseToZone("1528302600000", india).toOffsetDateTime());

输出

2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30

原答案

parse() 方法与2018-06-06T16:30:00Z 结合使用。
ofEpochMilli() 方法与1528302600000 一起使用。
然后使用atZone() 转换为您想要的时区。

演示

Instant instant1 = Instant.parse("2018-06-06T16:30:00Z");
Instant instant2 = Instant.ofEpochMilli(1528302600000L);

ZoneId india = ZoneId.of("Asia/Kolkata");
ZonedDateTime date1 = instant1.atZone(india);
ZonedDateTime date2 = instant2.atZone(india);

System.out.println(instant1);
System.out.println(instant2);
System.out.println(date1);
System.out.println(date2);

输出

2018-06-06T16:30:00Z
2018-06-06T16:30:00Z
2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30[Asia/Kolkata]

要以人类格式打印结果,请使用DateTimeFormatter

DateTimeFormatter indiaFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
                                                    .withLocale(Locale.forLanguageTag("en-IN"));
DateTimeFormatter hindiFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
                                                    .withLocale(Locale.forLanguageTag("hi-IN"));
System.out.println(date1.format(indiaFormatter));
System.out.println(date1.format(hindiFormatter));

输出

6 June 2018 at 10:00:00 PM IST
6 जून 2018 को 10:00:00 अपराह्न IST

【讨论】:

  • 是否有可能在 java.util.Date 中获得与返回类型相同的结果?或者有什么方法可以将 ZonedDateTime 转换为 java.util.Date?我试图达到同样的效果,但是当我使用 System.out.println(date); 打印日期时返回的日期与 TimeZone 无关,并且始终以本地时区打印日期。
  • @ShainiSinha 不,因为java.util.Date 始终是 UTC/GMT 并且不存储时区。使用旧的 Date API,它只是应用时区的格式化程序。使用 Java Time API,一些类也可以存储时区。这是他们修复的问题之一,也是他们创建新 API 的原因。因此,要在特定时区打印 java.util.Date,请在使用格式化程序之前调用 DateFormat.setTimeZone(TimeZone zone),但 input 时区已丢失。使用新课程!!!
【解决方案2】:

在 Java 8+ 中,您应该使用新的 java.time API。

您的初始 UTC 时间必须建模为 Instant。如果需要,可以使用 DateTimeFormatter 从 2018-06-07T22:21:00Z 之类的字符串中解析,或者使用 Instant.now 获取当前 Instant。

然后您可以使用 Instant.atZone 或 Instant.withOffset 分别转换为 ZonedDateTime。 OffsetDateTime 与所需的时间偏移。 ZonedDateTime 可帮助您获取给定地区/国家/地区的日期/时间,而 OffsetDateTime 可实现与位置和夏令时无关的纯数字时间偏移。

【讨论】:

  • 不需要DateTimeFormatter 来解析该字符串。 InstantOffsetDateTimeZonedDateTime 都可以原生解析。
  • 只是一个细节,它是Instant.atOffsetjava.timewith开头的方法再次返回相同的类型,例如Instant.with()返回一个Instant)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 2013-09-08
  • 2020-10-21
  • 2018-05-26
相关资源
最近更新 更多