马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
"日期区间"是一个很老也很实用的分析模式:把一段起止时间建模成一个对象,而不是散落在代码里的两个 Date 变量。这样做的好处是——区间作为一个整体可以被比较、被包含判断、被传参,边界逻辑不会散架。本文以 Java 写法讲清它的核心方法设计。
先定义:一个区间长什么样
class DateRange {
private final MfDate start;
private final MfDate end;
}
两个端点就够了。构造函数里用 new MfDate(...) 包一层,是为了把"外部传进来的可变日期"转成内部的稳定表示,避免调用方事后改了对象、区间跟着动。
边界处理:左闭右开,别凭感觉
日期区间的坑几乎都出在"端点算不算在内"。两种常见约定:
| 约定 | 含义 | 适合场景 |
左闭右开 [start, end) | 含开始、不含结束 | 按天统计、时间轴分段、SQL 区间查询 |
左闭右闭 [start, end] | 两端都含 | 合同期、有效期这类业务区间 |
选定一种之后写进注释、全局一致,比什么都重要。两套混用几乎必然出现"少算一天/多算一天"的 bug。
核心方法:includes
这是整个模式最关键的方法——判断某个时点是否落在这个区间内:
public boolean includes(MfDate arg) {
return !arg.before(start) && !arg.after(end);
}
写法上用"不小于起点 且 不晚于终点"而不是 arg >= start,是为了让比较逻辑集中在一处,端点语义调整时只改方法体。
传入另一个区间也能复用同一套判断:
public boolean includes(DateRange arg) {
return this.includes(arg.start) && this.includes(arg.end);
}
public boolean overlaps(DateRange arg) {
return arg.includes(start) || arg.includes(end) || this.includes(arg);
}
overlaps(是否有交集)由三个条件组合出来,没有重写一遍复杂的区间相交公式,这是组合复用带来的收益。
开区间与空缺的构造
public static DateRange upTo(MfDate end) {
return new DateRange(MfDate.PAST, end);
}
public static DateRange startingOn(MfDate start) {
return new DateRange(start, MfDate.FUTURE);
}
public static DateRange EMPTY = new DateRange(new MfDate(2000, 4, 1), new MfDate(2000, 1, 1));
用常量 PAST / FUTURE 表示无限延伸的端点,调用方读起来就是"到某天为止""从某天开始",比传 null 再到处判空干净得多。EMPTY 用一组倒置的日期表示空区间,配合下面的判空方法。
判空与相等性
public boolean isEmpty() {
return start.after(end);
}
@Override
public boolean equals(Object arg) {
if (!(arg instanceof DateRange)) return false;
DateRange other = (DateRange) arg;
return start.equals(other.start) && end.equals(other.end);
}
@Override
public int hashCode() {
return start.hashCode();
}
两个细节值得记住:空区间用"起止倒置"表达,不用额外布尔字段;重写 equals 必须同时重写 hashCode,否则放进 HashMap / HashSet 后行为诡异。
toString 方便排查
public String toString() {
if (isEmpty()) return "Empty Date Range";
return start.toString() + " - " + end.toString();
}
日志 里直接打区间对象就能看懂,省掉一句 dateRange.getStart() + " ~ " + dateRange.getEnd()。
这套模式能用在哪
- 统计口径统一。按天/按月/按财务期间的报表查询,全用同一个 DateRange 构造 SQL 的
BETWEEN 条件。
- 有效期校验。合同、优惠券、订阅的有效期判断,一行
range.includes(now) 搞定。
- 时间轴分段。把一整年切成多个区间做分桶统计,重叠判断交给
overlaps。
- 权限/生效时间。角色、功能灰度的时间窗,用区间对象传递比两个裸时间变量安全。
一句话总结:把"两个日期"升级成"一个区间对象",边界规则收敛到一处,业务代码里就不会再到处出现 >= 和 < 的散装比较。
qidao123.com企服评测-应用市场 编辑提示
本文由齐道123 IT 运维社区整理,介绍《分析模式:可重用对象模型》中"日期区间"这一分析模式的 Java 实现思路与工程取舍。文中代码为原理示例,仅作技术讨论,不含任何第三方链接;实际项目请结合团队规范补充单元测试,尤其覆盖边界日期与空区间场景。
|