Java:如何获得下一次匹配模式的时间

Java:如何获得下一次匹配模式的时间,java,datetime,datetimeformatter,Java,Datetime,Datetimeformatter,有没有一种简单/直接的方法可以使用DateTimeFormatter模式来获取与该模式匹配的下一个LocalDateTime时间 我想用它来轻松获得下一次事件发生的时间(可以是每天、每周、每月等)。例如,如果某个事件发生在“周一12:00 AM”,我希望获得下周一12:00 AM的LocalDateTime /**Get next LocalDateTime that matches this input * * @param input a String for

有没有一种简单/直接的方法可以使用DateTimeFormatter模式来获取与该模式匹配的下一个LocalDateTime时间

我想用它来轻松获得下一次事件发生的时间(可以是每天、每周、每月等)。例如,如果某个事件发生在“周一12:00 AM”,我希望获得下周一12:00 AM的LocalDateTime

    /**Get next LocalDateTime that matches this input
     * 
     * @param input a String for time matching the pattern: [dayOfWeek ][dayOfMonth ][month ][year ]<timeOfDay> <AM/PM>
     * @return LocalDateTime representing the next time that matches the input*/
    public LocalDateTime getNextTime(String input) {
        LocalDateTime currentTime = LocalDateTime.now();
        DateTimeFormatter format = DateTimeFormatter.ofPattern("[eeee ][d ][MMMM ][u ]h:m a");
        TemporalAccessor accessor = format.parse(input);
        // TODO somehow get the next time (that's after currentTime) that matches this pattern
        // LocalDateTime time = ???
        return time;
    }

如果您的输入格式正确且始终为英语,您可以在第一个空格处拆分输入并按如下方式使用:

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Locale;

public class Example {

    public static void main(String[] args) {
        LocalDateTime desiredDay = getNextDayTime("Friday 12:00 AM");

        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd.MM.yyyy hh:mm a");
        System.out.println(dtf.format(desiredDay));
    }
    public static LocalDateTime getNextDayTime(String input){
        String[] splited = input.split(" ", 2);
        LocalTime localTime = LocalTime.parse(splited[1], DateTimeFormatter.ofPattern("hh:mm a", Locale.US));
        LocalDateTime dateTime = LocalDateTime.now().with(localTime);
        LocalDateTime desiredDay = dateTime.with(TemporalAdjusters.next(DayOfWeek.valueOf(splited[0].toUpperCase())));
        return desiredDay;
    }
}

不,没有一种简单或直接的方法可以满足你的要求。它需要相当多的编码。你基本上有16个病例,因为每年、每个月、每个月的每一天和每个星期的每一天都可能存在,也可能不存在。你或多或少得分别处理每一个案子

下一次也可能没有这样的机会。如果这一年是2019年,那就没有了。如果字符串为2021年1月12日星期五凌晨2:00,则不会出现,因为1月12日是星期二,而不是星期五

private static DateTimeFormatter format = DateTimeFormatter
        .ofPattern("[eeee ][uuuu ][d ][MMMM ][uuuu ]h:m a", Locale.ENGLISH);

// input = [dayOfWeek] [dayOfMonth] [month] [year] <timeOfDay> <AM/PM>
public static LocalDateTime next(String text) {
    TemporalAccessor accessor;
    try {
        accessor = format.parse(text);
    } catch (DateTimeParseException dtpe) {
        return null;
    }
    LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault());
    LocalTime parsedTime = LocalTime.from(accessor);
    LocalDate earliest = now.toLocalDate();
    if (parsedTime.isBefore(now.toLocalTime())) {
        earliest = earliest.plusDays(1);
    }
    return resolveYearMonthDomDow(earliest, accessor).atTime(parsedTime);
}

private static LocalDate resolveYearMonthDomDow(LocalDate earliest, TemporalAccessor accessor) {
    if (accessor.isSupported(ChronoField.YEAR)) {
        Year parsedYear = Year.from(accessor);
        if (parsedYear.isBefore(Year.from(earliest))) {
            return null;
        }
        return resolveMonthDomDow(parsedYear, earliest, accessor);
    } else {
        Year candidateYear = Year.from(earliest);
        while (true) {
            LocalDate resolved = resolveMonthDomDow(candidateYear, earliest, accessor);
            if (resolved != null) {
                return resolved;
            }
            candidateYear = candidateYear.plusYears(1);
        }
    }
}

private static LocalDate resolveMonthDomDow(Year year, LocalDate earliest, TemporalAccessor accessor) {
    if (accessor.isSupported(ChronoField.MONTH_OF_YEAR)) {
        YearMonth knownYm = year.atMonth(accessor.get(ChronoField.MONTH_OF_YEAR));
        if (knownYm.isBefore(YearMonth.from(earliest))) {
            return null;
        }
        return resolveDomDow(knownYm, earliest, accessor);
    } else {
        YearMonth candidateYearMonth = YearMonth.from(earliest);
        if (candidateYearMonth.getYear() < year.getValue()) {
            candidateYearMonth = year.atMonth(Month.JANUARY);
        }
        while (candidateYearMonth.getYear() == year.getValue()) {
            LocalDate resolved = resolveDomDow(candidateYearMonth, earliest, accessor);
            if (resolved != null) {
                return resolved;
            }
            candidateYearMonth = candidateYearMonth.plusMonths(1);
        }
        return null;
    }
}

private static LocalDate resolveDomDow(YearMonth ym, LocalDate earliest, TemporalAccessor accessor) {
    if (accessor.isSupported(ChronoField.DAY_OF_MONTH)) {
        int dayOfMonth = accessor.get(ChronoField.DAY_OF_MONTH);
        if (dayOfMonth > ym.lengthOfMonth()) {
            return null;
        }
        LocalDate resolved = ym.atDay(dayOfMonth);
        if (resolved.isBefore(earliest)) {
            return null;
        } else {
            return resolveDow(resolved, accessor);
        }
    } else {
        LocalDate candidateDate = earliest;
        if (YearMonth.from(earliest).isBefore(ym)) {
            candidateDate = ym.atDay(1);
        }
        while (YearMonth.from(candidateDate).equals(ym)) {
            LocalDate resolved = resolveDow(candidateDate, accessor);
            if (resolved != null) {
                return resolved;
            }
            candidateDate = candidateDate.plusDays(1);
        }
        return null;
    }
}

private static LocalDate resolveDow(LocalDate date, TemporalAccessor accessor) {
    if (accessor.isSupported(ChronoField.DAY_OF_WEEK)) {
        if (date.getDayOfWeek().getValue() == accessor.get(ChronoField.DAY_OF_WEEK)) {
            return date;
        } else {
            return null;
        }
    } else {
        return date;
    }
}
我刚才跑步时的输出(2021年1月11日星期一晚上):

2021-01-18T00:00

所以下周一。看起来不错

举一个不同的例子,说明闰年得到尊重:

    String input = "Wednesday 29 February 12:00 AM";
2040-02-29T00:00

我的代码中很可能有bug,但基本思想是可行的

一天中的时间没有问题。挑战在于日期。我用一天中的时间来确定今天的日期是否是最早的候选日期。如果现在的时间已经超过字符串中的时间,则最早的日期是明天。对于您的示例字符串,
周一12:00am
,实际情况总是这样:总是在午夜12点之后


你在
星期一25:00 AM
中有一个模棱两可的地方,因为25可能是一年(几千年前)或一个月中的一天。我坚持用四位数的年份来解决这个问题。因此,如果一周中某一天的开头或后面的数字有四位数字,则表示一年,否则表示一个月中的某一天。我使用的格式化程序看起来很有趣,一年两次。我需要它来强制解析在尝试月日之前尝试年,或者有时需要一个四位数的数字作为月日。这反过来意味着格式化程序接受的格式太多了。我想这在实践中不会是一个问题。

所以周一和周一比赛,但周五和周一比赛,而不是周五,我很困惑,我想你需要定义一下“比赛”的含义。你想要下一个工作日的同一时间吗?这对我来说很有意义-有点像Cron-给我下周一12:00的时间,所以现在的答案(至少对我在英国)是2021-01-18T00:00:00如果我不打算睡觉,我会考虑一个答案,但正如前面提到的,我在英国,对我这个年龄的人来说已经晚了。希望不久你会有一个答案。如果输入总是天和时间,我想你可以根据天数做一个简单的加法,但你希望输入是灵活的guess@OneCricketeer
[]
可选部分应包含字符:这仅适用于输入匹配
EEE h:m a
。我希望这适用于与模式匹配的任何字符串
[eeee][d][MMMM][u]h:ma
    String input = "Monday 12:00 AM";
    // get the next time that matches this pattern
    LocalDateTime time = next(input);
    System.out.println(time);
    String input = "Wednesday 29 February 12:00 AM";