日期计算是日常生活和软件开发中最常见的需求之一。无论是计算项目工期、合同到期日、还款周期,还是简单地算算距离生日还有多少天,都需要精确的日期运算能力。本文将全面介绍日期计算的各种方法,涵盖 JavaScript、Python 和 Excel 中的实现方式,并提供可直接复制使用的代码示例。
TL;DR
| 场景 | JavaScript | Python | Excel |
|---|---|---|---|
| 两日期间隔天数 | (date2 - date1) / 86400000 |
(date2 - date1).days |
=B1-A1 |
| 日期加天数 | date.setDate(date.getDate() + n) |
date + timedelta(days=n) |
=A1+n |
| 工作日计算 | 循环判断 getDay() |
numpy.busday_count() |
=NETWORKDAYS(A1,B1) |
| 月份差 | 手动计算年月差 | relativedelta |
=DATEDIF(A1,B1,"M") |
需要快速计算?直接使用 QubitTool 日期计算器,在线即时获取结果,无需编写任何代码。
引言
日期计算看似简单,实际上充满了各种复杂性:不同月份的天数不同(28、29、30、31天)、闰年的存在、时区差异、夏令时切换等。这些因素使得手动计算日期极易出错。
在现代开发中,日期计算广泛应用于:
- 项目管理:计算 Sprint 周期、里程碑间隔、交付倒计时
- 金融系统:计息天数、还款周期、合同期限
- 电商平台:促销倒计时、退货期限、会员到期提醒
- 法律领域:诉讼时效、合同有效期、上诉期限
- 日常生活:生日倒计时、旅行天数、怀孕预产期
掌握正确的日期计算方法,可以在各种场景中节省大量时间,避免计算错误。
如何计算两个日期之间的天数
计算两个日期之间的天数是最基本也是最常用的日期运算。核心思路是将两个日期转换为统一的数值表示,然后相减。
基本计算公式
日期间隔的计算原理非常直观:
间隔天数 = 结束日期 - 开始日期
关键在于如何将"日期"转换为可以相减的数值。不同的编程语言和工具采用不同的内部表示方式:
| 语言/工具 | 内部表示 | 单位 |
|---|---|---|
| JavaScript | Unix 时间戳 | 毫秒 |
| Python | datetime 对象 |
直接支持相减 |
| Excel | 序列号(自1900-01-01起) | 天 |
| Java | Instant / LocalDate |
纳秒 / 天 |
JavaScript 实现
在 JavaScript 中,Date 对象内部以毫秒级 Unix 时间戳存储时间。两个日期相减得到毫秒差,再除以每天的毫秒数即可得到天数。
function daysBetween(dateStr1, dateStr2) {
const MS_PER_DAY = 1000 * 60 * 60 * 24;
const date1 = new Date(dateStr1);
const date2 = new Date(dateStr2);
const diffMs = Math.abs(date2.getTime() - date1.getTime());
return Math.floor(diffMs / MS_PER_DAY);
}
console.log(daysBetween('2026-01-01', '2026-04-01'));
// 90
console.log(daysBetween('2026-03-01', '2026-06-15'));
// 106
如果需要更精确的结果(避免夏令时影响),可以使用 UTC 方法:
function daysBetweenUTC(dateStr1, dateStr2) {
const MS_PER_DAY = 86400000;
const date1 = new Date(dateStr1 + 'T00:00:00Z');
const date2 = new Date(dateStr2 + 'T00:00:00Z');
return Math.abs(Math.round((date2 - date1) / MS_PER_DAY));
}
console.log(daysBetweenUTC('2024-01-01', '2024-12-31'));
// 365(2024是闰年,1月1日到12月31日为365天)
使用现代 Temporal API(Stage 3 提案,部分运行时已支持):
const date1 = Temporal.PlainDate.from('2026-01-01');
const date2 = Temporal.PlainDate.from('2026-04-01');
const diff = date1.until(date2, { largestUnit: 'day' });
console.log(diff.days);
// 90
Python 实现
Python 的 datetime 模块原生支持日期运算,使用起来更加简洁直观。
from datetime import date
date1 = date(2026, 1, 1)
date2 = date(2026, 4, 1)
delta = date2 - date1
print(delta.days)
# 90
计算更细粒度的时间差(包括年、月、日):
from dateutil.relativedelta import relativedelta
from datetime import date
date1 = date(2023, 3, 15)
date2 = date(2026, 7, 20)
diff = relativedelta(date2, date1)
print(f"{diff.years}年{diff.months}个月{diff.days}天")
# 3年4个月5天
批量计算多组日期间隔:
from datetime import date
date_pairs = [
(date(2026, 1, 1), date(2026, 6, 30)),
(date(2026, 3, 1), date(2026, 3, 31)),
(date(2025, 12, 25), date(2026, 1, 1)),
]
for start, end in date_pairs:
days = (end - start).days
print(f"{start} → {end}: {days}天")
# 2026-01-01 → 2026-06-30: 180天
# 2026-03-01 → 2026-03-31: 30天
# 2025-12-25 → 2026-01-01: 7天
Excel 公式
Excel 中日期的内部表示是序列号(自 1900 年 1 月 1 日起的天数),因此日期运算非常直观。
方法一:直接相减
=B1-A1
其中 A1 为开始日期,B1 为结束日期。结果直接为天数。需要将单元格格式设置为"数值"而非"日期"。
方法二:使用 DATEDIF 函数
DATEDIF 是 Excel 中专用的日期差计算函数,支持按不同单位返回结果:
=DATEDIF(A1, B1, "D") 返回总天数
=DATEDIF(A1, B1, "M") 返回完整月数
=DATEDIF(A1, B1, "Y") 返回完整年数
=DATEDIF(A1, B1, "YM") 返回扣除年后的剩余月数
=DATEDIF(A1, B1, "MD") 返回扣除月后的剩余天数
方法三:使用 DAYS 函数
=DAYS(B1, A1)
DAYS 函数是 Excel 2013 及以后版本引入的,语法更清晰,参数顺序为 DAYS(结束日期, 开始日期)。
实用示例:计算年龄
=DATEDIF(A1, TODAY(), "Y") & "岁" & DATEDIF(A1, TODAY(), "YM") & "个月"
日期加减运算
日期加减运算用于在给定日期的基础上,向前或向后推算指定天数、月数或年数后的日期。这在计算截止日期、到期日、预产期等场景中非常实用。
日期加天数
JavaScript 实现:
function addDays(dateStr, days) {
const date = new Date(dateStr);
date.setDate(date.getDate() + days);
return date.toISOString().split('T')[0];
}
console.log(addDays('2026-04-01', 30));
// "2026-05-01"
console.log(addDays('2026-04-01', 90));
// "2026-06-30"
console.log(addDays('2026-04-01', 365));
// "2027-04-01"
Python 实现:
from datetime import date, timedelta
start = date(2026, 4, 1)
print(start + timedelta(days=30))
# 2026-05-01
print(start + timedelta(days=90))
# 2026-06-30
print(start + timedelta(days=365))
# 2027-04-01
加月份或年份(使用 dateutil):
from datetime import date
from dateutil.relativedelta import relativedelta
start = date(2026, 1, 31)
print(start + relativedelta(months=1))
# 2026-02-28(自动处理月末)
print(start + relativedelta(years=1))
# 2027-01-31
print(start + relativedelta(months=3, days=15))
# 2026-05-15
日期减天数
日期减法与加法原理相同,只是使用负数。
JavaScript 实现:
function subtractDays(dateStr, days) {
const date = new Date(dateStr);
date.setDate(date.getDate() - days);
return date.toISOString().split('T')[0];
}
console.log(subtractDays('2026-04-01', 30));
// "2026-03-02"
console.log(subtractDays('2026-04-01', 90));
// "2026-01-01"
Python 实现:
from datetime import date, timedelta
end = date(2026, 4, 1)
print(end - timedelta(days=30))
# 2026-03-02
print(end - timedelta(days=90))
# 2026-01-01
Excel 公式:
=A1+30 在日期上加30天
=A1-30 在日期上减30天
=EDATE(A1,3) 在日期上加3个月
=EDATE(A1,-6) 在日期上减6个月
常见应用场景
| 场景 | 计算方式 | 示例 |
|---|---|---|
| 项目截止日期 | 开始日期 + 工期天数 | 4月1日 + 90天 = 6月30日 |
| 订阅到期日 | 订阅日期 + 订阅周期 | 1月15日 + 1年 = 次年1月15日 |
| 合同到期日 | 签约日期 + 合同期限 | 3月1日 + 6个月 = 9月1日 |
| 退货截止日 | 购买日期 + 退货期 | 3月20日 + 7天 = 3月27日 |
| 贷款还款日 | 放款日期 + 还款周期 | 每月相同日期 |
| 预产期计算 | 末次月经 + 280天 | 标准孕期40周 |
工作日计算:排除周末和节假日
在项目管理和商业场景中,通常需要计算的是"工作日"而非"日历天数"。工作日计算需要排除周末,有时还需要排除法定节假日。
什么是工作日
| 类型 | 包含范围 | 典型应用 |
|---|---|---|
| 日历天数 | 所有天(周一至周日) | 合同期限、保质期 |
| 工作日 | 周一至周五(排除周末) | 项目工期、交货周期 |
| 净工作日 | 工作日 - 法定假日 | 薪资计算、排班 |
一般规律:30个日历天 ≈ 22个工作日,一年约有 250-252 个工作日。
JavaScript 实现
function workdaysBetween(startStr, endStr) {
const start = new Date(startStr);
const end = new Date(endStr);
let count = 0;
const current = new Date(start);
while (current <= end) {
const dayOfWeek = current.getDay();
if (dayOfWeek !== 0 && dayOfWeek !== 6) {
count++;
}
current.setDate(current.getDate() + 1);
}
return count;
}
console.log(workdaysBetween('2026-04-01', '2026-04-30'));
// 22
添加公众假日排除功能:
function workdaysBetweenWithHolidays(startStr, endStr, holidays = []) {
const start = new Date(startStr);
const end = new Date(endStr);
const holidaySet = new Set(holidays);
let count = 0;
const current = new Date(start);
while (current <= end) {
const dayOfWeek = current.getDay();
const dateStr = current.toISOString().split('T')[0];
if (dayOfWeek !== 0 && dayOfWeek !== 6 && !holidaySet.has(dateStr)) {
count++;
}
current.setDate(current.getDate() + 1);
}
return count;
}
const holidays = ['2026-04-06', '2026-05-01'];
console.log(workdaysBetweenWithHolidays('2026-04-01', '2026-04-30', holidays));
// 21
计算 N 个工作日后的日期:
function addWorkdays(startStr, workdays) {
const date = new Date(startStr);
let added = 0;
while (added < workdays) {
date.setDate(date.getDate() + 1);
const dayOfWeek = date.getDay();
if (dayOfWeek !== 0 && dayOfWeek !== 6) {
added++;
}
}
return date.toISOString().split('T')[0];
}
console.log(addWorkdays('2026-04-01', 10));
// "2026-04-15"
Excel NETWORKDAYS 函数
Excel 提供了内置的工作日计算函数,非常强大且方便。
NETWORKDAYS 函数:计算两个日期之间的工作日数
=NETWORKDAYS(A1, B1)
排除自定义假日:
=NETWORKDAYS(A1, B1, D1:D10)
其中 D1:D10 为节假日列表。
WORKDAY 函数:计算 N 个工作日后的日期
=WORKDAY(A1, 10) 从A1起10个工作日后的日期
=WORKDAY(A1, -5) 从A1起5个工作日前的日期
=WORKDAY(A1, 10, D1:D5) 排除自定义假日
NETWORKDAYS.INTL 函数:自定义周末定义
=NETWORKDAYS.INTL(A1, B1, "0000011")
第三个参数为7位字符串,每一位对应周一至周日,1 表示非工作日,0 表示工作日。"0000011" 表示周六和周日为非工作日(默认值)。
不同国家和地区的周末定义可能不同:
| 地区 | 周末 | NETWORKDAYS.INTL 参数 |
|---|---|---|
| 大多数国家 | 周六、周日 | "0000011" |
| 中东部分国家 | 周五、周六 | "0000110" |
| 仅周日休息 | 周日 | "0000001" |
处理公众假日
各国法定节假日差异很大,处理公众假日通常需要维护一个假日列表。
Python 方案(使用 holidays 库):
import holidays
from datetime import date, timedelta
cn_holidays = holidays.China(years=2026)
def workdays_between(start, end, country_holidays):
count = 0
current = start
while current <= end:
if current.weekday() < 5 and current not in country_holidays:
count += 1
current += timedelta(days=1)
return count
start = date(2026, 1, 1)
end = date(2026, 12, 31)
print(workdays_between(start, end, cn_holidays))
使用 NumPy 的高效方案:
import numpy as np
from datetime import date
start = date(2026, 4, 1)
end = date(2026, 4, 30)
holidays = [np.datetime64('2026-04-06')]
workdays = np.busday_count(
np.datetime64(start),
np.datetime64(end),
holidays=holidays
)
print(workdays)
# 21
跨时区的日期计算
当日期计算涉及不同时区时,问题会变得更加复杂。一个看似简单的"今天"在不同时区可能对应不同的日期。
UTC 与本地时间
UTC(协调世界时)是全球时间的基准。在进行跨时区的日期计算时,建议统一使用 UTC 时间进行计算,然后再转换为本地时间显示。
const now = new Date();
console.log(now.toISOString());
// "2026-04-01T08:30:00.000Z" (UTC)
console.log(now.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }));
// "2026/4/1 16:30:00" (北京时间 UTC+8)
console.log(now.toLocaleString('zh-CN', { timeZone: 'America/New_York' }));
// "2026/4/1 04:30:00" (纽约时间 UTC-4)
from datetime import datetime, timezone, timedelta
utc_now = datetime.now(timezone.utc)
print(utc_now.strftime('%Y-%m-%d %H:%M:%S %Z'))
# 2026-04-01 08:30:00 UTC
beijing_tz = timezone(timedelta(hours=8))
beijing_now = utc_now.astimezone(beijing_tz)
print(beijing_now.strftime('%Y-%m-%d %H:%M:%S'))
# 2026-04-01 16:30:00
常见陷阱
陷阱一:夏令时导致天数计算不准确
在实行夏令时(DST)的地区,一天并不总是精确的 24 小时。春季"向前拨"时一天只有 23 小时,秋季"向后拨"时一天有 25 小时。
const spring2026 = new Date('2026-03-08T00:00:00');
const afterSpring = new Date('2026-03-09T00:00:00');
const diffHours = (afterSpring - spring2026) / (1000 * 60 * 60);
// 在美国时区可能是23小时而非24小时
解决方案:使用 UTC 时间进行日期计算,避免夏令时影响。
function safeDaysBetween(dateStr1, dateStr2) {
const d1 = new Date(dateStr1 + 'T00:00:00Z');
const d2 = new Date(dateStr2 + 'T00:00:00Z');
return Math.round((d2 - d1) / 86400000);
}
陷阱二:时区偏移导致日期"漂移"
当服务器和客户端处于不同时区时,同一个时间戳可能对应不同的日期。
const timestamp = 1743465600000;
const utcDate = new Date(timestamp).toISOString().split('T')[0];
// "2025-04-01"
const localDate = new Date(timestamp).toLocaleDateString('zh-CN', {
timeZone: 'Pacific/Auckland'
});
// "2025/4/2" (新西兰时间已经是4月2日)
解决方案:在存储和传输日期时始终使用 ISO 8601 格式(包含时区信息),在显示时才转换为本地时间。
陷阱三:new Date() 的解析差异
不同浏览器对日期字符串的解析行为不一致:
new Date('2026-04-01')
// 在某些浏览器中解析为UTC,在其他浏览器中解析为本地时间
new Date('2026-04-01T00:00:00Z')
// 明确指定UTC,所有浏览器一致
new Date('2026-04-01T00:00:00+08:00')
// 明确指定时区,所有浏览器一致
最佳实践:始终使用明确的时区标识,避免依赖浏览器的默认解析行为。
更多关于时区的处理方法,可以参考 时间戳转换器 提供的跨时区转换功能。
不同场景下的日期计算
项目管理
在敏捷开发和项目管理中,精确的日期计算有助于合理安排任务和资源。
Sprint 规划:
from datetime import date, timedelta
sprint_start = date(2026, 4, 1)
sprint_length = 14
sprint_end = sprint_start + timedelta(days=sprint_length - 1)
print(f"Sprint周期: {sprint_start} → {sprint_end}")
# Sprint周期: 2026-04-01 → 2026-04-14
sprints = []
current = sprint_start
for i in range(6):
end = current + timedelta(days=sprint_length - 1)
sprints.append((i + 1, current, end))
current = end + timedelta(days=1)
for num, start, end in sprints:
print(f"Sprint {num}: {start} → {end}")
里程碑跟踪:
function milestoneTracker(milestones) {
const today = new Date();
return milestones.map(m => {
const target = new Date(m.date);
const daysLeft = Math.ceil((target - today) / 86400000);
return {
name: m.name,
date: m.date,
daysLeft,
status: daysLeft < 0 ? '已过期' : daysLeft === 0 ? '今天' : `剩余${daysLeft}天`
};
});
}
const milestones = [
{ name: '需求评审', date: '2026-04-15' },
{ name: 'Alpha版本', date: '2026-05-30' },
{ name: '正式发布', date: '2026-07-01' }
];
console.log(milestoneTracker(milestones));
法律领域
法律场景中的日期计算往往需要极高的准确性,因为截止日期一旦错过,可能造成不可逆的后果。
诉讼时效计算:
from datetime import date
from dateutil.relativedelta import relativedelta
incident_date = date(2024, 6, 15)
statute_3y = incident_date + relativedelta(years=3)
print(f"事件日期: {incident_date}")
print(f"3年诉讼时效到期: {statute_3y}")
# 事件日期: 2024-06-15
# 3年诉讼时效到期: 2027-06-15
today = date(2026, 4, 1)
remaining = (statute_3y - today).days
print(f"距到期还剩: {remaining}天")
# 距到期还剩: 440天
合同期限:
from datetime import date
from dateutil.relativedelta import relativedelta
sign_date = date(2026, 4, 1)
contract_1y = sign_date + relativedelta(years=1) - relativedelta(days=1)
contract_3y = sign_date + relativedelta(years=3) - relativedelta(days=1)
print(f"签约日期: {sign_date}")
print(f"1年合同到期: {contract_1y}")
print(f"3年合同到期: {contract_3y}")
# 签约日期: 2026-04-01
# 1年合同到期: 2027-03-31
# 3年合同到期: 2029-03-31
renewal_notice = contract_1y - relativedelta(months=1)
print(f"续约提醒日: {renewal_notice}")
# 续约提醒日: 2027-02-28
个人生活
年龄精确计算:
function calculateExactAge(birthDateStr) {
const birth = new Date(birthDateStr);
const today = new Date();
let years = today.getFullYear() - birth.getFullYear();
let months = today.getMonth() - birth.getMonth();
let days = today.getDate() - birth.getDate();
if (days < 0) {
months--;
const prevMonth = new Date(today.getFullYear(), today.getMonth(), 0);
days += prevMonth.getDate();
}
if (months < 0) {
years--;
months += 12;
}
return { years, months, days };
}
const age = calculateExactAge('1995-08-15');
console.log(`${age.years}岁${age.months}个月${age.days}天`);
活动倒计时:
function countdown(eventName, eventDateStr) {
const event = new Date(eventDateStr);
const now = new Date();
const diffMs = event - now;
if (diffMs < 0) {
return `${eventName}已过去${Math.abs(Math.floor(diffMs / 86400000))}天`;
}
const days = Math.floor(diffMs / 86400000);
const hours = Math.floor((diffMs % 86400000) / 3600000);
const minutes = Math.floor((diffMs % 3600000) / 60000);
return `距离${eventName}还有${days}天${hours}小时${minutes}分钟`;
}
console.log(countdown('国庆节', '2026-10-01'));
console.log(countdown('元旦', '2027-01-01'));
预产期计算:
from datetime import date, timedelta
last_period = date(2026, 1, 15)
due_date = last_period + timedelta(days=280)
print(f"末次月经: {last_period}")
print(f"预产期: {due_date}")
# 末次月经: 2026-01-15
# 预产期: 2026-10-22
today = date(2026, 4, 1)
weeks_pregnant = (today - last_period).days // 7
days_remaining = (due_date - today).days
print(f"当前孕周: 第{weeks_pregnant}周")
print(f"距预产期: {days_remaining}天")
# 当前孕周: 第11周
# 距预产期: 204天
金融领域
计息天数(ACT/365 方法):
from datetime import date
deposit_date = date(2026, 1, 1)
maturity_date = date(2027, 1, 1)
principal = 100000
annual_rate = 0.035
days = (maturity_date - deposit_date).days
interest = principal * annual_rate * days / 365
print(f"存款本金: ¥{principal:,.2f}")
print(f"年利率: {annual_rate * 100}%")
print(f"计息天数: {days}天")
print(f"到期利息: ¥{interest:,.2f}")
# 存款本金: ¥100,000.00
# 年利率: 3.5%
# 计息天数: 365天
# 到期利息: ¥3,500.00
还款计划表:
from datetime import date
from dateutil.relativedelta import relativedelta
loan_date = date(2026, 4, 1)
loan_amount = 500000
annual_rate = 0.0388
term_months = 360
monthly_rate = annual_rate / 12
monthly_payment = loan_amount * monthly_rate * (1 + monthly_rate) ** term_months / ((1 + monthly_rate) ** term_months - 1)
print(f"贷款金额: ¥{loan_amount:,.2f}")
print(f"年利率: {annual_rate * 100}%")
print(f"贷款期限: {term_months // 12}年")
print(f"月供: ¥{monthly_payment:,.2f}")
print()
balance = loan_amount
for i in range(1, 7):
interest = balance * monthly_rate
principal_part = monthly_payment - interest
balance -= principal_part
payment_date = loan_date + relativedelta(months=i)
print(f"第{i}期 ({payment_date}): 月供¥{monthly_payment:,.2f} = 本金¥{principal_part:,.2f} + 利息¥{interest:,.2f} | 余额¥{balance:,.2f}")
信用卡账单周期:
from datetime import date
from dateutil.relativedelta import relativedelta
statement_date = date(2026, 4, 5)
payment_due = statement_date + relativedelta(days=20)
next_statement = statement_date + relativedelta(months=1)
print(f"账单日: {statement_date}")
print(f"还款日: {payment_due}")
print(f"下期账单日: {next_statement}")
# 账单日: 2026-04-05
# 还款日: 2026-04-25
# 下期账单日: 2026-05-05
日期计算中的闰年处理
闰年是日期计算中必须考虑的因素。闰年的 2 月有 29 天,而平年的 2 月只有 28 天。
闰年判断规则:
- 能被 4 整除的年份是闰年
- 能被 100 整除但不能被 400 整除的年份不是闰年
- 能被 400 整除的年份是闰年
function isLeapYear(year) {
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
}
console.log(isLeapYear(2024)); // true
console.log(isLeapYear(2025)); // false
console.log(isLeapYear(2000)); // true
console.log(isLeapYear(1900)); // false
import calendar
print(calendar.isleap(2024)) # True
print(calendar.isleap(2025)) # False
print(calendar.isleap(2000)) # True
print(calendar.isleap(1900)) # False
闰年对日期计算的影响:
from datetime import date
date1 = date(2024, 1, 1)
date2 = date(2025, 1, 1)
print(f"2024年天数: {(date2 - date1).days}")
# 2024年天数: 366
date3 = date(2025, 1, 1)
date4 = date(2026, 1, 1)
print(f"2025年天数: {(date4 - date3).days}")
# 2025年天数: 365
2月29日的特殊处理:
在闰年出生在 2 月 29 日的人,平年的生日通常按 2 月 28 日或 3 月 1 日计算。大多数日期库在加减年份时会自动处理这种情况:
from datetime import date
from dateutil.relativedelta import relativedelta
leap_birthday = date(2024, 2, 29)
next_year = leap_birthday + relativedelta(years=1)
print(next_year)
# 2025-02-28(自动调整为2月最后一天)
two_years = leap_birthday + relativedelta(years=2)
print(two_years)
# 2026-02-28
four_years = leap_birthday + relativedelta(years=4)
print(four_years)
# 2028-02-29(再次遇到闰年)
日期格式化与解析
在日期计算之前,正确解析输入的日期字符串至关重要。不同地区有不同的日期格式习惯。
| 地区 | 格式 | 示例 |
|---|---|---|
| 中国 | YYYY-MM-DD | 2026-04-01 |
| 美国 | MM/DD/YYYY | 04/01/2026 |
| 欧洲 | DD/MM/YYYY | 01/04/2026 |
| ISO 8601 | YYYY-MM-DDTHH:mm:ssZ | 2026-04-01T00:00:00Z |
JavaScript 日期格式化:
function formatDate(date, format) {
const pad = n => String(n).padStart(2, '0');
const tokens = {
'YYYY': date.getFullYear(),
'MM': pad(date.getMonth() + 1),
'DD': pad(date.getDate()),
'HH': pad(date.getHours()),
'mm': pad(date.getMinutes()),
'ss': pad(date.getSeconds())
};
return Object.entries(tokens).reduce(
(str, [token, value]) => str.replace(token, value),
format
);
}
const date = new Date('2026-04-01');
console.log(formatDate(date, 'YYYY年MM月DD日'));
// "2026年04月01日"
console.log(formatDate(date, 'YYYY-MM-DD'));
// "2026-04-01"
Python 日期格式化:
from datetime import datetime
dt = datetime(2026, 4, 1, 14, 30, 0)
print(dt.strftime('%Y年%m月%d日'))
# 2026年04月01日
print(dt.strftime('%Y-%m-%d %H:%M:%S'))
# 2026-04-01 14:30:00
print(dt.strftime('%m/%d/%Y'))
# 04/01/2026
日期字符串解析:
from datetime import datetime
formats = [
('2026-04-01', '%Y-%m-%d'),
('04/01/2026', '%m/%d/%Y'),
('01/04/2026', '%d/%m/%Y'),
('2026年4月1日', '%Y年%m月%d日'),
]
for date_str, fmt in formats:
parsed = datetime.strptime(date_str, fmt)
print(f"'{date_str}' → {parsed.date()}")
常见问题
如何计算两个日期之间的天数?
用较晚的日期减去较早的日期即可。在 JavaScript 中将两个日期转换为时间戳后相减再除以 86400000(每天毫秒数)。在 Excel 中直接用两个日期单元格相减。在 Python 中,两个 date 对象相减会返回 timedelta 对象,其 .days 属性即为天数差。如果不想编写代码,也可以使用 QubitTool 日期计算器 在线即时计算。
如何在日期上加减天数?
创建日期对象后加减天数即可。JavaScript 使用 setDate(getDate() + n) 方法,Python 使用 timedelta(days=n) 进行加减,Excel 直接在日期单元格上加减数字。如果需要加减月份或年份,JavaScript 可以使用 setMonth() 或 setFullYear(),Python 推荐使用 dateutil 库的 relativedelta,Excel 可以使用 EDATE() 函数。这些方法常用于计算截止日期、订阅到期日和合同日期。
如何计算两个日期之间的工作日?
统计两个日期之间的所有天数,排除周末(周六和周日)以及可选的公众假日。在 JavaScript 中需要遍历每一天,通过 getDay() 判断是否为周末。在 Python 中可以使用 numpy.busday_count() 高效计算。Excel 提供了 NETWORKDAYS 函数,可以直接计算工作日数,还支持通过第三个参数传入假日列表进行排除。
日历天数和工作日有什么区别?
日历天数包括所有天(工作日、周末、节假日),工作日仅计算周一至周五并排除公众假日。30 个日历天通常约包含 22 个工作日,一年通常有 250-252 个工作日。在实际应用中,合同期限、保质期等通常按日历天数计算,而项目工期、交货周期等通常按工作日计算。选择哪种计算方式取决于具体的业务场景和法律要求。
日期计算中如何处理闰年?
闰年每 4 年增加一天(2 月 29 日),但世纪年需被 400 整除才算闰年(如 2000 年是闰年,1900 年不是)。大多数编程语言和日期库会自动处理闰年,开发者无需手动干预。手动计算时,判断闰年的规则是:能被 4 整除且不能被 100 整除,或者能被 400 整除的年份为闰年。在日期加减中需要注意 2 月 29 日加 1 年后会自动调整为 2 月 28 日。
总结
日期计算是编程和日常生活中不可缺少的技能。本文涵盖了以下核心内容:
| 主题 | 要点 |
|---|---|
| 日期间隔计算 | JavaScript 时间戳相减、Python datetime、Excel 直接相减 |
| 日期加减运算 | 天数、月份、年份的加减及月末自动调整 |
| 工作日计算 | 排除周末和假日,NETWORKDAYS 函数 |
| 时区处理 | 统一使用 UTC 计算,注意夏令时陷阱 |
| 闰年处理 | 4/100/400 规则,2月29日特殊处理 |
| 实际应用 | 项目管理、法律、金融、个人生活 |
无论使用哪种编程语言或工具,日期计算的核心原理都是一致的。建议在实际开发中使用成熟的日期库(如 Python 的 dateutil、JavaScript 的 date-fns 或 dayjs),避免手动处理复杂的边界情况。
如果你只是需要快速计算两个日期之间的天数、在日期上加减天数或计算工作日,无需编写代码——直接使用 QubitTool 日期计算器,输入日期即可获取结果。