JavaScript如何处理年份超过最大整型数值的超大日期问题
超大范围日期天数计算方案(JavaScript)
核心逻辑
完全避开原生Date对象的范围限制,全程使用BigInt做整数运算,基于公历(格里高利历)规则实现年月日和累计天数的双向转换,无精度上限,支持任意远的过去/未来日期。
完整代码
/** * 年月日转累计天数(返回BigInt类型) * @param {number|bigint} year 年份,支持负数(天文纪年:公元前1年为0,公元前2年为-1,以此类推) * @param {number|bigint} month 月份 1-12 * @param {number|bigint} day 日期 1-31 * @returns {bigint} 累计天数 */ function dateToDays(year, month, day) { let y = BigInt(year); let m = BigInt(month); const d = BigInt(day); // 月份调整:把1、2月算作上一年的13、14月,简化置闰计算 if (m <= 2n) { y -= 1n; m += 12n; } // 格里高利历置闰计算 const leapAdjust = y / 4n - y / 100n + y / 400n; const days = 365n * y + leapAdjust + (153n * (m - 3n) + 2n) / 5n + d - 1n; // 如需和UTC 1970-01-01基准对齐,取消下方注释,得到和原生Date.getTime()/86400000一致的天数 // return days - 719162n; return days; } /** * 累计天数转回年月日 * @param {bigint} days 累计天数 * @returns {{year: bigint, month: bigint, day: bigint}} 年月日对象 */ function daysToDate(days) { days = BigInt(days); // 如果dateToDays中减去了719162n,这里需要取消下方注释加回偏移量 // days += 719162n; let a = days + 32044n; let b = (4n * a + 3n) / 146097n; a -= (146097n * b) / 4n; let c = (4n * a + 3n) / 1461n; a -= (1461n * c) / 4n; let m = (5n * a + 2n) / 153n; const day = a - (153n * m + 2n) / 5n + 1n; const month = m + 3n - 12n * (m / 10n); const year = 100n * b + c - 4800n + (m / 10n); return { year, month, day }; }
使用示例
// 计算1970-01-01的天数 console.log(dateToDays(1970, 1, 1)) // 输出719162n,和UTC基准对齐后为0n // 计算公元前100亿年1月1日的天数 console.log(dateToDays(-9999999999n, 1, 1)) // 计算未来1万亿年12月31日的天数 console.log(dateToDays(1000000000000n, 12, 31)) // 计算两个日期的天数差 const day1 = dateToDays(-13800000000n, 1, 1) // 早于宇宙大爆炸的日期 const day2 = dateToDays(2024, 5, 20) const diff = day2 - day1 console.log(`两个日期相差${diff}天`)
注意事项
- 所有运算全程使用
BigInt,不存在双精度浮点数的精度丢失问题,支持的年份范围仅受JS引擎对BigInt的最大长度限制,完全覆盖极远过去、极远未来的使用需求 - 本实现默认采用格里高利历规则,如果需要适配1582年历法改革前的儒略历日期,自行调整置闰逻辑即可
- 年份参数采用天文纪年规则,若要使用传统的公元前纪年,只需要把公元前N年转换为
-(N-1)传入即可,比如公元前100年对应参数为-99
内容的提问来源于stack exchange,提问作者Lockface
相关产品推荐
相关产品推荐

