Подтвердить что ты не робот

Добавление рабочего времени в Java DateTime

Для системы отслеживания проблем мне нужно рассчитать время отклика для запроса. Таймер для времени отклика должен работать только в рабочее время. Какой алгоритм/библиотеку следует использовать для этой задачи? (Конечно, я знаю о Joda-Time или ObjectLab Kit, но не смог найти ничего полезного в моей задаче. Я что-то пропустил?)

Пример:

  • Время работы: с 9:00 до 17:00 (8 часов в день).
  • Максимальное время отклика: 16 часов

Метод может выглядеть примерно так:

DateTime calculateResponseTime(DateTime issueReportedAt)

Я приведу несколько возможных входов и результатов в качестве примера:

  • Пн, 2011-09-19, 13:00 → Ср, 2011-09-21, 13:00
  • Пн, 2011-09-19, 6:05 pm → Thu, 2011-09-22, 9:00 am
  • Пт, 2011-09-23, 2:00 pm → Вт, 2011-09-27, 2:00 вечера
4b9b3361

Ответ 1

Вы можете взглянуть на бизнес-календарь jBPM.

Другая библиотека позволяет настраивать праздничные дни в банке, но у нее нет понятия рабочего времени.

Ответ 2

Я думаю, что Олег предлагал взглянуть на то, как jBPM реализует эту функциональность для вдохновения для кодирования собственного решения. Ниже мой ответ сильно заимствован из источника, который я нашел, выполнив Поиск кода Google.

Это не учитывает праздники, но я оставлю это как упражнение для вас. Могу ли я предложить использовать веб-сервис для ежегодного обновления списка ограниченных дат? Удачи!

    int fromHour = 9;
int fromMinute = 0;
int toHour = 17;
int toMinute = 0;
long maxResponseTime = 16;

Date calculateResponseTime(Date issueReportedAt, long responseHours) {

    Date end = null;

    Calendar responseTime = Calendar.getInstance();
    responseTime.setTime(issueReportedAt);

    int hourOfDay = responseTime.get(Calendar.HOUR_OF_DAY);
    int dayOfWeek = responseTime.get(Calendar.DAY_OF_WEEK);

    if (hourOfDay < fromHour) {
        responseTime.set(Calendar.HOUR, fromHour);

    }

    if (hourOfDay >= toHour || dayOfWeek == 1) {
        responseTime.add(Calendar.DATE, 1);
        responseTime.set(Calendar.HOUR_OF_DAY, fromHour);
        responseTime.set(Calendar.MINUTE, fromMinute);

    } else if (dayOfWeek == 7) {
        responseTime.add(Calendar.DATE, 2);
        responseTime.set(Calendar.HOUR_OF_DAY, fromHour);
        responseTime.set(Calendar.MINUTE, fromMinute);

    }

    int hour = responseTime.get(Calendar.HOUR_OF_DAY);
    int minute = responseTime.get(Calendar.MINUTE);

    long dateMilliseconds = ((hour * 60) + minute) * 60 * 1000;
    long dayPartEndMilleseconds = ((toHour * 60) + toMinute) * 60 * 1000;
    long millisecondsInThisDayPart = dayPartEndMilleseconds
            - dateMilliseconds;

    long durationMilliseconds = responseHours * 60 * 60 * 1000;

    if (durationMilliseconds < millisecondsInThisDayPart) {
        end = new Date(responseTime.getTimeInMillis()
                + durationMilliseconds);
    } else {
        long remainder = (durationMilliseconds - millisecondsInThisDayPart) / 60 / 60 / 1000;
        Date dayPartEndDate = new Date(responseTime.getTimeInMillis()
                + durationMilliseconds);

        responseTime.setTime(dayPartEndDate);

        end = calculateResponseTime(responseTime.getTime(), remainder);
    }

    return end;

}

@Test
public void testCalculateResponseTime() {

    Calendar issueReportedAt = Calendar.getInstance();
    Calendar expectedResponseTime = Calendar.getInstance();

    issueReportedAt.set(2011, 8, 19, 13, 0, 0);
    expectedResponseTime.set(2011, 8, 21, 13, 0, 0);

    assertTrue(expectedResponseTime.getTime().equals(
            calculateResponseTime(issueReportedAt.getTime(),
                    maxResponseTime)));

    issueReportedAt.set(2011, 8, 19, 18, 5, 0);
    expectedResponseTime.set(2011, 8, 22, 9, 0, 0);

    assertTrue(expectedResponseTime.getTime().equals(
            calculateResponseTime(issueReportedAt.getTime(),
                    maxResponseTime)));

    issueReportedAt.set(2011, 8, 23, 14, 0, 0);
    expectedResponseTime.set(2011, 8, 27, 14, 0, 0);

    assertTrue(expectedResponseTime.getTime().equals(
            calculateResponseTime(issueReportedAt.getTime(),
                    maxResponseTime)));

}

Ответ 3

Вам нужно добавить дополнительный случай if в нормализованную часть от ответа Anils, потому что, если проблема сообщается в пятницу 10:00, а responseHours - 10, то в следующем рекурсивном вызове issueReportedAt будет в пятницу 10 вечера, ведьма будет нормализована до субботы 9:00 вечера, ведьма также недействительна.

if (hourOfDay >= WorkingHours.TO_HOUR && dayOfWeek == Calendar.FRIDAY) {
        responseTime.add(Calendar.DATE, 3);
        responseTime.set(Calendar.HOUR_OF_DAY, WorkingHours.FROM_HOUR);
        responseTime.set(Calendar.MINUTE, WorkingHours.FROM_MINUTE);
}

Ответ 4

Ниже код решает эту проблему

public static Date addBusinessHours(Calendar startDate, int hours, int workingHourStart, int workingHourEnd){
    System.out.println("Entering: Date Time " + startDate.getTime() + " | Remaining Hours: "+ hours + " | Working hours ("+workingHourStart+"-"+workingHourEnd+")");

    if(hours == 0){
        return startDate.getTime();
    }
    int hourOfDay = startDate.get(Calendar.HOUR_OF_DAY);
    if(startDate.get(Calendar.MINUTE) > 0){
        hourOfDay = hourOfDay +1;
    }

    int dayOfWeek = startDate.get(Calendar.DAY_OF_WEEK);

    if(dayOfWeek == Calendar.SATURDAY){
        startDate.add(Calendar.DATE, 2);
        startDate.set(Calendar.HOUR_OF_DAY, workingHourStart);
        startDate.set(Calendar.MINUTE, 0);
        startDate.set(Calendar.SECOND, 0);
        addBusinessHours(startDate, hours, workingHourStart, workingHourEnd);
    }
    if(dayOfWeek == Calendar.SUNDAY){
        startDate.add(Calendar.DATE, 1);
        startDate.set(Calendar.HOUR_OF_DAY, workingHourStart);
        startDate.set(Calendar.MINUTE, 0);
        startDate.set(Calendar.SECOND, 0);
        addBusinessHours(startDate, hours, workingHourStart, workingHourEnd);
    }

    if(dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY){
        if(hourOfDay < workingHourStart){
            startDate.set(Calendar.HOUR_OF_DAY, workingHourStart);
            startDate.set(Calendar.MINUTE, 0);
            startDate.set(Calendar.SECOND, 0);
            hourOfDay = startDate.get(Calendar.HOUR_OF_DAY);
            dayOfWeek = startDate.get(Calendar.DAY_OF_WEEK);
            addBusinessHours(startDate, hours, workingHourStart, workingHourEnd);
        }
        else if(hourOfDay >= workingHourEnd){

            startDate.add(Calendar.DATE, 1);
            startDate.set(Calendar.HOUR_OF_DAY, workingHourStart);
            startDate.set(Calendar.MINUTE, 0);
            startDate.set(Calendar.SECOND, 0);
            hourOfDay = startDate.get(Calendar.HOUR_OF_DAY);
            dayOfWeek = startDate.get(Calendar.DAY_OF_WEEK);
            addBusinessHours(startDate, hours, workingHourStart, workingHourEnd);
        }

        else if(hourOfDay >= workingHourStart && hourOfDay < workingHourEnd){
            if(hours+hourOfDay <= workingHourEnd){
                startDate.add(Calendar.HOUR_OF_DAY, hours);
                return startDate.getTime();
            }else{
                //System.out.println("¤¤" + startDate.getTime() );
                startDate.add(Calendar.DATE, 1);
                //System.out.println("¤¤" + startDate.getTime() );
                startDate.set(Calendar.HOUR_OF_DAY, workingHourStart);
                startDate.set(Calendar.MINUTE, 0);
                startDate.set(Calendar.SECOND, 0);
                //System.out.println("¤¤" + startDate.getTime() );

                System.out.println("##"+hours+ "##"+ workingHourEnd + "##" + hourOfDay);
                int remaining_hours = hours - (workingHourEnd - hourOfDay);
                addBusinessHours(startDate, remaining_hours, workingHourStart, workingHourEnd);
            }
        }
    }

    return startDate.getTime();
}