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

Java中计算1月至2月日期间隔为何得到28天?

问题原因分析与解决方案

核心问题:Calendar的月份索引规则

你遇到的结果不符,根源是Calendar类的月份采用0-based索引:

  • 调用getDate(2023, 01, 01)时,cal.set(Calendar.MONTH, 01)会把月份设置为二月(Calendar中0代表一月,1代表二月),而非你预期的一月一日。
  • 同理,getDate(2023, 02, 01)生成的是三月一日。

2023年2月只有28天,所以2月1日到3月1日的间隔自然是28天,和你预期的1月1日到2月1日(31天)完全是两个时间区间。

次要隐患:毫秒计算天数的缺陷

同事的getDaysBetween方法直接通过毫秒差除以1000*60*60*24计算天数,这种方式存在隐性问题:

  • 夏令时切换时,一天的毫秒数会变成2336001000或2536001000,导致计算结果偏差;
  • 闰秒的存在也会让实际毫秒数和理论值不符。

修正方案

1. 修复日期生成逻辑

有两种方式修正getDate方法:

方式一:将传入的1-based月份转为0-based

修改getDate方法,自动处理用户传入的1-based月份:

private Date getDate(int year, int month, int day) {
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, year);
    // 把1-based月份转为Calendar要求的0-based
    cal.set(Calendar.MONTH, month - 1);
    cal.set(Calendar.DAY_OF_MONTH, day);
    cal.setTimeZone(TimeZone.getTimeZone("GMT"));
    return cal.getTime();
}

这样调用getDate(2023, 01, 01)就会生成2023年1月1日,getDate(2023, 02, 01)生成2023年2月1日,间隔计算结果就是31天。

方式二:明确传入0-based月份

如果不想修改方法,调用时直接传入符合Calendar规则的0-based月份:

System.err.println(DateUtils.getDaysBetween(
        getDate(2023, 0, 01), getDate(2023, 1, 01)));

(0代表一月,1代表二月)

2. 替换更可靠的日期间隔计算方式

推荐使用Java 8及以上版本提供的java.time包(JSR-310)来计算日期间隔,彻底避免毫秒计算的问题:

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;

public static long getDaysBetween(Date d1, Date d2) {
    // 将Date转为GMT时区的LocalDate
    LocalDate date1 = d1.toInstant().atZone(ZoneId.of("GMT")).toLocalDate();
    LocalDate date2 = d2.toInstant().atZone(ZoneId.of("GMT")).toLocalDate();
    // 直接计算两个日期的天数差
    return ChronoUnit.DAYS.between(date1, date2);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 21:35:38