You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java计算项目及任务时长始终返回0问题排查求助

排查项目时长计算始终返回0的问题

以下是几个可能的原因及对应的解决办法:

1. 毫秒转天数的精度问题

TimeUnit.DAYS.convert是向下取整计算,只要两个日期的毫秒差不足24小时(86400000毫秒),哪怕差23小时59分,结果都会是0天。比如任务开始于当天0点,结束于当天23点,计算后返回0。

解决办法:

改用按自然日期字段计算差值,而非纯毫秒数转换。推荐使用Java 8+的LocalDate(替代过时的Date/Calendar):

public static int computeDuration(Date from, Date to) {
    // 指定时区,避免时区偏差,比如ZoneId.of("Asia/Shanghai")
    ZoneId zone = ZoneId.systemDefault();
    LocalDate localFrom = from.toInstant().atZone(zone).toLocalDate();
    LocalDate localTo = to.toInstant().atZone(zone).toLocalDate();
    return Math.abs((int) ChronoUnit.DAYS.between(localFrom, localTo));
}

如果仍需使用Calendar,可以重置时间部分后再计算:

public static int computeDuration(Date from, Date to) {
    Calendar calFrom = Calendar.getInstance();
    calFrom.setTime(from);
    Calendar calTo = Calendar.getInstance();
    calTo.setTime(to);

    // 清空时间字段,只保留年月日
    calFrom.set(Calendar.HOUR_OF_DAY, 0);
    calFrom.set(Calendar.MINUTE, 0);
    calFrom.set(Calendar.SECOND, 0);
    calFrom.set(Calendar.MILLISECOND, 0);
    calTo.set(Calendar.HOUR_OF_DAY, 0);
    calTo.set(Calendar.MINUTE, 0);
    calTo.set(Calendar.SECOND, 0);
    calTo.set(Calendar.MILLISECOND, 0);

    long diffInMillis = Math.abs(calTo.getTimeInMillis() - calFrom.getTimeInMillis());
    return (int) TimeUnit.DAYS.convert(diffInMillis, TimeUnit.MILLISECONDS);
}

2. 初始minDate/maxDate的风险

当前代码直接用projectTasks[0]初始化minDate和maxDate,如果第一个任务的开始/结束日期相同,或者后续没有任务的日期超出这个范围,就会导致minDate和maxDate相等,计算出的时长为0。另外,如果projectTasks[0]为空或日期字段为空,还会引发空指针异常。

解决办法:

先遍历所有任务,动态初始化minDate和maxDate:

Date minDate = null;
Date maxDate = null;

// 第一步:遍历确定项目的最早开始和最晚结束日期
for (int i = 0; i < numOfTasks; ++i) {
    if (projectTasks[i] != null 
        && projectTasks[i].gettaskEndDate() != null 
        && projectTasks[i].gettaskFromDate() != null) {
        
        Date taskStart = projectTasks[i].gettaskFromDate();
        Date taskEnd = projectTasks[i].gettaskEndDate();
        
        if (minDate == null || taskStart.before(minDate)) {
            minDate = taskStart;
        }
        if (maxDate == null || maxDate.before(taskEnd)) {
            maxDate = taskEnd;
        }
    }
}

// 第二步:计算每个任务的时长
for (int i = 0; i < numOfTasks; ++i) {
    if (projectTasks[i] != null 
        && projectTasks[i].gettaskEndDate() != null 
        && projectTasks[i].gettaskFromDate() != null) {
        
        projectTasks[i].settaskDuration(
            utils.Globals.computeDuration(
                projectTasks[i].gettaskFromDate(), 
                projectTasks[i].gettaskEndDate()
            )
        );
    }
}

// 第三步:计算项目总时长(处理无有效任务的情况)
if (minDate != null && maxDate != null) {
    setprojectDuration(utils.Globals.computeDuration(minDate, maxDate));
} else {
    setprojectDuration(0); // 或根据业务需求抛出异常
}

3. 日期对象的实际值异常

如果任务的开始/结束日期被设置为同一个时间点(毫秒数相同),或者所有任务的日期范围没有跨度,计算结果自然是0。

排查办法:

在computeDuration方法中添加日志,打印日期的毫秒值和差值,确认数据是否正常:

public static int computeDuration(Date from, Date to){
    long fromMillis = from.getTime();
    long toMillis = to.getTime();
    long diffIn = Math.abs(toMillis - fromMillis);
    
    System.out.printf("From: %s (%dms), To: %s (%dms), 差值: %dms%n", 
                      from, fromMillis, to, toMillis, diffIn);
    
    int duration = (int) TimeUnit.DAYS.convert(diffIn, TimeUnit.MILLISECONDS);
    System.out.println("计算出的时长: " + duration);
    
    return duration;
}

4. 冗余的validateDates方法

当前validateDates方法只是封装了from.before(to),直接在判断中使用原方法即可,减少不必要的方法调用,逻辑更直观。


内容的提问来源于stack exchange,提问作者dannyph

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 13:08:09