使用JodaTime,是否有一种优雅的方式可以找到给定日期的星期几?我最初认为setCopy()
会是它,但是这会将当天设置为特定日期在同一周。因此,如果ld
为2011-11-27
而day
为“星期一”,则以下函数会返回2011-11-21
,而不是2011-11-28
。
// Note that "day" can be _any_ day of the week, not just weekdays.
LocalDate getNearestDayOfWeek(LocalDate ld, String day) {
return ld.dayOfWeek().setCopy(day);
}
各种输入的所需输出:
2011-12-04, Monday => 2011-12-05
2011-12-04, Tuesday => 2011-12-06
2011-12-04, Wednesday => 2011-12-07
2011-12-04, Thursday => 2011-12-01
2011-12-04, Friday => 2011-12-02
2011-12-04, Saturday => 2011-12-03
2011-12-04, Sunday => 2011-12-04
2011-12-05, Monday => 2011-12-05
2011-12-05, Tuesday => 2011-12-06
2011-12-05, Wednesday => 2011-12-07
2011-12-05, Thursday => 2011-12-08
2011-12-05, Friday => 2011-12-02
2011-12-05, Saturday => 2011-12-03
2011-12-05, Sunday => 2011-12-04
下面是我想出的解决方案,它适用于我当前情况下的特殊限制,但我很乐意帮助找到一个始终有效的完全通用的解决方案。
LocalDate getNearestDayOfWeek(LocalDate ld, String day) {
LocalDate target = ld.dayOfWeek().setCopy(day);
if (ld.getDayOfWeek() > DateTimeConstants.SATURDAY) {
target = target.plusWeeks(1);
}
return target;
}
答案 0 :(得分:5)
在Jodatime中,这种事情应该是三行或四行:
/** Given a reference LocalDate and a day of week, eg DateTimeConstants.MONDAY
Returns the nearest date with that day of week */
public static LocalDate getNearestDayOfWeek(LocalDate t0,int dow) {
LocalDate t1 = t0.withDayOfWeek(dow);
LocalDate t2 = t1.isBefore(t0) ? t1.plusWeeks(1) : t1.minusWeeks(1);
return Math.abs(Days.daysBetween(t1, t0).getDays()) <
Math.abs(Days.daysBetween(t2, t0).getDays()) ? t1 : t2;
}
或更紧凑和高效:
public static LocalDate getNearestDayOfWeek(LocalDate t0, int dow) {
LocalDate t1 = t0.withDayOfWeek(dow);
if (t1.isBefore(t0.minusDays(3))) return t1.plusWeeks(1);
else if (t1.isAfter(t0.plusDays(3))) return t1.minusWeeks(1);
else return t1;
}
如果你想以星期几的形式传递星期几:
public static LocalDate getNearestDayOfWeek(LocalDate t0, String dow) {
return getNearestDayOfWeek(t0,t0.dayOfWeek().setCopy(dow).getDayOfWeek());
}
示例:
// prints 2011-11-28
public static void main(String[] args) throws Exception {
LocalDate today = new LocalDate(2011,11,27);
int dow = DateTimeConstants.MONDAY;
System.out.println(getNearestDayOfWeek(today ,dow ));
}
答案 1 :(得分:2)
这是解决问题的方法。我对JodaTime有点了解,但并不是所有的类和方法。我假设在给定日期的情况下,您可以获得一周中的某一天以及下一个或之前的日期。
有三种情况。
如果 dayOfTheWeek 是枚举类型,那么case语句将以直接的方式处理任务。
答案 2 :(得分:2)
通过定义一周中最接近的天数的间隔来查找一周中最近的一天。 Joda将周定义为周一开始。因此,如果今天是星期二,并且星期几设置为星期日,那么日期将是下一个星期日,而不是之前的星期日。如果将一周的第一天重新定义为星期日,则返回的日期将是上一个星期日。以下代码不受本周第一天定义的影响。
DateTime getNearestDayOfWeek(DateTime dateTime, String day) { //Create an interval containing the nearest days of the week. DateTime begin = dateTime.minusHours(DateTimeConstants.HOURS_PER_WEEK/2).dayOfWeek().roundHalfCeilingCopy(); DateTime end = dateTime.plusHours(DateTimeConstants.HOURS_PER_WEEK/2).dayOfWeek().roundHalfCeilingCopy(); Interval interval = new Interval(begin, end); //Adjust nearest day to be within the interval. Doesn't depend on definition of first day of the week. DateTime nearest = dateTime.dayOfWeek().setCopy(day); if (interval.isAfter(nearest)) //nearest is before the interval return nearest.plusWeeks(1); else if (interval.isBefore(nearest)) //nearest is after the interval return nearest.minusWeeks(1); else return nearest; }
答案 3 :(得分:2)
像这样的东西。对于dayOfWeek参数,使用org.joda.time.DateTimeConstants中定义的常量:
public LocalDate getNext(int dayOfWeek) {
LocalDate today = new LocalDate();
return getNext(dateOfWeek, today);
}
public LocalDate getNext(int dayOfWeek, LocalDate fromDate) {
int dayOffset = DateTimeConstants.DAYS_PER_WEEK - dayOfWeek + 1;
LocalDate weekContainingDay = fromDate.plusDays(dayOffset);
return weekContainingDay.withDayOfWeek(dayOfWeek);
}
用法:
LocalDate nextSunday = foo.getNext(DateTimeConstants.SUNDAY);
答案 4 :(得分:1)
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();
}
}
答案 5 :(得分:0)
基于Richard Povinelli的回答,但更新为使用Java Time(从Java 8开始)
public static LocalDate getNearestDayOfWeek(LocalDate date, DayOfWeek dayOfWeek) {
LocalDate start = date.minusDays(3);
LocalDate end = date.plusDays(3);
LocalDate guessDate = date.with(dayOfWeek);
// the nearest day is between start and end, so we adjust our guess if required
if (guessDate.isAfter(end)) {
// guessed one week to late
return guessDate.minusWeeks(1);
} else if (guessDate.isBefore(start)) {
// guessed one week to early
return guessDate.plusWeeks(1);
} else {
// the guess was correct
return guessDate;
}
}