Java 8解析ISO-8601日期忽略时区的存在(或不存在)

sil*_*box 5 datetime iso8601 datetime-parsing java-8 java-time

我的应用程序应该能够解析忽略时区的日期(我总是知道它是UTC).问题是日期可能会出现以下两种形式 -

2017-09-11T12:44:07.793Z

0001-01-01T00:00:00

我可以解析第一个使用LocalDateTime,第二个使用Instant类.有没有办法使用单一机制?

PS我试图避免Z输入字符串末尾的硬编码

小智 6

如果Z偏移是可选的,则可以使用java.time.format.DateTimeFormatterBuilder带可选部分的a:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // date/time
    .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
    // optional offset
    .optionalStart().appendOffsetId()
    // create formatter
    .toFormatter();
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用该parseBest方法,以及TemporalQuery尝试创建对应对象的列表.然后检查返回类型并采取相应措施:

Instant instant = null;
// tries to create Instant, and if it fails, try a LocalDateTime
TemporalAccessor parsed = fmt.parseBest("2017-09-11T12:44:07.793Z", Instant::from, LocalDateTime::from);
if (parsed instanceof Instant) {
    instant = (Instant) parsed;
} else if (parsed instanceof LocalDateTime) {
    // convert LocalDateTime to UTC instant
    instant = ((LocalDateTime) parsed).atOffset(ZoneOffset.UTC).toInstant();
}
System.out.println(instant); // 2017-09-11T12:44:07.793Z
Run Code Online (Sandbox Code Playgroud)

使用第二个输入(0001-01-01T00:00:00)运行产生Instant等效于0001-01-01T00:00:00Z.

另外,在上述的例子中,我只是用Instant::fromLocalDateTime::from,所以格式化试图首先创建一个Instant.如果它不可能,那么它会尝试创建一个LocalDateTime.您可以向该列表添加任意数量的类型(例如,我可以添加ZonedDateTime::from,如果ZonedDateTime创建了一个,我可以转换为Instant使用toInstant()方法).


如您所知,输入始终为UTC,您也可以直接在格式化程序中进行设置:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // date/time
    .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
    // optional offset
    .optionalStart().appendOffsetId()
    // create formatter with UTC
    .toFormatter().withZone(ZoneOffset.UTC);
Run Code Online (Sandbox Code Playgroud)

所以你可以直接解析它Instant:

System.out.println(Instant.from(fmt.parse("2017-09-11T12:44:07.793Z"))); // 2017-09-11T12:44:07.793Z
System.out.println(Instant.from(fmt.parse("0001-01-01T00:00:00"))); // 0001-01-01T00:00:00Z
Run Code Online (Sandbox Code Playgroud)

  • @silent-box,请注意在调用`parseBest`时使用现有的方法引用并不是必须的:你可以编写自己的方法来生成所需类型的`Temporal`对象.我的答案中有一个例子. (2认同)