joda时间ISODateTimeFormat.dateTime()行为不端



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]]])

java.time

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

以下内容不会给您提供JodaTime解析器的全部灵活性,但它确实解析了您的五个示例字符串。而且你可能能够进一步调整它以适应你可能有的任何进一步的需求。

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(。

您的代码出了什么问题

詹格拉姆已经在评论中表示:

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

链接

  • Oracle教程:日期时间,解释如何使用java.Time
  • Joda时间-主页

最新更新