提问人:peter.petrov 提问时间:4/21/2023 最后编辑:Anonymouspeter.petrov 更新时间:4/29/2023 访问量:297
将非 UTC 日期字符串解析为 UTC Instant,并在另一个时区打印出来
Parse non-UTC date string as UTC Instant, and print it out in another TimeZone
问:
我正在使用 Java 11。
我有一个日期时间字符串,看起来像这样
“2023-02-17T03:56:50.254”
但我知道它代表了 UTC 时区的一个时间点。
考虑到它实际上是 UTC 格式,我如何解析这个字符串(解析必须独立于我的默认 JVM 时区)?
然后我如何将其转换为另一个表示相同日期/时间的字符串,例如美国/纽约时区?
这里有很多解析示例,但似乎没有一个完全代表我的情况。
答:
首先,将字符串解析为 ,因为这就是字符串中的全部内容 - 日期和时间。LocalDateTime
然后,您可以将其转换为 a 或 ,具体取决于您的解释 - 这是区域中的日期和时间,还是时间点。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);
评论
toInstant
ZonedDateTime
.atOffset(ZoneOffset.UTC)
OffsetDateTime
Instant
感谢您的所有评论和回答。把它们放在一起,我认为这就是我需要的。
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
评论
OffsetDateTime odt = local.atOffset(ZoneOffset.UTC);
Instant instant = odt.toInstant();
ZonedDateTime
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
- 偏移量只是 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
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
表示相同的同时时刻,即时间轴上的同一点。那一刻就是方法名称和类中“Instant”的含义。和变量在挂钟时间和日历上有所不同。就像冰岛雷克雅未克的某个人给加利福尼亚州洛杉矶的某个人打电话一样——当双方同时瞥一眼挂在各自墙上的时钟和日历时,他们会看到不同的时间和日期。atZoneSameInstant
Instant
odt
zdt
相反,命名的变量不表示时刻,也不是时间轴上的一个点。该类故意缺少时区或偏移量的上下文。因此,该类不能代表某个时刻。LocalDateTime
ldt
LocalDateTime
上一个:获取两次之间的周期
评论
atZone(ZoneId.systemDefault())