是否可以将 Java 中的日期范围拆分为数周?

Is it posibile to split a daterange in Java into weeks?

我的问题如下: 我有一个日期范围(在 java 中),由两个 Calendar 对象指定,一个用于开始,一个用于结束。 现在我想得到这个范围内所有周的列表。一周应由两个 Calendar 对象指定,一个用于开始,一个用于结束。 同样重要的是,整个日期范围的开始和结束可以在两个不同的月份甚至两个不同的年份。

这是使用新时间 Api 解决问题的方法,阅读有关 LocalDate、LocalDateTime、Period 等的信息

        LocalDate startDate = LocalDate.of(2019, 12, 12).with(DayOfWeek.MONDAY);
        LocalDate endDate = LocalDate.of(2020, 12, 12);

        //number of weeks
        long weekNumber = ChronoUnit.WEEKS.between(startDate, endDate);

        Map<LocalDate, LocalDate> weeks = new LinkedHashMap<>();
        for (int i = 0; i < weekNumber; i++) {
            LocalDate endOfWeek = startDate.plusDays(6);
            weeks.put(startDate, endOfWeek);
            startDate = endOfWeek.plusDays(1);
        }
        for (LocalDate week : weeks.keySet()) {
            LocalDate endOfWeek = weeks.get(week);
            System.out.println("Start of week: " + week + "[" + week.getDayOfWeek() + "]" +
                    " End of week: " + endOfWeek + "[" + endOfWeek.getDayOfWeek() + "]");
        }

它打印:

Start of week: 2020-12-07[MONDAY] End of week: 2020-12-13[SUNDAY]
Start of week: 2020-12-14[MONDAY] End of week: 2020-12-20[SUNDAY]
Start of week: 2020-12-21[MONDAY] End of week: 2020-12-27[SUNDAY]
Start of week: 2020-12-28[MONDAY] End of week: 2021-01-03[SUNDAY]
Start of week: 2021-01-04[MONDAY] End of week: 2021-01-10[SUNDAY]

等...

编辑:

使用 DateTimeFormatter 会更短,日期名称会以您的语言显示:

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd[EEEE]");
for (LocalDate startOfWeek : weeks.keySet()) {
    LocalDate endOfWeek = weeks.get(startOfWeek);
    System.out.println("Start of week: " + dateTimeFormatter.format(startOfWeek) +
                    " End of week: " + dateTimeFormatter.format(endOfWeek));
    }

要用旧的 Calendar 对象来做,你可以像答案的前半部分所示那样做。要使用 Java 8 中添加的较新的 Java 时间 API,请参阅答案的后半部分。


使用旧日历 API

static List<DateRange> weeksCovering(Calendar start, Calendar end) {
    List<DateRange> result = new ArrayList<>();
    
    Calendar cal = (Calendar) start.clone();
    cal.clear();
    cal.set(start.get(Calendar.YEAR), start.get(Calendar.MONTH), start.get(Calendar.DATE));
    cal.add(Calendar.DATE, (cal.getFirstDayOfWeek() - cal.get(Calendar.DAY_OF_WEEK) - 7) % 7);
    while (cal.compareTo(end) <= 0) {
        Calendar weekStart = (Calendar) cal.clone();
        cal.add(Calendar.DATE, 6);
        Calendar weekEnd = (Calendar) cal.clone();
        cal.add(Calendar.DATE, 1);
        result.add(new DateRange(weekStart, weekEnd));
    }
    return result;
}
public final class DateRange {
    private final Calendar start;
    private final Calendar end;

    public DateRange(Calendar start, Calendar end) {
        this.start = start;
        this.end = end;
    }

    public Calendar getStart() {
        return (Calendar) this.start.clone();
    }
    public Calendar getEnd() {
        return (Calendar) this.end.clone();
    }

    @Override
    public String toString() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, MMM d, yyyy");
        return dateFormat.format(this.start.getTime()) + " - " +
               dateFormat.format(this.end.getTime());
    }
}

测试

test(2020,12,13, 2021,2,7, Locale.US);
test(2020,12,13, 2021,2,7, Locale.GERMANY);
static void test(int startYear, int startMonth, int startDay, int endYear, int endMonth, int endDay, Locale locale) {
    Calendar start = Calendar.getInstance(locale);
    Calendar end = Calendar.getInstance(locale);
    start.clear();
    end.clear();
    start.set(startYear, startMonth - 1, startDay);
    end.set(endYear, endMonth - 1, endDay);
    List<DateRange> weeks = weeksCovering(start, end);
    System.out.println(new DateRange(start, end) + ":");
    for (DateRange week : weeks)
        System.out.println("  " + week);
}

输出

Sun, Dec 13, 2020 - Sun, Feb 7, 2021:
  Sun, Dec 13, 2020 - Sat, Dec 19, 2020
  Sun, Dec 20, 2020 - Sat, Dec 26, 2020
  Sun, Dec 27, 2020 - Sat, Jan 2, 2021
  Sun, Jan 3, 2021 - Sat, Jan 9, 2021
  Sun, Jan 10, 2021 - Sat, Jan 16, 2021
  Sun, Jan 17, 2021 - Sat, Jan 23, 2021
  Sun, Jan 24, 2021 - Sat, Jan 30, 2021
  Sun, Jan 31, 2021 - Sat, Feb 6, 2021
  Sun, Feb 7, 2021 - Sat, Feb 13, 2021
Sun, Dec 13, 2020 - Sun, Feb 7, 2021:
  Mon, Dec 7, 2020 - Sun, Dec 13, 2020
  Mon, Dec 14, 2020 - Sun, Dec 20, 2020
  Mon, Dec 21, 2020 - Sun, Dec 27, 2020
  Mon, Dec 28, 2020 - Sun, Jan 3, 2021
  Mon, Jan 4, 2021 - Sun, Jan 10, 2021
  Mon, Jan 11, 2021 - Sun, Jan 17, 2021
  Mon, Jan 18, 2021 - Sun, Jan 24, 2021
  Mon, Jan 25, 2021 - Sun, Jan 31, 2021
  Mon, Feb 1, 2021 - Sun, Feb 7, 2021

请注意它如何正确调整到由起始日历对象标识的 Locale 的周定义。


使用较新的 Java 8 次 API

static List<DateRange> weeksCovering(LocalDate start, LocalDate end, WeekFields weekFields) {
    List<DateRange> result = new ArrayList<>();
    
    LocalDate date = start.with(TemporalAdjusters.previousOrSame(weekFields.getFirstDayOfWeek()));
    while (date.compareTo(end) <= 0) {
        LocalDate weekStart = date;
        date = date.plusDays(6);
        LocalDate weekEnd = date;
        date = date.plusDays(1);
        result.add(new DateRange(weekStart, weekEnd));
    }
    return result;
}
public final class DateRange {
    private final LocalDate start;
    private final LocalDate end;

    public DateRange(LocalDate start, LocalDate end) {
        this.start = start;
        this.end = end;
    }

    public LocalDate getStart() {
        return this.start;
    }
    public LocalDate getEnd() {
        return this.end;
    }

    @Override
    public String toString() {
        DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("EEE, MMM d, uuuu");
        return dateFormat.format(this.start) + " - " + dateFormat.format(this.end);
    }
}

测试

test(2020,12,13, 2021,2,7, Locale.US);
test(2020,12,13, 2021,2,7, Locale.GERMANY);
static void test(int startYear, int startMonth, int startDay, int endYear, int endMonth, int endDay, Locale locale) {
    LocalDate start = LocalDate.of(startYear, startMonth, startDay);
    LocalDate end = LocalDate.of(endYear, endMonth, endDay);
    List<DateRange> weeks = weeksCovering(start, end, WeekFields.of(locale));
    System.out.println(new DateRange(start, end) + ":");
    for (DateRange week : weeks)
        System.out.println("  " + week);
}

输出

Sun, Dec 13, 2020 - Sun, Feb 7, 2021:
  Sun, Dec 13, 2020 - Sat, Dec 19, 2020
  Sun, Dec 20, 2020 - Sat, Dec 26, 2020
  Sun, Dec 27, 2020 - Sat, Jan 2, 2021
  Sun, Jan 3, 2021 - Sat, Jan 9, 2021
  Sun, Jan 10, 2021 - Sat, Jan 16, 2021
  Sun, Jan 17, 2021 - Sat, Jan 23, 2021
  Sun, Jan 24, 2021 - Sat, Jan 30, 2021
  Sun, Jan 31, 2021 - Sat, Feb 6, 2021
  Sun, Feb 7, 2021 - Sat, Feb 13, 2021
Sun, Dec 13, 2020 - Sun, Feb 7, 2021:
  Mon, Dec 7, 2020 - Sun, Dec 13, 2020
  Mon, Dec 14, 2020 - Sun, Dec 20, 2020
  Mon, Dec 21, 2020 - Sun, Dec 27, 2020
  Mon, Dec 28, 2020 - Sun, Jan 3, 2021
  Mon, Jan 4, 2021 - Sun, Jan 10, 2021
  Mon, Jan 11, 2021 - Sun, Jan 17, 2021
  Mon, Jan 18, 2021 - Sun, Jan 24, 2021
  Mon, Jan 25, 2021 - Sun, Jan 31, 2021
  Mon, Feb 1, 2021 - Sun, Feb 7, 2021

请注意它如何正确调整到由起始日历对象标识的 Locale 的周定义。