Calculate number of weekdays between two dates in

2019-01-02 20:58发布

Can anyone point me to some Java snippet wherein i can get business (except Sat and Sun) days between two dates.

标签: java
16条回答
闭嘴吧你
2楼-- · 2019-01-02 21:02

The startCal.add should add onto the Calendar.DATE field, not the Calendar.DAY_OF_MONTH, I was getting weird results with over Decemeber / January period.

查看更多
旧时光的记忆
3楼-- · 2019-01-02 21:02

This thread is filled with failing solutions... I started by writing a little test file which met my needs, and saw that Roland's both solutions fails, Amir's too. I wanted a solution that uses java 8 and that does not uses loops because, do I have to say why ?

So here's the test file :

@Test
public void test() {
    LocalDate d1 = LocalDate.of(2018, 8, 1);
    LocalDate d2 = LocalDate.of(2018, 8, 2);
    LocalDate d3 = LocalDate.of(2018, 8, 3);
    LocalDate d4 = LocalDate.of(2018, 8, 4);
    LocalDate d5 = LocalDate.of(2018, 8, 5);
    LocalDate d6 = LocalDate.of(2018, 8, 6);
    LocalDate d7 = LocalDate.of(2018, 8, 7);
    LocalDate d8 = LocalDate.of(2018, 8, 8);
    LocalDate d9 = LocalDate.of(2018, 8, 9);
    LocalDate d10 = LocalDate.of(2018, 8, 10);
    LocalDate d15 = LocalDate.of(2018, 8, 15);
    LocalDate dsep = LocalDate.of(2018, 9, 5);

    // same day : 0 days between
    Assert.assertEquals(0, DateUtils.calcWeekDays1(d1, d1));
    Assert.assertEquals(1, DateUtils.calcWeekDays1(d1, d2));
    Assert.assertEquals(2, DateUtils.calcWeekDays1(d1, d3));
    // end on week-end 
    Assert.assertEquals(2, DateUtils.calcWeekDays1(d1, d4));
    Assert.assertEquals(2, DateUtils.calcWeekDays1(d1, d5));
    // next week
    Assert.assertEquals(3, DateUtils.calcWeekDays1(d1, d6));
    Assert.assertEquals(4, DateUtils.calcWeekDays1(d1, d7));
    Assert.assertEquals(5, DateUtils.calcWeekDays1(d1, d8));
    Assert.assertEquals(6, DateUtils.calcWeekDays1(d1, d9));
    Assert.assertEquals(7, DateUtils.calcWeekDays1(d1, d10));
    // start on saturday
    Assert.assertEquals(0, DateUtils.calcWeekDays1(d4, d5));
    Assert.assertEquals(0, DateUtils.calcWeekDays1(d4, d6));
    Assert.assertEquals(1, DateUtils.calcWeekDays1(d4, d7));
    // start on sunday
    Assert.assertEquals(0, DateUtils.calcWeekDays1(d5, d5));
    Assert.assertEquals(0, DateUtils.calcWeekDays1(d5, d6));
    Assert.assertEquals(1, DateUtils.calcWeekDays1(d5, d7));
    // go to next week
    Assert.assertEquals(10, DateUtils.calcWeekDays1(d1, d15));
    // next month
    Assert.assertEquals(25, DateUtils.calcWeekDays1(d1, dsep));
    // start sat, go to next month
    Assert.assertEquals(22, DateUtils.calcWeekDays1(d4, dsep));

}

And here is my proposed solution, quite simple. Just let java count the number of weeks, multiply by five, and add the number of days needed to compensate the difference ; the only trick is adjusting the start and end to avoid week-ends :

public static long calcWeekDays1(LocalDate start, LocalDate end) {
    if (start.getDayOfWeek().getValue() > 5) {
        start = start.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
    }
    if (end.getDayOfWeek().getValue() > 5) {
        end = end.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
    }
    if (start.isAfter(end)) { // may happen if you start sat. and end sunday
        return 0;
    }
    long weeks = ChronoUnit.WEEKS.between(start, end);
    if (start.getDayOfWeek().getValue() > end.getDayOfWeek().getValue()) {
        weeks += 1;
    }
    return 5 * weeks + end.getDayOfWeek().getValue() - start.getDayOfWeek().getValue();
}

And now I will look stupid if my code fails too :)

查看更多
浅入江南
4楼-- · 2019-01-02 21:03

Solution without loop:

static long days(Date start, Date end){
    //Ignore argument check

    Calendar c1 = Calendar.getInstance();
    c1.setTime(start);
    int w1 = c1.get(Calendar.DAY_OF_WEEK);
    c1.add(Calendar.DAY_OF_WEEK, -w1);

    Calendar c2 = Calendar.getInstance();
    c2.setTime(end);
    int w2 = c2.get(Calendar.DAY_OF_WEEK);
    c2.add(Calendar.DAY_OF_WEEK, -w2);

    //end Saturday to start Saturday 
    long days = (c2.getTimeInMillis()-c1.getTimeInMillis())/(1000*60*60*24);
    long daysWithoutWeekendDays = days-(days*2/7);

    // Adjust days to add on (w2) and days to subtract (w1) so that Saturday
    // and Sunday are not included
    if (w1 == Calendar.SUNDAY && w2 != Calendar.SATURDAY) {
        w1 = Calendar.MONDAY;
    } else if (w1 == Calendar.SATURDAY && w2 != Calendar.SUNDAY) {
        w1 = Calendar.FRIDAY;
    } 

    if (w2 == Calendar.SUNDAY) {
        w2 = Calendar.MONDAY;
    } else if (w2 == Calendar.SATURDAY) {
        w2 = Calendar.FRIDAY;
    }

    return daysWithoutWeekendDays-w1+w2;
}
查看更多
君临天下
5楼-- · 2019-01-02 21:04

The do while in the solution of Piyush is wrong, it should be :

do {
    if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY && startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
        ++workDays;
    }
    startCal.add(Calendar.DAY_OF_MONTH, 1);
} while (startCal.getTimeInMillis() < endCal.getTimeInMillis());
查看更多
初与友歌
6楼-- · 2019-01-02 21:04

Using java 8 it can be easily done, example function:

long getBusinessDaysDifference(LocalDate startDate, LocalDate endDate) { 

    EnumSet<DayOfWeek> weekend = EnumSet.of(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY);
    List<LocalDate> list = Lists.newArrayList();

    LocalDate start = startDate;        
    while (start.isBefore(endDate)) {
        list.add(start);
        start = start.plus(1, ChronoUnit.DAYS);
    }

    long numberOfDays = list.stream().filter(d -> !weekend.contains(d.getDayOfWeek())).count();

    return numberOfDays;
}

Description:

  1. Define your off-days in an EnumSet (weekends in this case).
  2. Create a list holding all the days between the startDate and endDate.
  3. Reduce the outcome list by removing any occurrence of a day from the EnumSet.
  4. Then finally count the size of this reduced list.

Note: this function can be optimized, but might be helpful as a starting point.

查看更多
皆成旧梦
7楼-- · 2019-01-02 21:06

In groovy:

  public static int getWorkingDaysBetweenDates (Date start, Date end) {
    def totalDays = (Integer) (end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)
    def int workingDays = 0

    (0..totalDays).each { def dow = (start + it)[Calendar.DAY_OF_WEEK]; if(dow != Calendar.SATURDAY && dow != Calendar.SUNDAY){workingDays++} }

    workingDays
  }
查看更多
登录 后发表回答