将非 UTC 日期字符串解析为 UTC Instant,并在另一个 TimeZone 中打印出来

问题描述 投票:0回答:3

我正在使用 Java 11.

我有一个日期时间字符串,看起来像这样

“2023-02-17T03:56:50.254”

但我知道它代表UTC时区的一个时间点。

我如何解析这个字符串,考虑到它实际上是 UTC(解析必须独立于我的默认 JVM 时区)?

然后我如何将它转换为另一个代表相同日期/时间的字符串,例如美国/纽约时区?

这里有很多解析示例,但似乎没有一个能完全代表我的情况。

java datetime timezone datetime-parsing datetime-conversion
3个回答
4
投票

首先,将字符串解析为

LocalDateTime
,因为这就是字符串中的全部内容 - 日期和时间。

然后,您可以将其转换为

ZonedDateTime
Instant
,具体取决于您的解释 - 无论这是
UTC
区域中的日期和时间,还是时间点。

var parsedResult =
    LocalDateTime.parse(string/*, DateTimeFormatter.ISO_DATE_TIME*/)
        .toInstant(ZoneOffset.UTC); // for an Instant
//      .atZone(ZoneOffset.UTC); // for a ZonedDateTime

拥有其中任何一个后,您可以分别使用

withZoneSameInstant
/
atZone
将其放入另一个区域。

// if parsedResult is Instant
var atAnotherZone = parsedResult.atZone(anotherZone);
// if parsedResult is ZonedDateTime
var atAnotherZone = parsedResult.withZoneSameInstant(anotherZone);

1
投票

感谢大家的评论和回答。把它们放在一起,我想这就是我需要的。

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Main001 {

    public static void main(String[] args) {
        
        // Do first test with a winter date
        String text = "2023-02-17T03:56:50.254";
                
        LocalDateTime local = LocalDateTime.parse(text);
        ZonedDateTime zdt = local.atZone(ZoneId.of("UTC"));
        Instant instant = zdt.toInstant();
        
        System.out.println(instant);
        
        DateTimeFormatter formatter =
                DateTimeFormatter
                .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
                .withZone(ZoneId.of("America/New_York"));
        
        System.out.println(formatter.format(instant));
        
        // Do second test with a summer date
        text = "2023-07-17T03:56:59.257";
        
        local = LocalDateTime.parse(text);
        zdt = local.atZone(ZoneId.of("UTC"));
        instant = zdt.toInstant();
        
        System.out.println(instant);
        
        formatter =
                DateTimeFormatter
                .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
                .withZone(ZoneId.of("America/New_York"));
        System.out.println(formatter.format(instant));

    }

}

输出:

2023-02-17T03:56:50.254Z
2023-02-16T22:56:50.254
2023-07-17T03:56:59.257Z
2023-07-16T23:56:59.257

0
投票

tl;博士

LocalDateTime                           // Represent a date with time-of-day, but lacking the context of a time zone or offset from UTC.
.parse( "2023-02-17T03:56:50.254" )     // Parse text in standard ISO 8601 format.
.atOffset(                              // Assign an offset to this date-with-time.
    ZoneOffset.UTC                      // Constant for an offset-from-UTC of zero hours-minutes-seconds.
)                                       // Returns an `OffsetDateTime` object.
.atZoneSameInstant(                     // Adjust from a moment as seen with an offset of zero to being seen with a time zone some number of hours-minutes-seconds ahead/behind UTC.
    ZoneId.of( "America/New_York" )     // Represent a time zone. Name is in format of Continent/Region. 
)                                       // Returns a `ZonedDateTime` object.
.toString()                             // Generate text in standard ISO 8601 format extended wisely to append the name of the zone in square brackets.

查看 Ideone.com 上运行的代码。请注意日期和时间与输入的日期和时间有何不同。

2023-02-16T22:56:50.254-05:00[America/New_York]

偏移与区域

根据 Ole V.V.评论,这里适当的类是

OffsetDateTime
而不是
ZonedDateTime

  • 一个offset仅仅是UTC时间子午线之前或之后的数字小时、分钟和秒。
  • 时区是过去、现在和未来对特定地区人民使用的偏移量变化的命名历史,由他们的政治家决定。命名格式为
    Continent/Region
    .

java.time 类提供两个类来表示每个概念:

  • ZoneOffset
  • ZoneId

java.time 类提供了两个类来表示以各种方式看到的时刻。

  • OffsetDateTime
  • ZonedDateTime

顺便说一下,

Instant
类是 java.time 中更基本的构建块类,代表 UTC 中看到的时刻,始终为 UTC(偏移量为零)。

LocalDateTime

所以,是的,将您的输入解析为日期和时间,

LocalDateTime
.

LocalDateTime ldt = LocalDateTime.parse( "2023-02-17T03:56:50.254" ) ;

LocalDateTime
确实not代表一个时刻,因为它缺少偏移量或区域的上下文。

ZoneOffet
&
OffsetDateTime

你说:

我如何解析这个字符串,考虑到它实际上是 UTC

如果您确定日期和时间旨在表示“UTC”时刻,即偏移量为零小时-分钟-秒,则应用

ZoneOffset
而不是
ZoneId
到产生
OffsetDateTime
而不是
ZonedDateTime
.

Java 带有一个为零偏移量定义的常量,

ZoneOffset.UTC
.

OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;

ZoneId
&
ZonedDateTime

你问:

然后我如何将它转换为另一个代表相同日期/时间的字符串,例如美国/纽约时区?

定义您想要的时区。使用

ZoneId
作为区域(
ZoneOffset
仅用于偏移量)。

ZoneId zoneId = ZoneId.of( "America/New_York" ) ;

应用那个时区来产生一个

ZonedDateTime
.

ZonedDateTime zdt = odt.atZoneSameInstant( zoneId ) ;

在这个例子中,

odt
zdt
代表相同的时刻
,时间轴上的相同点。那一刻就是方法名称
atZoneSameInstant
和类
Instant
中的“Instant”的意思。
odt
zdt
变量的挂钟时间和日历不同。就像冰岛雷克雅未克的人打电话给加利福尼亚洛杉矶的人一样——当双方同时看一眼挂在各自墙上的时钟和日历时,他们会看到不同的时间和日期。

相比之下,名为

LocalDateTime
ldt
变量确实not代表一个时刻,not时间轴上的一个点。该类故意缺少时区或偏移量的上下文。所以
LocalDateTime
类不能代表一个时刻。

© www.soinside.com 2019 - 2024. All rights reserved.