Java 8 中有一个很好的 API 用于此目的,称为 TemporalAdjuster:
LocalDate today = LocalDate.now();
TemporalAdjuster adjustToNextWed = TemporalAdjusters.next(DayOfWeek.WEDNESDAY);
TemporalAdjuster adjustToNexOrSametWed = TemporalAdjusters.nextOrSame(DayOfWeek.WEDNESDAY);
LocalDate nextWed = today.with(adjustToNextWed);
LocalDate nextWedOrToday = today.with(adjustToNextOrSameWed);
java.time.temporal.TemporalAdjusters 类包含工厂一些常见的用例:
firstDayOfMonth, lastDayOfMonth, firstDayOfNextMonth, firstDayOfYear, lastDayOfYear, firstDayOfNextYear, firstInMonth, lastInMonth, dayOfWeekInMonth, next, nextOrSame, previous, previousOrSame
如您所见,“最近”没有工厂,但您可以创建自己的工厂。在检查了这些方法的来源之后,自己制作非常简单:
// This implementation is expanded and verbose for clarity,
// see simplified version below
public static TemporalAdjuster nearest(DayOfWeek dayOfWeek) {
int targetDay = dayOfWeek.getValue(); // range: +1..+7
return (temporal) -> {
int originalDay = temporal.get(DAY_OF_WEEK); // range: +1..+7
// difference between the target (1..7) and original (1..7) weekdays
int adjustDays = targetDay - originalDay; // range: -6..+6
if (adjustDays <= -4) {
// if the adjustment is 4 or more days ago,
// next week is closer:
adjustDays += 7;
}
if (adjustDays >= 4) {
// if the adjustment is 4 or more days in future,
// previous week is closer:
adjustDays -= 7;
}
return temporal.plus(adjustDays, DAYS);
};
}
使用它非常简单:
LocalDate date = LocalDate.now(); // some date to adjust, from your code
date.with(nearest(DayOfWeek.TUESDAY)); // the nearest Tuesday from the date
可以简化为单个表达式,将-6到+6的范围转换为-3..+3:
public static TemporalAdjuster nearest(DayOfWeek dayOfWeek) {
int targetDay = dayOfWeek.getValue();
return (temporal) -> {
int originalDay = temporal.get(DAY_OF_WEEK);
final int adjustDays = ((targetDay - originalDay + 10) % 7) - 3;
return temporal.plus(adjustDays, DAYS);
};
}
完整示例:
这是一个完整的实现,包含对所有日期组合的测试。
您可以运行程序来验证结果,产生如下输出:
...
original day: MONDAY, target day THURSDAY, difference: -3
nearest THURSDAY to MONDAY 2021-05-03 is 2021-05-06
original day: MONDAY, target day FRIDAY, difference: -4
nearest FRIDAY to MONDAY 2021-05-03 is 2021-04-30
...
original day: MONDAY, target day FRIDAY, difference: 4
nearest FRIDAY to MONDAY 2021-05-03 is 2021-04-30
....
解决方案:
// file TestNearest.java
class TestNearest {
public static LocalDate nearestDayOfWeek(LocalDate originalDate, DayOfWeek dayOfWeek) {
return originalDate.with(nearest(dayOfWeek));
}
public static TemporalAdjuster nearest(DayOfWeek dayOfWeek) {
int targetDay = dayOfWeek.getValue();
return (temporal) -> {
int originalDay = temporal.get(ChronoField.DAY_OF_WEEK);
final int adjustment = ((targetDay - originalDay + 10) % 7) - 3;
return temporal.plus(adjustment, ChronoUnit.DAYS);
};
}
public static void main(String[] args) {
for (int original = 1; original <= 7; original++) {
for (int target = 1; target <= 7; target++) {
final DayOfWeek originalDayOfWeek = DayOfWeek.of(original);
final DayOfWeek targetDayOfWeek = DayOfWeek.of(target);
// Create a test date:
final LocalDate testOriginalDate = LocalDate.now()
.with(TemporalAdjusters.dayOfWeekInMonth(1, originalDayOfWeek));
final LocalDate nearestDate = nearestDayOfWeek(testOriginalDate, targetDayOfWeek);
debug(testOriginalDate, targetDayOfWeek, nearestDate);
}
}
}
private static void debug(LocalDate original, DayOfWeek target, LocalDate result) {
System.out.println("original day: " + original.getDayOfWeek() +
", target day " + target +
", difference: " + (target.getValue() - original.getDayOfWeek().getValue()));
System.out.println(" nearest " + (result.getDayOfWeek()) + " to " +
(original.getDayOfWeek()) + " " +
original +
" is " +
result);
System.out.println();
}
}