如何使用Java日期时间API或Joda-time查找上周日的第n个?

时间:2017-06-02 05:36:43

标签: java date jodatime java-time dayofweek

我们如何计算前一个星期日或之前的星期日或一般情况下如何在 n 周之前找出如何查找星期日?问题是,如果今天是星期天那么它应该今天作为星期日而不是上周返回。

寻找Joda-Time或Java 8时间解决方案。

修改 我试过了

DateTime sunday = now
    .minusWeeks(1)
    .withDayOfWeek(DateTimeConstants.SUNDAY)
    .wi‌​thTimeAtStartOfDay()‌​;
DateTime previousWeekSunday = now
    .minusWeeks(2)
    .withDayOfWeek(DateTimeConstants.SATURDAY)
    .‌​withTime(23, 59, 59, 999); 

但如果当前是星期日,那么这个逻辑就会失败,因为它没有给出今天的日期。

2 个答案:

答案 0 :(得分:4)

你基本上需要检查今天是否是星期天,如果没有,那么回头查看前一个...(或者如果你需要前一个,那么递归地移回日期......)

使用java 8,您将需要:

LocalDate date = LocalDate.now();
DayOfWeek todayAsDayOfWeek = date.getDayOfWeek();
LocalDate prevSun = todayAsDayOfWeek == DayOfWeek.SUNDAY ? date : date.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY));
System.out.println(prevSun);

编辑:previousOrSame方法将跳过对实际星期几的检查

    LocalDate date = LocalDate.now();
    LocalDate prevSun = date.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY));

    prevSun = date.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
    System.out.println(prevSun);

答案 1 :(得分:1)

这个问题已经用Java 8方法回答了,但仅仅是为了记录,这里是一个Joda-Time的解决方案(以及我对Java 8的2美分)。

如果我理解正确,上周日获得n th 的一般算法是:

  • 如果当前日期已经是星期日,请返回n-1周(因此对于n=1,它会返回相同的日期)
  • 否则,从该日期前的星期日找到n th

我创建了一个接收n(周数)和DateTime(开始日期)的方法。代码是:

// get the n'th previous Sunday, from the given DateTime
public DateTime nPreviousSunday(int n, DateTime dateTime) {
    // avoid zero or negative numbers (optional, see if it fits your use cases)
    if (n <= 0) {
        return dateTime; // return the same date
    }

    DateTime d = dateTime;

    // get first previous (or same) Sunday
    int dow = d.getDayOfWeek();
    if (dow != DateTimeConstants.SUNDAY) { // not a Sunday, adjust the day to the previous one
        int diff = DateTimeConstants.SUNDAY - dow;
        // DateTimeConstants.SUNDAY is 7, so diff is always positive
        // d is (7 - diff) days ahead of Sunday, adjusting
        d = d.minusDays(7 - diff);
    }

    // find the n'th previous (considering that the first was already found above)
    d = d.minusWeeks(n - 1);

    return d;
}

以下是04/06/2017(星期日)的测试。对于n=1,它会返回04/06/2017,对于n >= 2,它会在该日期之前找到上周日的n th (考虑到04/06/2017本身就是第一个):

System.out.println(nPreviousSunday(1, new DateTime(2017, 6, 4, 10, 0))); // 2017-06-04
System.out.println(nPreviousSunday(2, new DateTime(2017, 6, 4, 10, 0))); // 2017-05-28
System.out.println(nPreviousSunday(3, new DateTime(2017, 6, 4, 10, 0))); // 2017-05-21

测试05/06/2017(不是星期日),它会得到相同的结果(与前一个星期日04/06/2017相同):

System.out.println(nPreviousSunday(1, new DateTime(2017, 6, 5, 10, 0))); // 2017-06-04
System.out.println(nPreviousSunday(2, new DateTime(2017, 6, 5, 10, 0))); // 2017-05-28
System.out.println(nPreviousSunday(3, new DateTime(2017, 6, 5, 10, 0))); // 2017-05-21

测试整个星期直到星期六(10/06/2017):

System.out.println(nPreviousSunday(1, new DateTime(2017, 6, 6, 10, 0))); // 2017-06-04
System.out.println(nPreviousSunday(1, new DateTime(2017, 6, 7, 10, 0))); // 2017-06-04
System.out.println(nPreviousSunday(1, new DateTime(2017, 6, 8, 10, 0))); // 2017-06-04
System.out.println(nPreviousSunday(1, new DateTime(2017, 6, 9, 10, 0))); // 2017-06-04
System.out.println(nPreviousSunday(1, new DateTime(2017, 6, 10, 10, 0))); // 2017-06-04

System.out.println(nPreviousSunday(3, new DateTime(2017, 6, 6, 10, 0))); // 2017-05-21
System.out.println(nPreviousSunday(3, new DateTime(2017, 6, 7, 10, 0))); // 2017-05-21
System.out.println(nPreviousSunday(3, new DateTime(2017, 6, 8, 10, 0))); // 2017-05-21
System.out.println(nPreviousSunday(3, new DateTime(2017, 6, 9, 10, 0))); // 2017-05-21
System.out.println(nPreviousSunday(3, new DateTime(2017, 6, 10, 10, 0))); // 2017-05-21

PS :我使用的是DateTime,但您也可以将此代码用于org.joda.time.LocalDateorg.joda.time.LocalDateTime(算法相同,只需在方法中更改变量的类型。

Java 8方法(我的2美分)

在Java 8中,您可以将TemporalAdjuster用作already answered。但是为了得到我的2美分,您可以创建一个返回TemporalAdjuster的方法,然后您可以将它与任何java时间类型一起使用:

// get the n'th previous dayOfWeek, from the given temporal
public TemporalAdjuster previous(int n, DayOfWeek dayOfWeek) {
    return (temporal) -> {
        // avoid zero or negative numbers (optional, see if it fits your use cases)
        if (n <= 0) {
            return temporal; // return the same temporal
        }

        // get first previous (or same) dayOfWeek
        Temporal t = temporal.with(TemporalAdjusters.previousOrSame(dayOfWeek));

        // find the n'th previous (considering that the first was already found above)
        t = t.minus(n - 1, ChronoUnit.WEEKS);

        return t;
    };
}

所以你可以这样使用它:

System.out.println(LocalDate.of(2017, 6, 4).with(previous(1, DayOfWeek.SUNDAY))); // 2017-06-04
System.out.println(LocalDate.of(2017, 6, 4).with(previous(2, DayOfWeek.SUNDAY))); // 2017-05-28
System.out.println(LocalDate.of(2017, 6, 4).with(previous(3, DayOfWeek.SUNDAY))); // 2017-05-21

System.out.println(LocalDate.of(2017, 6, 5).with(previous(1, DayOfWeek.SUNDAY))); // 2017-06-04
System.out.println(LocalDate.of(2017, 6, 5).with(previous(2, DayOfWeek.SUNDAY))); // 2017-05-28
System.out.println(LocalDate.of(2017, 6, 5).with(previous(3, DayOfWeek.SUNDAY))); // 2017-05-21

好处是它也适用于其他类型:

LocalDateTime dt = LocalDateTime.of(2017, 6, 4, 10, 0);
System.out.println(dt.with(previous(1, DayOfWeek.SUNDAY))); // 2017-06-04T10:00
System.out.println(dt.with(previous(2, DayOfWeek.SUNDAY))); // 2017-05-28T10:00

ZonedDateTime zdt = ZonedDateTime.of(dt, ZoneId.of("America/Sao_Paulo"));
System.out.println(zdt.with(previous(1, DayOfWeek.SUNDAY))); // 2017-06-04T10:00-03:00[America/Sao_Paulo]
System.out.println(zdt.with(previous(2, DayOfWeek.SUNDAY))); // 2017-05-28T10:00-03:00[America/Sao_Paulo]

OffsetDateTime odt = OffsetDateTime.of(dt, ZoneOffset.ofHours(2));
System.out.println(odt.with(previous(1, DayOfWeek.SUNDAY))); // 2017-06-04T10:00+02:00
System.out.println(odt.with(previous(2, DayOfWeek.SUNDAY))); // 2017-05-28T10:00+02:00

previous()方法返回TemporalAdjuster时,您不需要每次调用它,只需将调整器存储在变量中并重复使用它:

TemporalAdjuster thirdPreviousSunday = previous(3, DayOfWeek.SUNDAY);
System.out.println(LocalDate.of(2017, 6, 4).with(thirdPreviousSunday)); // 2017-05-21
System.out.println(LocalDate.of(2017, 6, 5).with(thirdPreviousSunday)); // 2017-05-21

这种方法的另一个优点是:代码变得更加清晰(IMO),并且可以在一周中的任何一天使用。

PS:如果类型没有DayOfWeek字段(如LocalTime,只有小时/分钟/秒/),则下面的代码会引发异常纳秒):

// throws UnsupportedTemporalTypeException (because LocalTime doesn't have the DayOfWeek field)
LocalTime.now().with(previous(1, DayOfWeek.SUNDAY));

只是提醒一下,现有的调整员已经发生了这种情况:

// also throws exception (Unsupported field: DayOfWeek)
LocalTime.now().with(TemporalAdjusters.previous(DayOfWeek.SUNDAY));

这是有道理的,因为LocalTime没有日期字段,也无法了解工作日。