Расчет разницы рабочих дней между двумя календарными датами

Я пытаюсь найти количество рабочих дней между двумя датами (выходные и время должны игнорироваться). Я использую следующую функцию для этого. Но это дает ложные результаты для нескольких условий, например, если дата начала приходится на выходные или дата окончания находится на выходных. Вот один пример для демонстрации, который дает один дополнительный день в счете.

08.03.2018 00:00:00.0 и 22.04.2018 01:37:29.887

Считайте, что возвращается 32 (должно быть 31, также учитывается 23-04-2018). Пожалуйста, предоставьте идеальное решение/подход, чтобы сделать то же самое.

private static int calculateDuration(Date startDate, Date endDate)
{
  Calendar startCal = Calendar.getInstance();
  startCal.setTime(startDate);
  startCal.set( Calendar.HOUR_OF_DAY, 0 );
  startCal.set( Calendar.MINUTE, 0 );
  startCal.set( Calendar.SECOND, 0 );
  startCal.set( Calendar.MILLISECOND, 0 );
  Calendar endCal = Calendar.getInstance();
  endCal.setTime(endDate);
  endCal.set( Calendar.HOUR_OF_DAY, 0 );
  endCal.set( Calendar.MINUTE, 0 );
  endCal.set( Calendar.SECOND, 0 );
  endCal.set( Calendar.MILLISECOND, 0 );
  int workDays = 0;

  if (startCal.getTimeInMillis() > endCal.getTimeInMillis())
  {
    startCal.setTime(endDate);
    endCal.setTime(startDate);
  }

  do
  {
    startCal.add(Calendar.DAY_OF_MONTH, 1);
    System.out.println("************"+Calendar.DAY_OF_WEEK);
    System.out.println("Before weekend condition"+Calendar.DAY_OF_WEEK+"Workdays="+workDays);

    if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY && startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY)
    {
      workDays++;
        System.out.println("This day picked "+startCal.getTime()+"Workdays="+workDays);


    }
  }
  while (startCal.getTimeInMillis() <= endCal.getTimeInMillis());
System.out.println("Final workdays count for  "+startDate+" and "+endDate+" is"+workDays);

  return workDays;
}

Я пробовал несколько решений, но это сработало хорошо, за исключением упомянутого сценария.


person nik    schedule 22.04.2018    source источник
comment
Я рекомендую использовать LocalDate/LocalDateTime и читать «java 8 вычисляет разницу, используя соответствующие единицы времени между двумя локальными данными»> stackoverflow.com/questions/25747499/   -  person Bogdan Lukiyanchuk    schedule 22.04.2018
comment
32 правильно, кстати.   -  person Jacob G.    schedule 22.04.2018
comment
Об этом уже неоднократно спрашивали и отвечали. Извините, мне нелегко найти оригинал, но вы можете увидеть, лучше ли ваши поисковые способности, чем мои.   -  person Ole V.V.    schedule 22.04.2018
comment
Следует ли учитывать первый и/или последний день (при условии, что это рабочие дни)?   -  person Ole V.V.    schedule 22.04.2018
comment
@ОлеВ.В. - Дата начала должна быть исключена, а дата окончания должна быть включена в счет.   -  person nik    schedule 25.04.2018


Ответы (1)


Я настоятельно рекомендую использовать java.time.LocalDate::datesUntil, встречающийся в Java 9 и более поздних версиях. Для расчета требуется всего пара строк, вместо использования Calendar:

var startDate = LocalDate.parse("2018-03-08");
var endDate = LocalDate.parse("2018-04-22");

var numWeekDays = startDate.datesUntil(endDate)
                           .map(LocalDate::getDayOfWeek)
                           .filter(d -> d != DayOfWeek.SATURDAY && d != DayOfWeek.SUNDAY)
                           .count();

System.out.println(numWeekDays);

Выход:

32
person Jacob G.    schedule 22.04.2018
comment
Если вы статически импортируете SATURDAY и SUNDAY и используете EnumSet, вы даже можете написать EnumSet<DayOfWeek> weekend = EnumSet.of(SATURDAY, SUNDAY) и EnumSet<DayOfWeek> weekdays = EnumSet.complementOf(weekend), а затем выполнить .filter(weekdays::contains) для действительно чистого кода. :) - person David Conrad; 22.04.2018