在Java中将字符串转换为OffsetDateTime

20

我试图将一个字符串转换为OffsetDateTime,但是出现了以下错误。

java.time.format.DateTimeParseException: 无法解析文本“20150101”:无法从TemporalAccessor获取OffsetDateTime:{},ISO解析为类型为java.time.format.Parsed的2015-01-01

代码:OffsetDateTime.parse("20150101", DateTimeFormatter.ofPattern("yyyyMMdd"));

期望输出:带有日期20150101的OffsetDateTime对象。

如果您能提供任何帮助,我将非常感激。

谢谢。


您的字符串日期格式与模式不同。难道您不应该使用“yyyyMMdd”格式吗? - tsolakp
抱歉打错字了,我已经更新了我的问题。我只传递了“yyyyMMdd”,但是却出现了上述错误。 - Shashwat Shekhar Shukla
我认为你的日期和格式化程序也必须像这样指定偏移量:date: 2007-12-03T10:15:30+01:00。请注意加号后面的部分。 - tsolakp
5个回答

14

OffsetDateTime表示带有偏移的日期时间,例如:

2007-12-03T10:15:30+01:00

您要解析的文本不符合OffsetDateTime的要求。请参见https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html

被解析的字符串既不包含ZoneOffset也不包含时间。从字符串和格式化程序的模式来看,似乎您只需要一个LocalDate。所以,您可以使用:

LocalDate.parse("20150101", DateTimeFormatter.ofPattern("yyyyMMdd"));

4

感谢大家的回复。

之前我使用了joda日期时间库(请查看下面的方法)来处理日期和日期时间,但我想使用Java8库来替代外部库。

static public DateTime convertStringInDateFormat(String date, String dateFormat){
    DateTimeFormatter formatter = DateTimeFormat.forPattern(dateFormat);
return formatter.parseDateTime(date);
}

我原本期望可以使用OffsetDateTime,但是后来发现如果需要操作某个特定时区的日期/时间,我们可以使用ZonedDateTime或OffsetDateTime。

由于我正在处理Period和Duration,因此可以使用LocalDate。

将字符串转换为日期时间:

LocalDate date =
LocalDate.parse("20150101", DateTimeFormatter.ofPattern("yyyyMMdd"));

将LocalDate转换为所需的字符串格式:

String dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'";
date.atStartOfDay().format(DateTimeFormatter.ofPattern(dateFormat));

2
正确的理解。提示:在最后一行,我建议始终向atStartOfDay调用传递一个显式的ZoneId。例如:.atStartOfDay(ZoneId.of(“Africa / Lagos”))否则,您将隐式获取JVM当前默认时区。最好明确您所需/期望的时区。而且,该默认值可以在运行时的任何时刻由JVM中的任何代码更改,因此默认值不可靠。例如,根据您在问题中提到的内容,您将获得芝加哥日的开始,而不是拉各斯日的开始。 - Basil Bourque
另外需要注意的是,LocalDate 适用于 Period,因为该类表示以年、月、日为粒度的时间跨度。但是,Duration 是指总秒数加上纳秒分数的时间跨度。因此,Duration 适用于日期时间值,例如 InstantOffsetDateTimeZonedDateTime,而不适用于仅包含日期的 LocalDate - Basil Bourque

2

正如Pallavi所说,OffsetDateTime只在偏移量的上下文中使用。因此,要从日期字符串转换为OffsetDateTime,您需要一个时区!

以下是步骤。找到一个时区,如UTC或其他。

ZoneId zoneId = ZoneId.of("UTC");   // Or another geographic: Europe/Paris
ZoneId defaultZone = ZoneId.systemDefault();

让LocalDateTime与LocalDate一样工作。

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");    
LocalDateTime dateTime = LocalDateTime.parse("2022-01-28T14:29:10.212", formatter);

偏移量只有在时区和时间存在时才有意义。例如,东部时间根据一年中的时间而变化,在GMT-4和GMT-5之间浮动。

ZoneOffset offset = zoneId.getRules().getOffset(dateTime);

最后,你可以根据时间和偏移量创建OffsetDateTime:

OffsetDateTime offsetDateTime = OffsetDateTime.of(dateTime, offset);

希望这能帮助到任何人。

2

Z 不是字面意思

接受的答案存在一个严重问题:它在模式中使用了字面上的'Z'来指定UTC偏移量。 'Z'只是一个字符字面量,而Z是零时区偏移的时区标识符。它代表Zulu,并指定UTC偏移量(+00:00小时)。请查看'Z'Z不同以了解更多信息。

DateTimeFormatter.ofPattern( "yyyy-MM-dd'T'HH:mm:ssZ" )  // Z is a formatting code, not a string literal.

DateTimeFormatter.BASIC_ISO_DATE

除此之外,解析代码可以通过使用预定义的格式化方式DateTimeFormatter#BASIC_ISO_DATE进行改进。

LocalDate.parse("20150101", DateTimeFormatter.BASIC_ISO_DATE)

指定时区

此外,应始终明确指定时区。否则,JVM将使用系统的默认时区,这是许多开发人员面临的常见问题。

演示:

class Main {
    public static void main(String[] args) {
        LocalDate date = LocalDate.parse("20150101", DateTimeFormatter.BASIC_ISO_DATE);

        // Convert date into a ZonedDateTime at the start of the day in the 
        // desired timezone e.g. ZoneId.of("Etc/UTC")
        ZonedDateTime zdt = date.atStartOfDay(ZoneId.of("Etc/UTC"));

        // Convert the obtained ZonedDateTime into an OffsetDateTime
        OffsetDateTime odt = zdt.toOffsetDateTime();
        System.out.println(odt);
    }
}

输出:

2015-01-01T00:00Z

在线演示

教程:日期时间了解现代日期时间 API


也许最好使用ZoneOffset.UTC常量而不是ZoneId.of("Etc/UTC")。或者选择一些任意的时区作为示例。 - Basil Bourque
感谢@BasilBourque提供的宝贵修改意见和使用ZoneOffset.UTC的建议。我在我的IDE中编写了代码,使用了ZoneOffset.UTC,但在发布答案之前将其更改为ZoneId.of("Etc/UTC")。我这样做的原因是因为许多开发人员没有意识到ZoneOffset扩展了ZoneId,并且在LocalDate#atStartOfDay(ZoneId)中与ZoneId混淆。 - Arvind Kumar Avinash

1

如果您只想解析日期(没有时间/偏移),请使用LocalDate而不是OffsetDateTime。关于OffsetDateTime的用法已经在这里进行了广泛讨论。


2
你可以使用 atStartOfDay().atOffset(yourDesiredOffset) 来将其转换为 OffsetDateTime。偏移量可以是例如 ZoneOffset.UTC。日期和时间类通常会强制你明确你想要的内容,而不是给你可能不符合你需求的默认值,这是一件好事。 - Ole V.V.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接