是否可以将 Java 中的日期范围拆分为数周? 使用旧的日历 API使用较新的 Java 8 Time API

问题描述

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

解决方法

这是您的问题的实现,使用新的 Time Api,阅读有关 LocalDate、LocalDateTime、Period 等的信息。

        LocalDate startDate = LocalDate.of(2019,12,12).with(DayOfWeek.MONDAY);
        LocalDate endDate = LocalDate.of(2020,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 Time 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,13,2021,2,7,Locale.US);
test(2020,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,2020 - Sat,Dec 19,2020
  Sun,Dec 20,Dec 26,Dec 27,Jan 2,2021
  Sun,Jan 3,2021 - Sat,Jan 9,Jan 10,Jan 16,Jan 17,Jan 23,Jan 24,Jan 30,Jan 31,Feb 6,Feb 13,2021
Sun,2021:
  Mon,Dec 7,2020
  Mon,Dec 14,Dec 21,Dec 28,2021
  Mon,Jan 4,2021 - Sun,Jan 11,Jan 18,Jan 25,Feb 1,2021

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


使用较新的 Java 8 Time 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,uuuu");
        return dateFormat.format(this.start) + " - " + dateFormat.format(this.end);
    }
}

测试

test(2020,Locale locale) {
    LocalDate start = LocalDate.of(startYear,startMonth,startDay);
    LocalDate end = LocalDate.of(endYear,endMonth,end,WeekFields.of(locale));
    System.out.println(new DateRange(start,2021

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