首页 > 解决方案 > Java 8 DateTimeFormatter,可选部分不带秒

问题描述

已经存在带有可选部分的 Java 8 DateTimeFormatter问题,但是当可选部分只有小时和分钟而没有秒时,它的答案将不起作用:

DateTimeFormatter patternWithOptional = new DateTimeFormatterBuilder()
    .appendPattern("M/d/yyyy[ h:mm]")
    .toFormatter();
TemporalAccessor tmp = patternWithOptional.parseBest("4/11/2020 1:20", LocalDateTime::from, LocalDate::from);
System.out.println(tmp);
System.out.println(tmp.getClass().getSimpleName());
// prints 2020-04-11, without time
// class is LocalDate in this case

这是因为LocalDateTime.from(TemporalAccessor temporal)用于TemporalQueries.LOCAL_TIME查询temporal. TemporalQueries.LOCAL_TIME反过来,需要ChronoField.NANO_OF_DAY从 获得temporal

System.out.println(patternWithOptional.parse("4/11/2020 1:20"));
// prints:
{HourOfAmPm=1, MinuteOfHour=20},ISO resolved to 2020-04-11

由于HourOfAmPm并且MinuteOfHour可用,实现我需要的最简单的方法,我可以想出:

private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
    .appendPattern("M/d/yyyy[ h:mm]")
    .toFormatter();

public static void main(String[] args) {
    // demo
    System.out.println(parse("3/20/1995"));      // without time
    System.out.println(parse("4/11/2020 1:20")); // with time
}

private static LocalDateTime parse(String s) {
    TemporalAccessor parsed = FORMATTER.parse(s);
    return LocalDateTime.of(
        LocalDate.from(parsed),
        LocalTime.of(
            parsed.isSupported(ChronoField.HOUR_OF_AMPM)
                ? (int) ChronoField.HOUR_OF_AMPM.getFrom(parsed)
                : 0,
            parsed.isSupported(ChronoField.MINUTE_OF_HOUR)
                ? (int) ChronoField.MINUTE_OF_HOUR.getFrom(parsed)
                : 0
        ) // minor note: this part could also be used as a lambda argument for parseBest method.
    );
}

isSupported有没有更简单的方法可以在没有明确检查的情况下做到这一点?

标签: javatimejava-timedatetime-parsinglocaldate

解决方案


在您的格式模式字符串中,您需要在H一天中的一小时内使用大写:

            .appendPattern("M/d/yyyy[ H:mm]")

通过此更改,您的第一个片段打印

2020-04-11T01:20
LocalDateTime

小写h是上午或下午内的小时。因此,您的时间可能意味着 01:20 AM 或 01:20 PM,即 13:20。Java 无法决定,因此选择不解释一天中的时间,只给你一个LocalDate.

如果你总是想要一个LocalDateTime,你也可以使用parseDefaulting

    DateTimeFormatter patternWithOptional = new DateTimeFormatterBuilder()
            .appendPattern("M/d/yyyy[ H:mm]")
            .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
            .toFormatter();
    System.out.println(LocalDateTime.parse("4/11/2020 1:20", patternWithOptional));
    System.out.println(LocalDateTime.parse("4/11/2020", patternWithOptional));

输出:

2020-04-11T01:20
2020-04-11T00:00

另一方面,如果您确实需要 aLocalDate或 a ,LocalDateTime具体取决于字符串中是否有可用的时间,则不需要 a DateTimeFormatterBuilder

    DateTimeFormatter patternWithOptional = DateTimeFormatter.ofPattern("M/d/yyyy[ H:mm]");

推荐阅读