如何计算两个日期之间的天数
计算两个日期之间的天数听起来简单,但每种语言的处理方式略有不同——边界情况(夏令时、时区、闰年)是无数差一错误的根源。以下是在常用工具中正确处理的方法。
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-fns、dateutil、pandas)可正确处理所有这些情况。手动毫秒方法可行,但需要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,以应对夏令时切换。