无法使用 DateTimeFormatter 解析月+日

Unable to parse a Month+day using DateTimeFormatter

我试着查看这个 link 来寻找灵感:

但是,当我尝试将字符串 "Mon 21st May" 解析为 "Monday 21st May" - 全日名称、日期编号和完整月份时出现错误。

Exception in thread "main" java.time.format.DateTimeParseException: Text 'Mon 21st May' could not be parsed at index 0 at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949) at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851) at java.time.LocalDate.parse(LocalDate.java:400) at HelloWorld.main(HelloWorld.java:45)

代码如下:

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.text.SimpleDateFormat;  
import java.util.Date;  
import java.util.Locale;

// one class needs to have a main() method
public class HelloWorld
{
  // arguments are passed using the text field below this editor
  public static void main(String[] args) throws Exception
  {

    String str = "Mon 21st May";
    DateTimeFormatter parseFormatter = DateTimeFormatter.ofPattern("EEEE d['st']['nd']['rd']['th'] MMMM", Locale.ENGLISH);
    LocalDate datetext = LocalDate.parse(str, parseFormatter);

  }
}

更新:

这是我按照建议尝试过的最新代码,我更改了字符串以查看问题是否与此有关,下面是我现在收到的错误。看起来它知道日期,只是无法解析它:

  public static void main(String[] args) throws Exception
  {

    String str = "Tue 21st May";
    DateTimeFormatter parseFormatter = DateTimeFormatter.ofPattern("EEE d['st']['nd']['rd']['th'] MMMM", Locale.ENGLISH);
    LocalDate datetext = LocalDate.parse(str, parseFormatter);

  }
}

错误:

Exception in thread "main" java.time.format.DateTimeParseException: Text 'Tue 21st May' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {DayOfWeek=2, DayOfMonth=21, MonthOfYear=5},ISO of type java.time.format.Parsed at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1920) at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1855) at java.time.LocalDate.parse(LocalDate.java:400) at HelloWorld.main(HelloWorld.java:26) Caused by: java.time.DateTimeException: Unable to obtain LocalDate from TemporalAccessor: {DayOfWeek=2, DayOfMonth=21, MonthOfYear=5},ISO of type java.time.format.Parsed at java.time.LocalDate.from(LocalDate.java:368) at java.time.format.Parsed.query(Parsed.java:226) at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851) ... 2 more

MonthDay

如果你想解析没有年份的月份和日期,使用MonthDay:

    String str = "Mon 21st May";
    DateTimeFormatter parseFormatter = DateTimeFormatter.ofPattern("EEE d['st']['nd']['rd']['th'] MMMM", Locale.ENGLISH);
    MonthDay md = MonthDay.parse(str, parseFormatter);
    System.out.println(md);

输出为:

--05-21

前导破折号表示缺席年份。格式模式字符串中的 EEEE 是星期几的全名,例如星期一或星期二。对于缩写,您需要 EEEEEE.

LocalDate

如果你想要 LocalDate,你需要以某种方式提供一年。一种选择是:

    LocalDate datetext = md.atYear(Year.now(ZoneId.of("Europe/London")).getValue());
    System.out.println(datetext);

2019-05-21

不过,这不会验证月份中的第几天。为此:

    String str = "Tue 21st May";
    DateTimeFormatter parseFormatter = new DateTimeFormatterBuilder()
            .appendPattern("EEE d['st']['nd']['rd']['th'] MMMM")
            .parseDefaulting(ChronoField.YEAR, Year.now(ZoneId.of("Europe/London")).getValue())
            .toFormatter(Locale.ENGLISH);

    LocalDate datetext = LocalDate.parse(str, parseFormatter);

2019-05-21

在您提问的评论中:

What about if I want to output it as Tuesday 21 May?

这是一个新问题,已经讨论过很多次了,但是没关系。

    DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("EEEE d MMMM", Locale.ENGLISH);
    System.out.println(datetext.format(outputFormatter));

Tuesday 21 May

从星期几检测年份

I may not know the year, as in I am trying to view dates in an application but some dates may be this year, some may fall over to next year but these dates don't have a year supplied

以下完整示例假定日期在从今天算起的未来 3 年内,并检测星期几正确的年份。成功后,它会以您想要的格式打印。

    String str = "Wed 20th May";
    ZoneId zone = ZoneId.of("Europe/London");
    LocalDate today = LocalDate.now(zone);
    int currentYear = today.getYear();
    LocalDate datetext = null;
    final int maxYearsFromToday = 3;
    for (int year = currentYear; year <= currentYear + maxYearsFromToday; year++) {
        DateTimeFormatter parseFormatter = new DateTimeFormatterBuilder()
                .appendPattern("EEE d['st']['nd']['rd']['th'] MMMM")
                .parseDefaulting(ChronoField.YEAR, year)
                .toFormatter(Locale.ENGLISH);

        try {
            datetext = LocalDate.parse(str, parseFormatter);
            System.out.println("Day of week matched for year " + year);
            break;
        } catch (DateTimeParseException dtpe) {
            // Ignore, try next year
        }
    }

    DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("EEEE d MMMM", Locale.ENGLISH);
    if (datetext == null) {
        System.out.println("Could not parse date;"
                + " possibly the day of week didn’t match for any year in the range "
                + currentYear + " through " + (currentYear + maxYearsFromToday));
    } else if (datetext.isBefore(today) || datetext.isAfter(today.plusYears(maxYearsFromToday))) {
        System.out.println("Date is out of range");
    } else {
        System.out.println("Successfully parsed: " + datetext.format(outputFormatter));
    }
Day of week matched for year 2020
Successfully parsed: Wednesday 20 May

现在是 2019 年 5 月 21 日星期二。下面的代码有效。

    String str = "Tue 21st May 2019";
    DateTimeFormatter parseFormatter = DateTimeFormatter.ofPattern("EEE d['st']['nd']['rd']['th'] MMMM yyyy", Locale.ENGLISH);
    LocalDate datetext = LocalDate.parse(str, parseFormatter);

这是我搜索正确年份的代码:

在不知道星期几的情况下,您有 6/7 的机会将日期解析为错误的年份。但是,如果您知道日期名称,那么您可以搜索 7 年范围以找到正确的年份。

假设您有一个类似于以下之一的日期:

Wednesday, May 27
WED 5/27

格式化程序如:

DateTimeFormatter visibleButtonFormat = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendPattern("EEE M/dd")
            .toFormatter(Locale.US);
        DateTimeFormatter accessibleFormat = DateTimeFormatter.ofPattern("EEEE, MMMM dd");

然后,您可以像这样解析 MonthDay:

MonthDay monthDay = MonthDay.parse(dateText, oneOfTheAboveFormatters);

然后,您可以搜索正确的年份。在这种情况下是 2020 年:

private static int findYearMatchingMonthDay(String dateText, MonthDay monthDay) {
    for(int checkYear = 2020; checkYear >= 2016; checkYear--) {
        LocalDate localDate = LocalDate.of(checkYear, monthDay.getMonth(), monthDay.getDayOfMonth());
        String shortDay = localDate.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.US).toUpperCase();
        if (shortDay.equals(dateText.substring(0,3))) {
            ConsoleUtils.logDebug("Assuming schedule buttons within year: " + checkYear);
            return checkYear;
        }
    }
    return Year.now().getValue();
}