LocalTime 持续时长计算

发布时间 2023-06-09 15:57:04作者: _Y_h
public class DurationUtil {
    private static final Logger log = LoggerFactory.getLogger(DurationUtil.class);

    public static double toHours(Temporal start, Temporal end) {
        long minutes = Duration.between(start, end).toMinutes();
        long hours = minutes / 60;
        double v = (minutes % 60) / 60D;
        return v + hours;
    }


    /**
     * 24小时内 两个时间段的重合区间
     * <pre>
     *     public static void main(String[] args) {
     *         {
     *             LocalTime formatStart = LocalTime.of(1, 0);
     *             LocalTime formatEnd = LocalTime.of(8, 0);
     *             LocalTime compareStart = LocalTime.of(21, 0);
     *             LocalTime compareEnd = LocalTime.of(8, 0);
     *             double v = toMillis(formatStart, formatEnd, compareStart, compareEnd) / 1000 / 60;
     *             System.out.println("shout 180 current is " + v);
     *         }
     *         {
     *             LocalTime formatStart = LocalTime.of(21, 0);
     *             LocalTime formatEnd = LocalTime.of(8, 0);
     *             LocalTime compareStart = LocalTime.of(21, 0);
     *             LocalTime compareEnd = LocalTime.of(8, 3);
     *             double v = toMillis(formatStart, formatEnd, compareStart, compareEnd) / 1000 / 60;
     *             System.out.println("shout 3 current is " + v);
     *         }
     *         {
     *             LocalTime formatStart = LocalTime.of(21, 0);
     *             LocalTime formatEnd = LocalTime.of(8, 0);
     *             LocalTime compareStart = LocalTime.of(20, 56);
     *             LocalTime compareEnd = LocalTime.of(8, 3);
     *             double v = toMillis(formatStart, formatEnd, compareStart, compareEnd) / 1000 / 60;
     *             System.out.println("shout 7 current is " + v);
     *         }
     *         {
     *             LocalTime formatStart = LocalTime.of(4, 0);
     *             LocalTime formatEnd = LocalTime.of(8, 0);
     *             LocalTime compareStart = LocalTime.of(20, 56);
     *             LocalTime compareEnd = LocalTime.of(8, 3);
     *             double v = toMillis(formatStart, formatEnd, compareStart, compareEnd) / 1000 / 60;
     *             System.out.println("shout  current is " + v);
     *         }
     *         {
     *             LocalTime formatStart = LocalTime.of(21, 0);
     *             LocalTime formatEnd = LocalTime.of(8, 0);
     *             LocalTime compareStart = LocalTime.of(20, 30);
     *             LocalTime compareEnd = LocalTime.of(4, 0);
     *             double v = toMillis(formatStart, formatEnd, compareStart, compareEnd) / 1000 / 60;
     *             System.out.println("shout 30 current is " + v);
     *         }
     *         {
     *             LocalTime formatStart = LocalTime.of(21, 0);
     *             LocalTime formatEnd = LocalTime.of(8, 0);
     *             LocalTime compareStart = LocalTime.of(21, 30);
     *             LocalTime compareEnd = LocalTime.of(4, 0);
     *             double v = toMillis(formatStart, formatEnd, compareStart, compareEnd) / 1000 / 60;
     *             System.out.println("shout 0 current is " + v);
     *         }
     *         {
     *             LocalTime formatStart = LocalTime.of(21, 0);
     *             LocalTime formatEnd = LocalTime.of(8, 0);
     *             LocalTime compareStart = LocalTime.of(20, 30);
     *             LocalTime compareEnd = LocalTime.of(20, 50);
     *             double v = toMillis(formatStart, formatEnd, compareStart, compareEnd) / 1000 / 60;
     *             System.out.println("shout 20 current is " + v);
     *         }
     *     }
     * </pre>
     */
    public static long toMillis(LocalTime formatStart, LocalTime formatEnd, LocalTime compareStart, LocalTime compareEnd) {
        List<LocalTimeDuration> build = LocalTimeDuration.build(formatStart, formatEnd);
        LocalTimeDuration formatMin = build.get(0);
        LocalTimeDuration formatMax = build.get(1);
        List<LocalTimeDuration> compares = LocalTimeDuration.build(compareStart, compareEnd);
        long result = 0;
        for (LocalTimeDuration compare : compares) {
            result += toMillis(formatMin, formatMax, compare);
        }
        return result;
    }

    private static long toMillis(LocalTimeDuration min, LocalTimeDuration max, LocalTimeDuration compare) {
        if (compare == LocalTimeDuration.empty) {
            return 0;
        }
        LocalTime start = compare.start;
        LocalTime end = compare.end;
        long result = 0;
        if (min != LocalTimeDuration.empty) {
            if (start.isBefore(min.start)) {
                if (end.isBefore(min.start)) {
                    return Duration.between(start, end).toMillis();
                } else {
                    result += Duration.between(start, min.start).toMillis();
                    start = min.end;
                }
            }
            if (min.isIn(start)) {
                start = min.end;
            }
        }

        if (start.isAfter(end)) {
            return result;
        }
        if (start.isBefore(max.start)) {
            if (end.isBefore(max.start)) {
                return result + Duration.between(start, end).toMillis();
            } else if (max.isIn(end)) {
                return result + Duration.between(start, max.start).toMillis();
            } else {
                result += Duration.between(start, max.start).toMillis();
                start = max.end;
            }
        } else if (max.isIn(start)) {
            if (end.isBefore(max.end)) {
                return result;
            } else {
                return result + Duration.between(max.end, end).toMillis();
            }
        } else {
            return result + Duration.between(start, end).toMillis();
        }
        if (start.isAfter(end)) {
            return result;
        }
        return result + Duration.between(start, end).toMillis();
    }


    /**
     * eg: start-> 21:00 end -> 08:00 checkTime -> 22:00 result is true
     * eg: start-> 21:00 end -> 08:00 checkTime -> 21:00 result is true
     * eg: start-> 21:00 end -> 08:00 checkTime -> 08:00 result is true
     * eg: start-> 21:00 end -> 08:00 checkTime -> 04:00 result is true
     * eg: start-> 21:00 end -> 08:00 checkTime -> 08:30 result is false
     * eg: start-> 08:00 end -> 12:00 checkTime -> 08:30 result is true
     * eg: start-> 08:00 end -> 12:00 checkTime -> 11:30 result is true
     * eg: start-> 08:00 end -> 16:00 checkTime -> 13:30 result is true
     * eg: start-> 08:00 end -> 16:00 checkTime -> 17:30 result is false
     */

    public static boolean timeInDuration(LocalTime start, LocalTime end, LocalTime time) {
        if (log.isDebugEnabled()) {
            log.debug("start [{}] end [{}] time[{}]", start, end, time);
        }
        List<LocalTimeDuration> durations = LocalTimeDuration.build(start, end);
        for (LocalTimeDuration duration : durations) {
            if (duration == LocalTimeDuration.empty) {
                continue;
            }
            if (duration.isIn(time)) {
                return true;
            }
        }
        return false;
    }

    private static class LocalTimeDuration {
        private static final LocalTimeDuration empty = new LocalTimeDuration(null, null);

        public final LocalTime start;
        public final LocalTime end;

        public LocalTimeDuration(LocalTime start, LocalTime end) {
            this.start = start;
            this.end = end;
        }

        public static LocalTimeDuration of(LocalTime start, LocalTime end) {
            return new LocalTimeDuration(start, end);
        }

        public static LocalTimeDuration max(LocalTime time) {
            return new LocalTimeDuration(time, LocalTime.MAX);
        }

        public static LocalTimeDuration min(LocalTime time) {
            return new LocalTimeDuration(LocalTime.MIN, time);
        }

        public static List<LocalTimeDuration> build(LocalTime start, LocalTime end) {
            if (start.isAfter(end)) {
                return Arrays.asList(min(end), max(start));
            }
            return Arrays.asList(empty, of(start, end));
        }

        /**
         * 全闭
         */
        public boolean isIn(LocalTime time) {
            //return start.isBefore(time) && end.isAfter(time);
            return time.equals(start) || (start.isBefore(time) && end.isAfter(time)) || end.equals(time);
        }

        public String toString() {
            if (start != null && end != null) {
                return start + "\t" + end;
            }
            return "";
        }
    }
}