如何用Java Date and Time或Joda-Time创建不重叠日历事件
嘿,这个需求我之前做类似功能时刚好研究过,用Java 8引入的java.time日期时间API就能完美搞定——毕竟现在Joda-Time已经进入维护状态了,官方更推荐用原生的java.time。下面我一步步给你讲怎么实现:
第一步:定义符合要求的Event类
你提到想创建包含四个变量的类,其实不用自己拆分年月日,直接用java.time.LocalDate来封装开始和结束日期更简洁,还能避免手动处理日期逻辑的bug。我们可以给类加校验逻辑,确保事件本身符合规则:
import java.time.LocalDate; // Java 16+用record更简洁,也可以用普通class public record Event(String name, LocalDate start, LocalDate end) { // 自定义构造器做参数校验 public Event { // 确保开始时间早于结束时间 if (start.isAfter(end) || start.isEqual(end)) { throw new IllegalArgumentException("事件开始时间必须早于结束时间"); } // 确保事件在3月1日(不含)到3月31日(不含)之间 LocalDate marchStart = LocalDate.of(start.getYear(), 3, 1); LocalDate marchEnd = LocalDate.of(start.getYear(), 3, 31); if (start.isBefore(marchStart) || end.isAfter(marchEnd)) { throw new IllegalArgumentException("事件必须落在3月1日至3月31日之间(不含首尾)"); } if (start.isEqual(marchStart) || end.isEqual(marchEnd)) { throw new IllegalArgumentException("事件不能包含3月1日或3月31日"); } } }
第二步:实现事件管理与重叠校验
接下来需要一个管理类来添加事件,同时校验新事件和已有事件是否重叠。判断两个事件是否重叠的逻辑很简单:如果新事件的开始时间晚于已有事件的结束时间,或者新事件的结束时间早于已有事件的开始时间,就不重叠,反之则重叠。
import java.time.LocalDate; import java.util.ArrayList; import java.util.List; public class EventManager { private final List<Event> events = new ArrayList<>(); private final LocalDate marchStart; private final LocalDate marchEnd; // 指定年份,针对该年的3月创建事件 public EventManager(int year) { this.marchStart = LocalDate.of(year, 3, 1); this.marchEnd = LocalDate.of(year, 3, 31); } // 添加事件,返回是否添加成功 public boolean addEvent(Event event) { // 二次校验(可选,因为Event构造器已经做了基础校验) if (event.start().isBefore(marchStart) || event.end().isAfter(marchEnd) || event.start().isEqual(marchStart) || event.end().isEqual(marchEnd)) { System.out.println("错误:事件不在允许的时间范围内"); return false; } // 检查是否与已有事件重叠 for (Event existingEvent : events) { if (isOverlapping(event, existingEvent)) { System.out.println("错误:事件与「" + existingEvent.name() + "」重叠"); return false; } } events.add(event); return true; } // 判断两个事件是否重叠的工具方法 private boolean isOverlapping(Event newEvent, Event existingEvent) { return !(newEvent.start().isAfter(existingEvent.end()) || newEvent.end().isBefore(existingEvent.start())); } // 打印所有已添加的事件 public void printAllEvents() { events.forEach(event -> System.out.println(event.name() + ":" + event.start() + " 至 " + event.end()) ); } }
第三步:测试使用
写个主类来验证功能,看看合法事件、重叠事件、违规事件的处理效果:
public class Main { public static void main(String[] args) { EventManager manager = new EventManager(2024); // 添加合法事件,会成功 manager.addEvent(new Event("Event1", LocalDate.of(2024, 3, 3), LocalDate.of(2024, 3, 5))); manager.addEvent(new Event("Event2", LocalDate.of(2024, 3, 6), LocalDate.of(2024, 3, 10))); manager.addEvent(new Event("Event3", LocalDate.of(2024, 3, 13), LocalDate.of(2024, 3, 25))); // 尝试添加重叠事件,会失败 manager.addEvent(new Event("Event4", LocalDate.of(2024, 3, 9), LocalDate.of(2024, 3, 12))); // 尝试添加包含3月1日的事件,会失败 manager.addEvent(new Event("Event5", LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 2))); // 打印最终合法的事件列表 manager.printAllEvents(); } }
关于Joda-Time的实现思路
如果因为项目限制必须用Joda-Time,思路和上面完全一致,只是把java.time.LocalDate换成org.joda.time.LocalDate,核心的isBefore()、isAfter()、isEqual()方法用法几乎一样,事件类和管理类的逻辑可以直接照搬,只是导入的包不同。
额外小提示
- 如果需要按时间顺序展示事件,可以在添加后对
events列表排序:Collections.sort(events, Comparator.comparing(Event::start)) - 要是需要支持跨年份的3月事件,只需要调整
EventManager的初始化逻辑,不用固定年份即可
内容的提问来源于stack exchange,提问作者user8203210
相关产品推荐
相关产品推荐

