All Tools / Blog / 如何计算两个日期之间的天数

如何计算两个日期之间的天数

2 min read

计算两个日期之间的天数听起来简单,但每种语言的处理方式略有不同——边界情况(夏令时、时区、闰年)是无数差一错误的根源。以下是在常用工具中正确处理的方法。

JavaScript

最简洁的方法是解析两个日期,相减,然后将毫秒转换为天数。

function daysBetween(date1, date2) {
    const d1 = new Date(date1);
    const d2 = new Date(date2);
    const msPerDay = 1000 * 60 * 60 * 24;
    return Math.abs(Math.round((d2 - d1) / msPerDay));
}

console.log(daysBetween("2024-01-01", "2024-12-31"));
// 365(2024是闰年)

console.log(daysBetween("2025-03-01", "2026-03-01"));
// 365

Math.round()而非Math.floor()处理夏令时切换时的1小时边界情况——否则在跨越夏令时边界的365天范围内,偶尔会得到364而非365。

使用date-fns(生产环境推荐):

import { differenceInCalendarDays } from 'date-fns';

const days = differenceInCalendarDays(new Date('2024-12-31'), new Date('2024-01-01'));
console.log(days); // 365

differenceInCalendarDays 统计跨越的日历日边界数,通常是"距上次登录天数"等场景所需的结果。

Python

from datetime import date

def days_between(date1: str, date2: str) -> int:
    d1 = date.fromisoformat(date1)
    d2 = date.fromisoformat(date2)
    return abs((d2 - d1).days)

print(days_between("2024-01-01", "2024-12-31"))
# 365

print(days_between("2025-03-01", "2026-03-01"))
# 365

Python的datetime.date相减返回timedelta对象。.days属性给出整数天数——没有夏令时问题,因为date对象没有时区组件。

对于带时区的日期时间:

from datetime import datetime, timezone

def days_between_aware(dt1: str, dt2: str) -> int:
    # 带时区信息的ISO 8601格式
    d1 = datetime.fromisoformat(dt1)
    d2 = datetime.fromisoformat(dt2)
    return abs((d2 - d1).days)

Excel

Excel将日期存储为序列号(自1900年1月1日以来的天数),因此相减就是简单的算术。

简单减法:

=B1 - A1

如果A1是2024-01-01,B1是2024-12-31,结果是365。确保单元格格式为数字而非日期——否则Excel会将结果显示为日期。

DAYS函数(更清晰):

=DAYS(B1, A1)

DAYS(结束日期, 开始日期) 返回两者之间的天数。结束在开始之后为正数,反之为负数。

DATEDIF(经典但常用):

=DATEDIF(A1, B1, "D")

DATEDIF 是从Lotus 1-2-3继承的未文档化遗留函数。对于天数差异可靠。"D" 参数返回总天数;"M" 返回完整月数;"Y" 返回完整年数。

工作日(排除周末)

// JavaScript
function workingDaysBetween(start, end) {
    let count = 0;
    const current = new Date(start);
    const endDate = new Date(end);
    while (current < endDate) {
        const day = current.getDay();
        if (day !== 0 && day !== 6) count++;
        current.setDate(current.getDate() + 1);
    }
    return count;
}
# Python
from datetime import date, timedelta

def working_days_between(start: str, end: str) -> int:
    d1, d2 = date.fromisoformat(start), date.fromisoformat(end)
    count = 0
    current = d1
    while current < d2:
        if current.weekday() < 5:  # 0=周一, 4=周五
            count += 1
        current += timedelta(days=1)
    return count

Excel:

=NETWORKDAYS(A1, B1)

NETWORKDAYS 自动排除周末,第三个参数可选填节假日日期范围。

日期计算为何容易出错

夏令时 — 时钟切换的那天有23或25小时。如果减的是时间戳(而非日期对象),365天有时在毫秒上看起来像364天。

时区 — JavaScript中new Date("2024-01-01")解析为UTC午夜。如果本地时区是UTC-5,实际上是当地时间12月31日。始终明确指定时区或使用UTC日期。

闰年 — 2024年有366天。从2024年1月1日开始的"1年"范围有366天,而非365天。

使用日期专用库(date-fnsdateutilpandas)可正确处理所有这些情况。手动毫秒方法可行,但需要Math.round()技巧来应对夏令时。

要点总结

  • JavaScript:Math.round((d2 - d1) / 86400000) 或date-fns的differenceInCalendarDays
  • Python:(date2 - date1).days——date对象没有夏令时问题。
  • Excel:=DAYS(B1, A1)=DATEDIF(A1, B1, "D")
  • 仅工作日:Excel用NETWORKDAYS;Python用weekday() < 5的循环。
  • JavaScript中用Math.round而非Math.floor,以应对夏令时切换。