我正在使用 Java 11.
我有一个日期时间字符串,看起来像这样
“2023-02-17T03:56:50.254”
但我知道它代表UTC时区的一个时间点。
我如何解析这个字符串,考虑到它实际上是 UTC(解析必须独立于我的默认 JVM 时区)?
然后我如何将它转换为另一个代表相同日期/时间的字符串,例如美国/纽约时区?
这里有很多解析示例,但似乎没有一个能完全代表我的情况。
首先,将字符串解析为
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);
感谢大家的评论和回答。把它们放在一起,我想这就是我需要的。
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
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
。
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
.
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
类不能代表一个时刻。