英文:
Error parsing RSS Feed Time with DateTimeFormatter
问题
我分别使用SimpleDateFormat
和DateTimeFormatter
来解析:
val text = "Tue, 07 Mar 2023 15:32:23 +0800"
val pattern = "EEE, dd MMM yyyy HH:mm:ss zzz"
val date = SimpleDateFormat(pattern, Locale.ENGLISH).parse(text)
println(date)
val dateTime = LocalDateTime.parse(text, DateTimeFormatter.ofPattern(pattern, Locale.ENGLISH))
println(dateTime)
但DateTimeFormatter
出现了错误:
java.time.format.DateTimeParseException:
在索引26处无法解析文本'Tue, 07 Mar 2023 15:32:23 +0800'
我知道可以使用内置类型DateTimeFormatter.RFC_1123_DATE_TIME
成功解析它。但我想知道这个模式有什么问题?为什么DateTimeFormatter
出错?
我找到了一个相关的问题,但与我的情况不同,他的时区是GMT
,而我的是+0800
。
英文:
I used SimpleDateFormat
and DateTimeFormatter
respectively to parse:
val text = "Tue, 07 Mar 2023 15:32:23 +0800"
val pattern = "EEE, dd MMM yyyy HH:mm:ss zzz"
val date = SimpleDateFormat(pattern, Locale.ENGLISH).parse(text)
println(date)
val dateTime = LocalDateTime.parse(text, DateTimeFormatter.ofPattern(pattern, Locale.ENGLISH))
println(dateTime)
But DateTimeFormatter
got an error:
java.time.format.DateTimeParseException:
Text 'Tue, 07 Mar 2023 15:32:23 +0800' could not be parsed at index 26
I know it can be successfully parsed using the built-in type DateTimeFormatter.RFC_1123_DATE_TIME
.
But I want to know where is the problem with this pattern? Why does DateTimeFormatter
go wrong?
I found a related question, but it's not the same as mine, his timezone is GMT
, mine is +0800
答案1
得分: 2
+0800
不是一个时区,而是与UTC的偏移。
DateTimeFormatter
区分时区(ZoneId
)和偏移(ZoneOffset
),支持不同的模式字符,这就是为什么它拒绝解析你的text
的原因...
我会解析一个包含与UTC的偏移的String
,而不是LocalDateTime
,因为后者会剥离关于偏移的信息,只保留日期和一天中的时间。但这显然取决于具体的要求...
这意味着如果你想使用DateTimeFormatter
解析此输入String
,你将不得不引入不同的模式。
你可以在该模式中使用xxxx
而不是 zzz
(其余部分保持不变,但最好使用 uuuu
而不是 yyyy
)。
fun main() {
// 输入的字符串
val text = "Tue, 07 Mar 2023 15:32:23 +0800"
// SimpleDateFormat的模式
val patternSdf = "EEE, dd MMM yyyy HH:mm:ss zzz"
// DateTimeFormatter的模式
val patternDtf = "EEE, dd MMM yyyy HH:mm:ss xxxx"
// 使用SimpleDateFormat解析字符串获得java.util.Date
val date = SimpleDateFormat(patternSdf, Locale.ENGLISH).parse(text)
// 打印日期
println(date)
// 使用DateTimeFormatter解析字符串获得LocalDateTime
val dateTime = LocalDateTime.parse(
text,
DateTimeFormatter.ofPattern(patternDtf, Locale.ENGLISH)
)
// 打印它
println(dateTime);
// 使用相同的方法获得OffsetDateTime
val offsetDateTime = OffsetDateTime.parse(
text,
DateTimeFormatter.ofPattern(patternDtf, Locale.ENGLISH)
)
// 打印它
println(offsetDateTime)
}
输出:
Tue Mar 07 07:32:23 UTC 2023
2023-03-07T15:32:23
2023-03-07T15:32:23+08:00
偏移 X 和 x:
这基于模式字母的数量格式化偏移。一个字母仅输出小时,例如 '+01',除非分钟不为零,在这种情况下还会输出分钟,例如 '+0130'。两个字母输出小时和分钟,没有冒号,例如 '+0130'。三个字母输出小时和分钟,带有冒号,例如 '+01:30'。四个字母输出小时和分钟以及可选的秒,没有冒号,例如 '+013015'。五个字母输出小时和分钟以及可选的秒,带有冒号,例如 '+01:30:15'。六个或更多字母会引发IllegalArgumentException异常。模式字母 'X'(大写)将在要输出的偏移为零时输出 'Z',而模式字母 'x'(小写)将输出 '+00'、'+0000'或'+00:00'。
偏移 Z:
这基于模式字母的数量格式化偏移。一个、两个或三个字母输出小时和分钟,没有冒号,例如 '+0130'。当偏移为零时,输出将是 '+0000'。四个字母输出本地化偏移的完整形式,相当于Offset-O的四个字母。如果偏移为零,输出将是相应的本地化偏移文本。五个字母输出小时、分钟,如果不为零还会输出可选的秒,带有冒号。如果偏移为零,输出将是 'Z'。六个或更多字母将引发IllegalArgumentException异常。
英文:
+0800
is not a time zone, it is an offset from UTC.
A DateTimeFormatter
distingishes between zone (ZoneId
) and offset (ZoneOffset
) and supports different pattern characters that's why it refuses to parse your text
…
I would parse a String
that contains an offset from UTC to an OffsetDateTime
instead of a LocalDateTime
, because the latter would strip off the information about the offset and simply keep a date and a time of day. But that obviously depends on the specific requirements…
That means you will have to introduce a different pattern if you want to parse this input String
with a DateTimeFormatter
.
You could use xxxx
instead of zzz
in that pattern (the rest stays the same, but better use uuuu
instead of yyyy
).
fun main() {
// input String
val text = "Tue, 07 Mar 2023 15:32:23 +0800"
// pattern for the SimpleDateFormat
val patternSdf = "EEE, dd MMM yyyy HH:mm:ss zzz"
// pattern for the DateTimeFormatter
val patternDtf = "EEE, dd MMM yyyy HH:mm:ss xxxx"
// get a java.util.Date by parsing the String with the SimpleDateFormat
val date = SimpleDateFormat(patternSdf, Locale.ENGLISH).parse(text)
// print the Date
println(date)
// get a LocalDateTime by parsing the String with the DateTimeFormatter
val dateTime = LocalDateTime.parse(
text,
DateTimeFormatter.ofPattern(patternDtf, Locale.ENGLISH)
)
// print it
println(dateTime);
// get an OffsetDateTime using the same approach
val offsetDateTime = OffsetDateTime.parse(
text,
DateTimeFormatter.ofPattern(patternDtf, Locale.ENGLISH)
)
// print it
println(offsetDateTime)
}
Output:
Tue Mar 07 07:32:23 UTC 2023
2023-03-07T15:32:23
2023-03-07T15:32:23+08:00
From JavaDocs of DateTimeFormatter
:
>Offset X and x:
This formats the offset based on the number of pattern letters. One letter outputs just the hour, such as '+01', unless the minute is non-zero in which case the minute is also output, such as '+0130'. Two letters outputs the hour and minute, without a colon, such as '+0130'. Three letters outputs the hour and minute, with a colon, such as '+01:30'. Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'. Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'. Six or more letters throws IllegalArgumentException. Pattern letter 'X' (upper case) will output 'Z' when the offset to be output would be zero, whereas pattern letter 'x' (lower case) will output '+00', '+0000', or '+00:00'.
> Offset Z:
This formats the offset based on the number of pattern letters. One, two or three letters outputs the hour and minute, without a colon, such as '+0130'. The output will be '+0000' when the offset is zero. Four letters outputs the full form of localized offset, equivalent to four letters of Offset-O. The output will be the corresponding localized offset text if the offset is zero. Five letters outputs the hour, minute, with optional second if non-zero, with colon. It outputs 'Z' if the offset is zero. Six or more letters throws IllegalArgumentException.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论