使用DateUtil.between遇到的坑
在使用EasyExcel做导出功能的时候需要生成一个横向扩展的动态表头,列如这样
通过使用DateUtil.between方法来计算最小时间和最大时间中间的天数,来判断到底需要横向扩展多少个。代码如下
long between = DateUtil.between(ApsDateUtils.beginOfDay(responseList.get(responseList.size() - 1).getStartTime()),
ApsDateUtils.beginOfDay(responseList.get(0).getStartTime()),
DateUnit.DAY) + 1;
Date startTime = responseList.get(responseList.size() - 1).getStartTime();
for (int i = 0; i < between; i++) {
String time = ApsDateUtils.year(startTime) + "年" + (ApsDateUtils.month(startTime) + 1) + "月" + ApsDateUtils
.dayOfMonth(startTime) + "日";
List<String> head4 = new ArrayList<>();
head4.add(time);
head4.add("订单号");
list.add(head4);
List<String> head5 = new ArrayList<>();
head5.add(time);
head5.add("物料号");
list.add(head5);
List<String> head6 = new ArrayList<>();
head6.add(time);
head6.add("计划数量");
list.add(head6);
List<String> head7 = new ArrayList<>();
head7.add(time);
head7.add("交货数量");
list.add(head7);
startTime = ApsDateUtils.getNextDay(startTime);
}
最开始没有出现问题,后来某一天突然出现计算出来的天数少了一天,写测试类测试之后发现当最大时间和最小时间的时分秒不一样时会出现这个问题。
String start = "2022-09-27 00:00:00";
//String start1 = "2022-09-27 08:00:00"; 此时算出来的between是8,比正常的要少一天
String end = "2022-10-05 00:00:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date startTime = sdf.parse(start);
Date endTime = sdf.parse(end);
long between = DateUtil.between(endTime, startTime, DateUnit.DAY) + 1;
for (int i = 0; i < between; i++) {
String time = DateUtil.year(startTime) + "年" + (DateUtil.month(startTime) + 1) + "月" + ApsDateUtils
.dayOfMonth(startTime) + "日";
System.out.println(time);
startTime = ApsDateUtils.getNextDay(startTime);
}
输出结果
在研究了between方法的源码之后发现,他是通过两个时间的时间戳相减,然后在除以对应日期单位的毫秒数来获取的。并不是我以为的取日期单位对应的数据直接去比较,比如取相差天数就不考虑时分秒。
时间戳相减
/**
* 判断两个日期相差的时长<br>
* 返回 给定单位的时长差
*
* @param unit 相差的单位:相差 天{@link DateUnit#DAY}、小时{@link DateUnit#HOUR} 等
* @return 时长差
*/
public long between(DateUnit unit) {
long diff = end.getTime() - begin.getTime();
return diff / unit.getMillis();
}
获取日期单位对应的毫秒数
public enum DateUnit {
/** 一毫秒 */
MS(1),
/** 一秒的毫秒数 */
SECOND(1000),
/**一分钟的毫秒数 */
MINUTE(SECOND.getMillis() * 60),
/**一小时的毫秒数 */
HOUR(MINUTE.getMillis() * 60),
/**一天的毫秒数 */
DAY(HOUR.getMillis() * 24),
/**一周的毫秒数 */
WEEK(DAY.getMillis() * 7);
private final long millis;
DateUnit(long millis){
this.millis = millis;
}
/**
* @return 单位对应的毫秒数
*/
public long getMillis(){
return this.millis;
}
}
最后在看源码的时候发现了一个比较有趣的东西
这一个方法好像会自动置换大小值,保证输出的结果是正数,如果这样的话,在使用的时候是不是可以不用去考虑输入值的大小关系,不过具体的我没有测试过。
/**
* 构造<br>
* 在前的日期做为起始时间,在后的做为结束时间
*
* @param begin 起始时间
* @param end 结束时间
* @param isAbs 日期间隔是否只保留绝对值正数
* @since 3.1.1
*/
public DateBetween(Date begin, Date end, boolean isAbs) {
Assert.notNull(begin, "Begin date is null !");
Assert.notNull(end, "End date is null !");
if (isAbs && begin.after(end)) {
// 间隔只为正数的情况下,如果开始日期晚于结束日期,置换之
this.begin = end;
this.end = begin;
} else {
this.begin = begin;
this.end = end;
}
}