解析 RSS 订阅时间时出现了 DateTimeFormatter 错误。

huangapple go评论74阅读模式
英文:

Error parsing RSS Feed Time with DateTimeFormatter

问题

我分别使用SimpleDateFormatDateTimeFormatter来解析:

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

Java DateTimeFormatter的文档中:

偏移 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.

huangapple
  • 本文由 发表于 2023年3月7日 16:41:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/75659665.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定