Java:无法从 TemporalAccessor 获取 LocalDate

Posted

技术标签:

【中文标题】Java:无法从 TemporalAccessor 获取 LocalDate【英文标题】:Java: Unable to obtain LocalDate from TemporalAccessor 【发布时间】:2018-01-01 10:09:20 【问题描述】:

我正在尝试将 String 日期的格式从 EEEE MMMM d 更改为 MM/d/yyyy,首先,将其转换为 LocalDate,然后将不同模式的格式化程序应用于之前的 LocalDate再次将其解析为String

这是我的代码:

private String convertDate(String stringDate) 

    //from EEEE MMMM d -> MM/dd/yyyy

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .append(DateTimeFormatter.ofPattern("EEEE MMMM d"))
            .toFormatter();

    LocalDate parsedDate = LocalDate.parse(stringDate, formatter);
    DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("MM/d/yyyy");

    String formattedStringDate = parsedDate.format(formatter2);

    return formattedStringDate;

但是,我收到了这个我不太明白的异常消息:

Exception in thread "main" java.time.format.DateTimeParseException: Text 'TUESDAY JULY 25' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: DayOfWeek=2, MonthOfYear=7, DayOfMonth=25,ISO of type java.time.format.Parsed
    at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1920)

【问题讨论】:

好吧,没有年份就不能约会。 你还没有说出你对这一年的期望。本年度?总是2017?根据月份和星期几的组合来计算年份?根据您的用例,KayV 或 Hugo 最接近。 与Java Autocomplete/Format Date from MM-DD input几乎重复 【参考方案1】:

LocalDate 的文档说,

LocalDate 是表示日期的不可变日期时间对象, 通常被视为年-月-日。例如,值“10 月 2 日 2007" 可以存储在 LocalDate 中。

在您的情况下,输入 String 缺少 LocalDate 的重要组成部分,即年份。你所拥有的基本上是月和日。因此,您可以使用适合 MonthDay 的类。使用它可以将您的代码修改为:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .parseCaseInsensitive()
                .append(DateTimeFormatter.ofPattern("EEEE MMMM d"))
                .toFormatter();

 MonthDay monthDay = MonthDay.parse(stringDate, formatter);
 LocalDate parsedDate = monthDay.atYear(2017); // or whatever year you want it at
 DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("MM/d/yyyy");

 String formattedStringDate = parsedDate.format(formatter2);
 System.out.println(formattedStringDate); //For "TUESDAY JULY 25" input, it gives the output 07/25/2017 

【讨论】:

【参考方案2】:

这是您需要实施的小改动:

private static String convertDate(String stringDate) 

    //from EEEE MMMM d -> MM/dd/yyyy

    DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern("EEEE MMMM dd")
                                        .parseDefaulting(ChronoField.YEAR, 2017)
                                        .toFormatter();

    LocalDate parsedDate = LocalDate.parse(stringDate, formatter);
    DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("MM/d/yyyy");

    String formattedStringDate = parsedDate.format(formatter2);

    return formattedStringDate;

    使用.parseDefaulting(ChronoField.YEAR, 2017)在格式化程序中添加默认年份

    使用参数"Tuesday July 25" 像这样convertDate("Tuesday July 25"); 调用方法

【讨论】:

我相信这验证了获取日期的星期几与输入字符串中的星期几一致,我想这是我们想要的。所以这很好。【参考方案3】:

正如其他答案已经说过的那样,要创建LocalDate,您需要年份,它不在输入String 中。它只有 daymonth星期几

要得到完整的LocalDate,你需要解析daymonth,并找到一个year,其中这个日/月组合匹配星期几

当然你可以忽略星期几,并假设日期总是在当前;在这种情况下,其他答案已经提供了解决方案。但如果您想找到与星期几完全匹配的年份,则必须循环直到找到为止。

我还创建了一个带有java.util.Locale 的格式化程序,以明确表示我想要英文的monthday of week 名称。如果不指定区域设置,则使用系统默认设置,并且不保证始终为英语(即使在运行时也可以更改,恕不另行通知)。

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .parseCaseInsensitive()
    .append(DateTimeFormatter.ofPattern("EEEE MMMM d"))
    // use English Locale to correctly parse month and day of week
    .toFormatter(Locale.ENGLISH);
// parse input
TemporalAccessor parsed = formatter.parse("TUESDAY JULY 25");
// get month and day
MonthDay md = MonthDay.from(parsed);
// get day of week
DayOfWeek dow = DayOfWeek.from(parsed);
LocalDate date;
// start with some arbitrary year, stop at some arbitrary value
for(int year = 2017; year > 1970; year--) 
    // get day and month at the year
    date = md.atYear(year);
    // check if the day of week is the same
    if (date.getDayOfWeek() == dow) 
        // found: 'date' is the correct LocalDate
        break;
    

在此示例中,我从 2017 年开始,并试图找到一个可以追溯到 1970 年的日期,但您可以调整适合您用例的值。

您还可以使用Year.now().getValue() 获取当前年份(而不是某个固定的任意值)。

【讨论】:

【参考方案4】:

另一种选择是执行以下操作(就像其他答案有点 hacky),当然假设您希望日期在当年:

LocalDate localDate = LocalDate.parse(stringDate + " " +LocalDate.now().getYear(), DateTimeFormatter.ofPattern("EEEE MMMM d");

【讨论】:

以上是关于Java:无法从 TemporalAccessor 获取 LocalDate的主要内容,如果未能解决你的问题,请参考以下文章

DateTimeParseException:无法解析文本:无法从 TemporalAccessor 获取 LocalDateTime

Java SE 8 TemporalAccessor.from 与 java.time.Instant 对象一起使用时出现问题

为未知的TemporalAccessor解析字符串

10hutool实战:TemporalAccessorUtil{TemporalAccessor} 工具类封装

10hutool实战:TemporalAccessorUtil{TemporalAccessor} 工具类封装

解析 localDateTime 时无法从 Temporal Accessor 获取 LocalDateTime。我正在努力摆脱不到 30 天的几个月