【问题标题】:Calculate only working hours between two dates excluding weekends in Java仅计算两个日期之间的工作时间,不包括 Java 中的周末
【发布时间】:2017-10-09 18:39:55
【问题描述】:

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

感谢您的帮助。

【问题讨论】:

标签: java datetime hour weekday


【解决方案1】:

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

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;
    }
}

【讨论】:

    【解决方案2】:

    在我的头顶。

    我建议您首先研究带有子包的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 方法。您可能需要特别处理新的开始日期时间和结束日期时间在同一日期的情况。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-05
      • 2016-01-17
      • 1970-01-01
      • 2019-04-15
      • 2012-04-03
      • 1970-01-01
      相关资源
      最近更新 更多