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

MID*_*AFI 7 java datetime hour weekday

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

谢谢你的帮助。

Ant*_*Kot 5

每个人!我遇到了类似的问题(计算时间戳之间的工作分钟数)并完成了这个解决方案。希望,有人发现它有用:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Ole*_*.V. 1

从我的头顶掉下来。

\n\n

我建议您首先研究java.time带有子包的包,即现代 Java 日期和时间 API。这里有\xe2\x80\x99s一个Oracle教程以及其他不错的阅读材料,去搜索一下。

\n\n

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

\n\n

考虑是否需要考虑时区和夏令时 (DST)。由于夏令时转换通常发生在晚上而不是工作时间,我想不会,但请自行决定。如果您(可能)需要这个,请依赖ZonedDateTime对象,否则LocalDateTime

\n\n

我首先会为工作时间计算编写一个好的单元测试。您可能还想编写一个用于从输入字符串到 或 的转换LocalDateTimeZonedDateTime但这里不需要进行大量测试。

\n\n

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

\n\n

型号/工时计算

\n\n

这个问题的启发,我认为如果开始和结束日期时间不在工作时间,调整开始和结束日期时间会很方便。例如,如果开始时间是星期六凌晨 3 点,请将其移至工作日开始时的星期一。如果结束时间是星期六凌晨 3 点,则将其移至星期五工作日结束时。您将需要getDayOfWeektoLocalDateminusDaysplusDays和 等方法atTime,具体取决于您想要执行此操作的具体方式。您可能也想跳过这一步,稍后您会发现是否值得。或者也许只移动一天中的时间而不改变日期。

\n\n

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

\n\n

此时情况变得更加复杂,因为您需要查看这些天是否是工作日以及工作日的结束和开始时间。该类Duration可以方便地总结每个工作日从新的开始日期时间到结束日期时间的小时、分钟和秒数。您可以使用它的betweenplus方法。您可能需要特别处理新的开始日期时间和结束日期时间位于同一日期的情况。

\n\n

看看这是否不能让您开始。

\n