计算两个日期之间的工作时间,不包括Java中的周末

时间:2017-05-10 22:56:05

标签: java datetime hour weekday

我需要帮助, 如何计算两个日期之间的营业时间? 例如,我们有两个日期; 01/01/2017 10:00和04/01/2017 15:00 我们工作时间的工作时间为09:30至17:30(8小时)。如何使用Java计算工作时间和分钟?

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

脱离我的头顶。

我建议您首先研究带有子包的java.time包,现代Java日期和时间API。网上有an Oracle tutorial以及其他好的阅读材料,请搜索。

接下来,我将模型(域,业务层)与(用户)接口分开。我假设01/01/2017 10:00是来自某个地方的输入字符串。我认为这是接口。在您的模型中,您将需要为数据使用日期时间类和对象。

考虑是否需要考虑时区和夏令时(DST)。由于夏季时间过渡通常发生在夜晚,而不是在工作时间,我不这么认为,但要做出自己的决定。如果您(可能)需要此功能,请依赖ZonedDateTime个对象,否则LocalDateTime

我首先要为工时计算编写一个好的单元测试。您可能还想为输入字符串转换为LocalDateTimeZonedDateTime编写一个,但此处不需要进行大量测试。

我会使用DateTimeFormatter将您的两个日期时间值解析为LocalDateTime个对象。如果您需要转换为.atZone(),请ZonedDateTime

模型/工时计算

this question启发我认为如果它们超出工作时间,则可以方便地调整开始和结束日期时间。例如,如果开始时间是星期六凌晨3点,则在工作日开始时将其移至星期一。如果结束时间是周六凌晨3点,则在工作日结束时将其移至星期五。您需要getDayOfWeektoLocalDateminusDaysplusDaysatTime等方法,具体取决于您要执行此操作的具体方式。您可能还想跳过此步骤,稍后您会看到是否值得。或者可能只是移动时间而不是改变一天。

接下来,您需要ChronoUnit枚举。例如,使用ChronoUnit.WEEKS.between(startDateTime, endDateTime)开始查找您的间隔中的整周数。乘以每周的工作小时数。一个看似有吸引力的选项是将小时存储到Duration对象中,因为我认为无论如何我们将需要一个小时。同时将周数添加到您的开始时间,以便您有剩余工作时间(天和小时)的间隔。

此时它变得越来越复杂,因为您需要查看日期是工作日以及工作日的结束和开始时间。 Duration类可以方便地将每个工作日的小时,分​​钟和秒从新的开始日期时间到结束日期时间相加。您可以使用其betweenplus方法。您可能需要特别处理新的开始日期时间和结束日期时间在同一日期的情况。

看看这是不是让你开始。

答案 1 :(得分:1)

大家!我遇到了类似的问题(计算到TimeStamps之间的工作时间)并完成了此解决方案。希望有人发现它有用:

public class WorkingMinutesCalculator {
    private static final int WORK_HOUR_START = 9;
    private static final int WORK_HOUR_END = 17;
    private static final long MINUTES = 60;

    private static final long WORKING_HOURS_PER_DAY = WORK_HOUR_END - WORK_HOUR_START;
    private static final long WORKING_MINUTES_PER_DAY = WORKING_HOURS_PER_DAY * MINUTES;

    public int getWorkingMinutesSince(final Timestamp startTime) {
        Timestamp now = Timestamp.from(Instant.now());
        return getWorkingMinutes(startTime, now);
    }

    public int getWorkingMinutes(final Timestamp startTime, final Timestamp endTime) {
        if (null == startTime || null == endTime) {
            throw new IllegalStateException();
        }
        if (endTime.before(startTime)) {
            return 0;
        }

        LocalDateTime from = startTime.toLocalDateTime();
        LocalDateTime to = endTime.toLocalDateTime();

        LocalDate fromDay = from.toLocalDate();
        LocalDate toDay = to.toLocalDate();

        int allDaysBetween = (int) (ChronoUnit.DAYS.between(fromDay, toDay) + 1);
        long allWorkingMinutes = IntStream.range(0, allDaysBetween)
                .filter(i -> isWorkingDay(from.plusDays(i)))
                .count() * WORKING_MINUTES_PER_DAY ;

        // from - working_day_from_start
        long tailRedundantMinutes = 0;
        if (isWorkingDay(from)) {
            if (isWorkingHours(from)) {
                tailRedundantMinutes = Duration.between(fromDay.atTime(WORK_HOUR_START, 0), from).toMinutes();
            } else if (from.getHour() > WORK_HOUR_START) {
                tailRedundantMinutes = WORKING_MINUTES_PER_DAY;
            }
        }

        // working_day_end - to
        long headRedundanMinutes = 0;
        if (isWorkingDay(to)) {
            if (isWorkingHours(to)) {
                headRedundanMinutes = Duration.between(to, toDay.atTime(WORK_HOUR_END, 0)).toMinutes();
            } else if (from.getHour() < WORK_HOUR_START) {
                headRedundanMinutes = WORKING_MINUTES_PER_DAY;
            }
        }
        return (int) (allWorkingMinutes - tailRedundantMinutes - headRedundanMinutes);
    }

    private boolean isWorkingDay(final LocalDateTime time) {
        return time.getDayOfWeek().getValue() < DayOfWeek.SATURDAY.getValue();
    }

    private boolean isWorkingHours(final LocalDateTime time) {
        int hour = time.getHour();
        return WORK_HOUR_START <= hour && hour <= WORK_HOUR_END;
    }
}