【问题标题】:Parsing RFC 2822 date in JAVA在 JAVA 中解析 RFC 2822 日期
【发布时间】:2011-01-28 08:21:20
【问题描述】:

我需要在 Java 中解析日期的 RFC 2822 字符串表示。示例字符串在这里:

2010 年 3 月 13 日星期六 11:29:05 -0800

它看起来很糟糕,所以我想确保我做的一切都是正确的,并且稍后会遇到奇怪的问题,因为通过 AM-PM/军事时间问题、UTC 时间问题、我不知道的问题来解释错误的日期预测等等……

谢谢!

【问题讨论】:

  • 您是否尝试过使用java.text.SimpleDateFormat
  • 这看起来很适合使用,我也担心正确的格式字符串是什么,看起来很容易搞砸。这似乎是 RFC 2822 的正确字符串:“EEE, d MMM yyyy HH:mm:ss Z”(根据下面的答案)
  • 这太疯狂了,我从 SimpleDateFormat 官方页面上删除了它。他们的示例在技术上是正确的,但仍然是错误的:java.sun.com/j2se/1.4.2/docs/api/java/text/… 感谢您提醒我,这就是我的代码中的内容。
  • 标准来源:Internet Message Format,向下滚动到 3.3 部分。日期和时间规范.

标签: java date parsing rfc2822


【解决方案1】:

DateTimeFormatter.RFC_1123_DATE_TIME

自从 Java 8 实现了新的日期时间类:java.time.ZonedDateTimejava.time.LocalDateTimeZonedDateTime 支持解析几乎开箱即用的 RFC 字符串:

String rfcDate = "Tue, 4 Dec 2018 17:37:31 +0100 (CET)";  
if (rfcDate.matches(".*[ ]\\(\\w\\w\\w\\)$")) {
    //Brackets with time zone are added sometimes, for example by JavaMail
    //This must be removed before parsing
    //from: "Tue, 4 Dec 2018 17:37:31 +0100 (CET)"
    //  to: "Tue, 4 Dec 2018 17:37:31 +0100"
    rfcDate = rfcDate.substring(0, rfcDate.length() - 6);
}

//and now parsing... 
DateTimeFormatter dateFormat = DateTimeFormatter.RFC_1123_DATE_TIME;
try {
    ZonedDateTime zoned = ZonedDateTime.parse(rfcDate, dateFormat);
    LocalDateTime local = zoned.toLocalDateTime();        
} catch (DateTimeParseException e) { ... }

【讨论】:

  • 解析的好答案。但我不建议将ZonedDateTime 转换为LocalDateTime。这样一来,您就放弃了有价值的信息,即时区,而没有任何收获作为回报。就像没有特定货币上下文的金额一样,LocalDateTime 是模棱两可的,因此不能代表片刻。
【解决方案2】:

有一个执行 RFC-2822 日期解析的 javax.mail 类:

javax.mail.internet.MailDateFormat

包括可选和过时的格式。

只要做:

new javax.mail.internet.MailDateFormat().parse("Sat, 13 Mar 2010 11:29:00 -0800")
new javax.mail.internet.MailDateFormat().parse("13 Mar 2010 11:29:00 -0800")
new javax.mail.internet.MailDateFormat().parse("13 Mar 2010 11:29 -0800")

它将正确解析这些有效的 RFC-2822 日期

至于其他旧的 DateFormatter,MailDateFormat 类不是线程安全的。

【讨论】:

    【解决方案3】:

    这是执行您所要求的快速代码(使用 SimpleDateFormat

    String rfcDate = "Sat, 13 Mar 2010 11:29:05 -0800";
    String pattern = "EEE, dd MMM yyyy HH:mm:ss Z";
    SimpleDateFormat format = new SimpleDateFormat(pattern);
    Date javaDate = format.parse(rfcDate);
    
    //Done.
    

    PS。我这里没有处理异常和并发(因为 SimpleDateFormat 在解析日期时不同步)。

    【讨论】:

    【解决方案4】:

    请记住,[day-of-week ","] 在 RFC-2822 中是可选的,因此建议的示例并未涵盖所有 RFC-2822 日期格式。此外,RFC-822 日期类型允许许多不同的时区表示法(obs-zone),“Z”格式说明符未涵盖这些符号。

    我想没有简单的出路,除了寻找“,”和“-|+”来确定使用哪种模式。

    【讨论】:

    • +1 指出星期几是可选的。我正在设置一个包含各种模式的 try/catch 瀑布,以不断尝试变化,直到找到可行的变化。
    • 不仅day-of-week 是可选的,一天中的秒数也被声明为可选:time-of-day = hour ":" minute [ ":" second ]
    【解决方案5】:

    如果您的应用程序使用的是英语以外的其他语言,您可能希望通过使用备用 SimpleDateFormat 构造函数来强制日期解析/格式化的语言环境:

    String pattern = "EEE, dd MMM yyyy HH:mm:ss Z";
    SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.ENGLISH);
    

    【讨论】:

    • 绝对需要设置区域设置。 Locale 的 android javadoc 建议使用 Locale.US 进行计算机到计算机的通信。 link
    • +1 Locale.ROOT 也是一个不错的选择,但并非在所有系统上都可用。
    • @jasongilbert 你能解释一下为什么你说语言环境“绝对是必需的”吗?根据文档,它不是:docs.oracle.com/javase/7/docs/api/java/text/…——但也许你的意思是“如果……是必需的”,它是我感兴趣的“如果”的延续……
    • @AdamTuttle 如果您希望在默认语言环境不是美国英语时正确解析日期,则需要它。例如,如果用户在德国,则无法使用其默认区域设置正确解析日期。
    猜你喜欢
    • 2010-10-27
    • 2012-12-08
    • 2013-09-01
    • 2020-01-13
    • 2012-01-28
    • 2011-03-28
    • 1970-01-01
    • 2013-05-15
    • 2011-08-27
    相关资源
    最近更新 更多