使用 ZonedDateTime 解析日期时出现 DateTimeParseException
DateTimeParseException while parsing date using ZonedDateTime
我有以下程序,看起来 ZonedDateTime 无法解析日期字符串。我应该使用不同的日期格式还是不同的库来解析?
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
class Scratch {
public static void main(String[] args) {
final String inputDate = "2022-03-12T03:59:59+0000Z";
ZonedDateTime.parse(inputDate, DateTimeFormatter.ISO_DATE_TIME).toEpochSecond();
}
}
Exception in thread "main" java.time.format.DateTimeParseException: Text '2022-03-12T03:59:59+0000Z' could not be parsed, unparsed text found at index 19
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2053)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:599)
at Scratch.main(scratch_29.java:7)
Process finished with exit code 1
这不是 ISO_DATE_TIME 格式。这将需要类似 2022-03-12T03:59:59+0000
的东西(没有 'Z')。有效的格式化程序类似于:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
class Scratch {
public static void main(String[] args) {
final String inputDate = "2022-03-12T03:59:59+0000Z";
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart()
.appendPattern(".SSS")
.optionalEnd()
.optionalStart()
.appendZoneOrOffsetId()
.optionalEnd()
.optionalStart()
.appendOffset("+HHMM", "0000")
.optionalEnd()
.optionalStart()
.appendLiteral('Z')
.optionalEnd()
.toFormatter();
long epochSecond = ZonedDateTime.parse(inputDate, formatter).toEpochSecond();
System.out.println("epochSecond is " + epochSecond);
}
}
源自 。您可以在一个地方创建该格式化程序并再次使用它。
tl;博士
您的输入恰好是 java.time.Instant
class 默认使用的标准 IS0 8601 格式的变体。修复您的输入字符串,然后解析。
Instant.parse( "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) )
或者,重新格式化:
Instant.parse
(
"2022-03-12T03:59:59+0000Z"
.replace( "+0000Z" , "Z" )
)
在 IdeOne.com 查看此代码 运行。
2022-03-12T03:59:59Z
但最好的解决方案是在交换 date-time 值时仅使用 ISO 8601 格式。
详情
ZonedDateTime
这里不合适
ZonedDateTime
是您输入的错误 class。您的输入有一个 Z
,它是零 hours-minutes-seconds 与 UTC 的偏移量的标准缩写。但没有指明时区,只是一个偏移量。所以使用 OffsetDateTime
或 Instant
而不是 ZonedDateTime
.
+0000
和 Z
多余
+0000
也表示偏移量为零 hours-minutes-seconds。这与 Z
的含义相同。所以这部分是多余的。我建议您对数据的发布者进行有关标准 ISO 8601 格式的培训。无需发明输入中看到的格式。
字符串操作而不是自定义格式化程序
如果您的所有输入都具有相同的 +0000Z
结尾,我建议您清理传入数据而不是定义格式模式。
String input = "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) ;
Instant instant = Instant.parse( input ) ;
其他格式
你以后:
"2017-01-04T12:30:00-05:00" , "2017-03-20T22:05:00Z", etc. So I cannot assume all my inputs to have the same ending of +0000Z.
这两种格式都是标准的 ISO 8601 格式。两者都可以解析为 OffsetDateTime
对象 as-is,无需更改。
所以我仍然认为最简单的方法是,考虑到您可能的输入范围,首先进行 replace
字符串操作,如果您的其他两种格式到达,这将不起作用。然后将所有三个变体解析为 OffsetDateTime
个对象。有时程序员倾向于 over-think 一个问题,over-engineer 一个复杂的解决方案,一个简单的解决方案就足够了。
示例代码:
OffsetDateTime odt1 = OffsetDateTime.parse( "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) ) ;
OffsetDateTime odt2 = OffsetDateTime.parse( "2017-01-04T12:30:00-05:00".replace( "+0000Z" , "Z" ) ) ;
OffsetDateTime odt3 = OffsetDateTime.parse( "2017-03-20T22:05:00Z".replace( "+0000Z" , "Z" ) ) ;
2022-03-12T03:59:59Z
2017-01-04T12:30-05:00
2017-03-20T22:05Z
看到这个code run live at IdeOne.com。
解析时陷入 DateTimeParseException
以检测另一种意外格式。
当然,最好的解决方案是教育您的数据发布者一致使用 ISO 8601 格式,例如后两个示例,同时避免第一个示例的古怪格式.
从纪元开始计数
我建议不要将时间跟踪为 count-since-epoch。这样的计数本质上是模棱两可的 error-prone。相反,请使用标准 ISO 8601 格式的文本。但如果你坚持要数的话,就在这里。
要计算自 1970-01-01T00:00Z 纪元参考以来的秒数,从 OffsetDateTime
中提取 Instant
并查询。
long secondsSinceEpoch = odt.toInstant().getEpochSecond() ;
我有以下程序,看起来 ZonedDateTime 无法解析日期字符串。我应该使用不同的日期格式还是不同的库来解析?
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
class Scratch {
public static void main(String[] args) {
final String inputDate = "2022-03-12T03:59:59+0000Z";
ZonedDateTime.parse(inputDate, DateTimeFormatter.ISO_DATE_TIME).toEpochSecond();
}
}
Exception in thread "main" java.time.format.DateTimeParseException: Text '2022-03-12T03:59:59+0000Z' could not be parsed, unparsed text found at index 19
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2053)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:599)
at Scratch.main(scratch_29.java:7)
Process finished with exit code 1
这不是 ISO_DATE_TIME 格式。这将需要类似 2022-03-12T03:59:59+0000
的东西(没有 'Z')。有效的格式化程序类似于:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
class Scratch {
public static void main(String[] args) {
final String inputDate = "2022-03-12T03:59:59+0000Z";
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart()
.appendPattern(".SSS")
.optionalEnd()
.optionalStart()
.appendZoneOrOffsetId()
.optionalEnd()
.optionalStart()
.appendOffset("+HHMM", "0000")
.optionalEnd()
.optionalStart()
.appendLiteral('Z')
.optionalEnd()
.toFormatter();
long epochSecond = ZonedDateTime.parse(inputDate, formatter).toEpochSecond();
System.out.println("epochSecond is " + epochSecond);
}
}
源自
tl;博士
您的输入恰好是 java.time.Instant
class 默认使用的标准 IS0 8601 格式的变体。修复您的输入字符串,然后解析。
Instant.parse( "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) )
或者,重新格式化:
Instant.parse
(
"2022-03-12T03:59:59+0000Z"
.replace( "+0000Z" , "Z" )
)
在 IdeOne.com 查看此代码 运行。
2022-03-12T03:59:59Z
但最好的解决方案是在交换 date-time 值时仅使用 ISO 8601 格式。
详情
ZonedDateTime
这里不合适
ZonedDateTime
是您输入的错误 class。您的输入有一个 Z
,它是零 hours-minutes-seconds 与 UTC 的偏移量的标准缩写。但没有指明时区,只是一个偏移量。所以使用 OffsetDateTime
或 Instant
而不是 ZonedDateTime
.
+0000
和 Z
多余
+0000
也表示偏移量为零 hours-minutes-seconds。这与 Z
的含义相同。所以这部分是多余的。我建议您对数据的发布者进行有关标准 ISO 8601 格式的培训。无需发明输入中看到的格式。
字符串操作而不是自定义格式化程序
如果您的所有输入都具有相同的 +0000Z
结尾,我建议您清理传入数据而不是定义格式模式。
String input = "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) ;
Instant instant = Instant.parse( input ) ;
其他格式
你以后
"2017-01-04T12:30:00-05:00" , "2017-03-20T22:05:00Z", etc. So I cannot assume all my inputs to have the same ending of +0000Z.
这两种格式都是标准的 ISO 8601 格式。两者都可以解析为 OffsetDateTime
对象 as-is,无需更改。
所以我仍然认为最简单的方法是,考虑到您可能的输入范围,首先进行 replace
字符串操作,如果您的其他两种格式到达,这将不起作用。然后将所有三个变体解析为 OffsetDateTime
个对象。有时程序员倾向于 over-think 一个问题,over-engineer 一个复杂的解决方案,一个简单的解决方案就足够了。
示例代码:
OffsetDateTime odt1 = OffsetDateTime.parse( "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) ) ;
OffsetDateTime odt2 = OffsetDateTime.parse( "2017-01-04T12:30:00-05:00".replace( "+0000Z" , "Z" ) ) ;
OffsetDateTime odt3 = OffsetDateTime.parse( "2017-03-20T22:05:00Z".replace( "+0000Z" , "Z" ) ) ;
2022-03-12T03:59:59Z
2017-01-04T12:30-05:00
2017-03-20T22:05Z
看到这个code run live at IdeOne.com。
解析时陷入 DateTimeParseException
以检测另一种意外格式。
当然,最好的解决方案是教育您的数据发布者一致使用 ISO 8601 格式,例如后两个示例,同时避免第一个示例的古怪格式.
从纪元开始计数
我建议不要将时间跟踪为 count-since-epoch。这样的计数本质上是模棱两可的 error-prone。相反,请使用标准 ISO 8601 格式的文本。但如果你坚持要数的话,就在这里。
要计算自 1970-01-01T00:00Z 纪元参考以来的秒数,从 OffsetDateTime
中提取 Instant
并查询。
long secondsSinceEpoch = odt.toInstant().getEpochSecond() ;