【问题标题】:How to convert UTC DateTime to another Time Zone using Java 8 library?如何使用 Java 8 库将 UTC DateTime 转换为另一个时区?
【发布时间】:2019-06-04 02:59:47
【问题描述】:
final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(
    Instant.ofEpochMilli(rawDateTime.getTime()), zoneId); 
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]

final ZonedDateTime zonedDateTime1 = 
ZonedDateTime.of(rawDateTime.toLocalDateTime(), zoneId);
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]

但我想将转换后的日期时间设为 2031-04-26 00:00:00+5:30,因为我的时间戳值位于 UTC 时区。

请帮忙。

【问题讨论】:

  • 您的代码无法编译。您在第一行缺少分号,“Asia/Calcutta”不是ZoneId,而是String。在发布到 Stack Overflow 之前,请确保您的代码确实执行了您声称的操作。
  • 由于您使用的是现代 Java 日期和时间 API java.time,您应该避免使用 Timestamp 类,它属于现在已被替换的旧类和过时类。请改用Instant(或在特殊情况下使用LocalDateTime)。
  • Java: How do you convert a UTC timestamp to local time? 和许多其他问题的可能重复。请搜索并找到。

标签: java datetime java-8


【解决方案1】:

使用 DateTimeFormatter 格式化 ZonedDateTime:

    final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
    final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
    final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(
            Instant.ofEpochMilli(rawDateTime.getTime()), zoneId);
    // here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[XXX]");
    System.out.println(formatter.format(zonedDateTime));

    final ZonedDateTime zonedDateTime1 =
            ZonedDateTime.of(rawDateTime.toLocalDateTime(), zoneId);
    // here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]
    System.out.println(formatter.format(zonedDateTime1));

输出:

2031-04-25 23:00:00+05:30
2031-04-25 18:30:00+05:30

已编辑:根据@Ole V.V. 的评论。 - 在应用格式之前,必须将本地日期时间转换为 zonedatetime :

 final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
        LocalDateTime ldt = rawDateTime.toLocalDateTime();
        final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
        ZonedDateTime zdt = ldt.atZone(ZoneId.of("UTC"))
                .withZoneSameInstant(zoneId);


        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[XXX]");
        System.out.println(formatter.format(zdt));

这将给出输出:

2031-04-26 00:00:00+5:30

【讨论】:

  • 对,localdate时间需要转换为请求时区的时区日期时间。已编辑,谢谢。它应该给出所需的结果。
【解决方案2】:

使用 OffsetDateTime 代替具有(超)国家标准(如日间节省)的命名区域的 ZonedDateTime。

OffsetDateTime utc = OffsetDateTime.parse("2031-04-25T18:30:00Z");
OffsetDateTime asia = utc.withOffsetSameInstant(ZoneOffset.ofHoursMinutes(5, 30));

默认解析为 ISO 格式。

  • Z 表示零,UTC,+0:00。
  • 生成的默认格式为2031-04-26T00:00+05:30

Ole V.V. 评论后

如果涉及夏令时,上述内容尤其容易出错,例如在中欧时间,偏移量为 +1:00 和 +2:00。

Instant raw = Instant.parse("2031-04-25T18:30:00Z");
ZonedDateTime zoned = raw.atZone(ZoneId.of("Asia/Calcutta"));
OffsetDateTime offset = OffsetDateTime.from(zoned);

【讨论】:

  • 不太推荐。虽然Asia/Calcutta 说明了为什么需要 +05:30 的偏移量,但 ZoneOffset.ofHoursMinutes(5, 30) 没有。如果有一天印度议会决定从 UTC 移到整小时或引入夏令时 (DST),后者将会中断(在这种特殊情况下风险可能不大,但通常使用区域 ID 更好练习;其他区域确实会更频繁地更改偏移量)。
  • @OleV.V.我同意,但需要抵消,而且不是亚洲/加尔各答。出于这个原因,我提到了差异,即“国家标准”和 DST。但是 OffsetDateTime 确实会丢失有价值的信息。 OP 想要一个表示为印度偏移量的 UTC 日期。对于夏季时间的 CET,我会通过 ZoneId。
  • Instant 不会解析 '2031-04-25 18:30:00' 形式的字符串,首先需要 DateTimeFormatter 或 LocalDate.parse 来创建 Instant。
  • @user1653941 是的。 ISO 规定了 T 而不是 time 部分前面的空格。对于默认解析。
【解决方案3】:

首先,您不应该使用Timestamp。可以使用DateTimeFormatter解析成LocalDateTime

然后,您将 LocalDateTime 区域划分为 UTC,然后使用 ZonedDateTime.withZoneSameInstant 转换为加尔各答区域。

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .append(DateTimeFormatter.ISO_LOCAL_DATE)
    .appendLiteral(' ')
    .append(DateTimeFormatter.ISO_LOCAL_TIME)
    .toFormatter();

LocalDateTime localDateTime = LocalDateTime.parse("2031-04-25 18:30:00", formatter);
ZoneId calcuttaZone = ZoneId.of("Asia/Calcutta");
ZonedDateTime calcuttaZonedDateTime = localDateTime.atZone(ZoneOffset.UTC)
    .withZoneSameInstant(calcuttaZone);

【讨论】:

  • DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[XXX]").format(calcuttaZonedDateTime ) 应该给出格式化的日期 - 即 2031-04-26 00:00:在这种情况下为 00+5:30。
猜你喜欢
  • 2011-02-02
  • 2011-02-11
  • 2015-10-16
  • 2016-11-21
  • 1970-01-01
  • 2023-03-23
  • 2014-12-05
  • 2012-08-06
  • 2021-02-14
相关资源
最近更新 更多