【问题标题】:joda-time ISODateTimeFormat.dateTime() misbehavingjoda-time ISODateTimeFormat.dateTime() 行为不端
【发布时间】:2021-03-03 04:53:07
【问题描述】:

ISODateTimeFormat.dateTime() 应该是宽大灵活的。例如。毫秒是可选的,日期是可选的,时区是可选的,时区可以是Z 或+/- HH[:MM]

但事实并非如此。我错过了什么?

使用版本joda-time:2.9.9(也尝试了2.10.8,结果相同)

import org.joda.time.format.ISODateTimeFormat;
import java.util.Arrays;

public static void main(String[] args) {
    Arrays.asList("2020-11-22T01:59:59.001+00:00", "2020-11-22T01:59:59.001Z", "2020-11-22T01:59:59+00:00",
        "2020-11-22T01:59:59Z", "01:59:59").forEach(s -> {
        try {
            System.out.println(String.format("%-30s -- %s", s, ISODateTimeFormat.dateTime().parseDateTime(s)));
        } catch (Exception e) {
            System.out.println(String.format("%-30s -- %s", s, e.getMessage()));
        }
    });
}

输出:

2020-11-22T01:59:59.001+00:00  -- 2020-11-22T01:59:59.001Z
2020-11-22T01:59:59.001Z       -- 2020-11-22T01:59:59.001Z
2020-11-22T01:59:59+00:00      -- Invalid format: "2020-11-22T01:59:59+00:00" is malformed at "+00:00"
2020-11-22T01:59:59Z           -- Invalid format: "2020-11-22T01:59:59Z" is malformed at "Z"
01:59:59.000                   -- Invalid format: "01:59:59.000" is malformed at ":59:59.000"

javadoc:

public static DateTimeFormatter dateTimeParser()

Returns a generic ISO datetime parser which parses either a date or a time or both.

The returned formatter can only be used for parsing, printing is unsupported.

The parser is strict by default, thus time string 24:00 cannot be parsed.

It accepts formats described by the following syntax:

 datetime          = time | date-opt-time
 time              = 'T' time-element [offset]
 date-opt-time     = date-element ['T' [time-element] [offset]]
 date-element      = std-date-element | ord-date-element | week-date-element
 std-date-element  = yyyy ['-' MM ['-' dd]]
 ord-date-element  = yyyy ['-' DDD]
 week-date-element = xxxx '-W' ww ['-' e]
 time-element      = HH [minute-element] | [fraction]
 minute-element    = ':' mm [second-element] | [fraction]
 second-element    = ':' ss [fraction]
 fraction          = ('.' | ',') digit+
 offset            = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])
 

【问题讨论】:

  • 您正在链接到 dateTimeParser 的文档,但正在调用 dateTime()。
  • 你用的是什么java版本?如果是 8 或以上,那么joda home page 指示您迁移到 java.time (JSR-310) - JDK 的核心部分,它取代了这个项目
  • @jensgram,是的,这就是问题所在! (-‸ლ)
  • @Abra,所有预定义的formats in DateTimeFormatter 似乎都是STRICT。有没有一些简单的方法来获得像ISODateTimeFormat.dateTimeParser() 这样的 SMART 解析器?
  • DateTimeFormatter.ISO_OFFSET_DATE_TIME.withResolverStyle(ResolverStyle.SMART)?它不完全等同于 Joda-Time 的东西,但它应该是 SMART。

标签: java datetime parsing jodatime datetime-format


【解决方案1】:

java.time

正如 Abra 在评论中建议的那样,您可能希望遵循 Joda-Time 官方建议并继续使用现代 Java 日期和时间 API java.time。

以下内容不会为您提供 Joda-Time 解析器的全部灵活性,但它会解析您的五个示例字符串。而且您可以进一步调整它以满足您可能有的任何进一步需求。

    ZoneOffset defaultOffset = ZoneOffset.UTC; // Configurable
    LocalDate defaultDate = LocalDate.now(ZoneId.systemDefault());
    
    DateTimeFormatter flexibleFormatter = new DateTimeFormatterBuilder()
            .optionalStart()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral('T')
            .optionalEnd()
            .parseDefaulting(ChronoField.YEAR, defaultDate.getYear())
            .parseDefaulting(ChronoField.MONTH_OF_YEAR, defaultDate.getMonthValue())
            .parseDefaulting(ChronoField.DAY_OF_MONTH, defaultDate.getDayOfMonth())
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .optionalStart()
            .appendOffsetId()
            .optionalEnd()
            .parseDefaulting(ChronoField.OFFSET_SECONDS, defaultOffset.getTotalSeconds())
            .toFormatter();

    Arrays.asList("2020-11-22T01:59:59.001+00:00", "2020-11-22T01:59:59.001Z", "2020-11-22T01:59:59+00:00",
            "2020-11-22T01:59:59Z", "01:59:59").forEach(s -> {
            try {
                System.out.println(String.format("%-30s -- %s", s, OffsetDateTime.parse(s, flexibleFormatter)));
            } catch (DateTimeParseException dtpe) {
                System.out.println(String.format("%-30s -- %s", s, dtpe.getMessage()));
            }
        });     

我刚才在欧洲/哥本哈根时区跑步时的输出:

2020-11-22T01:59:59.001+00:00  -- 2020-11-22T01:59:59.001Z
2020-11-22T01:59:59.001Z       -- 2020-11-22T01:59:59.001Z
2020-11-22T01:59:59+00:00      -- 2020-11-22T01:59:59Z
2020-11-22T01:59:59Z           -- 2020-11-22T01:59:59Z
01:59:59                       -- 2020-11-19T01:59:59Z

来自 Joda-Time 主页:

请注意,Joda-Time 被认为是一个基本上“已完成”的项目。 没有计划进行重大改进。如果使用 Java SE 8,请迁移 到java.time (JSR-310)。

你的代码出了什么问题?

jensgram 在评论中已经说过了:

您正在链接到 dateTimeParser 的文档,但正在调用 dateTime()

链接

【讨论】:

  • 谢谢!我现在要坚持使用joda。但希望这会对其他人有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-20
相关资源
最近更新 更多