Java中如何简洁判断LocalDateTime是否在指定营业时间区间
需求说明
需要校验给定LocalDateTime实例是否在商家营业时间范围内,营业时间规则如下:
- 周一至周五:8:00 - 12:30、14:00 - 18:00
- 周六:8:00 - 14:00
原有实现存在大量重复逻辑,需要更整洁、可读性更高的写法,可借助Java 8 Lambda特性完成优化。原有实现代码如下:
static boolean duringWorkingHours(LocalDateTime dateTime){ //MO - FR 08:00 - 12:30 //MO - FR 14:00 - 18:00 //SA 08:00 - 14:00 LocalDateTime morningStart = dateTime.with(LocalTime.of(8,0)); LocalDateTime morningEnd = dateTime.with(LocalTime.of(12,30)); LocalDateTime afternoonStart = dateTime.with(LocalTime.of(14,0)); LocalDateTime afternoonEnd = dateTime.with(LocalTime.of(18,0)); LocalDateTime saturdayStart = dateTime.with(LocalTime.of(8,0)); LocalDateTime saturdayEnd = dateTime.with(LocalTime.of(14,0)); Set<DayOfWeek> weekDays = Set.of(DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY,DayOfWeek.FRIDAY); boolean isWeekDay = weekDays.contains(dateTime.getDayOfWeek()); boolean isSaturday = dateTime.getDayOfWeek() == DayOfWeek.SATURDAY; boolean isMorning = (dateTime.isEqual(morningStart) || dateTime.isEqual(morningEnd)) || (dateTime.isAfter(morningStart) && dateTime.isBefore(morningEnd)); boolean isAfternoon = (dateTime.isEqual(afternoonStart) || dateTime.isEqual(afternoonEnd)) || (dateTime.isAfter(afternoonStart) && dateTime.isBefore(afternoonEnd)); boolean isSaturdayRange = (dateTime.isEqual(saturdayStart) || dateTime.isEqual(saturdayEnd)) || (dateTime.isAfter(saturdayStart) && dateTime.isBefore(saturdayEnd)); return (isWeekDay && isMorning) || (isWeekDay && isAfternoon) || (isSaturday && isSaturdayRange); }
优化方案
原有代码最大的冗余点是每次都基于传入时间构造多个LocalDateTime实例做区间判断,实际上只需要提取传入时间的DayOfWeek(判断周几)和LocalTime(判断当天时间点)即可完成校验,不需要构造多余的日期对象。
优化后将营业规则抽为静态配置,和判断逻辑解耦,借助Stream Lambda简化多时段匹配逻辑,代码如下:
import java.time.DayOfWeek; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.List; import java.util.Map; public class WorkingHoursValidator { // 抽离公共时段配置,避免重复定义 private static final List<TimeRange> WEEKDAY_RANGES = List.of( new TimeRange(LocalTime.of(8, 0), LocalTime.of(12, 30)), new TimeRange(LocalTime.of(14, 0), LocalTime.of(18, 0)) ); private static final List<TimeRange> SATURDAY_RANGES = List.of( new TimeRange(LocalTime.of(8, 0), LocalTime.of(14, 0)) ); // 按星期几映射对应营业时段,后续调整规则直接修改该配置即可 private static final Map<DayOfWeek, List<TimeRange>> WORKING_HOURS_RULES = Map.of( DayOfWeek.MONDAY, WEEKDAY_RANGES, DayOfWeek.TUESDAY, WEEKDAY_RANGES, DayOfWeek.WEDNESDAY, WEEKDAY_RANGES, DayOfWeek.THURSDAY, WEEKDAY_RANGES, DayOfWeek.FRIDAY, WEEKDAY_RANGES, DayOfWeek.SATURDAY, SATURDAY_RANGES ); static boolean duringWorkingHours(LocalDateTime dateTime) { List<TimeRange> todayRanges = WORKING_HOURS_RULES.get(dateTime.getDayOfWeek()); if (todayRanges == null) { return false; // 周日无营业配置直接返回false } LocalTime checkTime = dateTime.toLocalTime(); // 用Lambda判断是否匹配任意一个营业时段 return todayRanges.stream().anyMatch(range -> range.contains(checkTime)); } // 内部时间区间类,封装闭区间判断逻辑 private static class TimeRange { private final LocalTime start; private final LocalTime end; public TimeRange(LocalTime start, LocalTime end) { this.start = start; this.end = end; } public boolean contains(LocalTime time) { // 等价于 >= start 且 <= end,包含边界时间点 return !time.isBefore(start) && !time.isAfter(end); } } }
优化点说明
- 去掉冗余的
LocalDateTime构造:仅提取星期和时间点做判断,减少不必要的对象创建,逻辑更直观 - 配置与逻辑解耦:营业规则统一维护在静态配置中,后续调整营业时间、新增营业时段不需要修改核心判断逻辑
- 消除重复判断代码:抽离时间区间类统一做边界判断,避免多段重复的
isEqual/isAfter/isBefore组合判断,降低出错概率 - 用Stream的
anyMatch实现多时段匹配,语义清晰,代码简洁 - 公共时段复用:周一到周五的相同时段只定义一次,避免重复代码
内容的提问来源于stack exchange,提问作者bbKing
相关产品推荐
相关产品推荐

