解析Unix时间转日期算法并修改基准为2025年1月1日
一、算法原理拆解
这段代码的核心是将Unix纪元以来的天数转换为公历日期,本质是先把输入天数转成儒略日(Julian Date,JD,一种连续的日期计数系统),再通过拆分儒略日得到年、月、日,其中通过“把1、2月归为上一年的13、14月”的技巧,简化月份天数的计算逻辑。
逐行拆解关键步骤:
计算公历400年周期调整项:
a = (uint32_t) ((4 * t + 102032) / 146097 + 15);146097是公历400年的总天数(365×400 + 97个闰年),这一步修正Unix天数到儒略日的偏移量,处理400年一循环的闰年规则。
转换为儒略日:
b = (uint32_t) (t + 2442113 + a - (a / 4));b是最终的儒略日数值,2442113是Unix纪元(1970-01-01)对应的儒略日偏移常量,a - a/4是对400年周期的二次修正。拆分儒略日得到年份相关值:
c = (20 * b - 2442) / 7305;7305是公历20年的总天数(365×20 + 5个闰年),这一步通过儒略日计算近似的年份索引,为后续拆分月、日做准备。
计算年内天数偏移:
d = b - 365 * c - (c / 4);扣除当前年份的整天天数(含闰年的2月29日调整),得到当前日期在年内的天数位置。
计算调整后的月份索引:
e = d * 1000 / 30601;30601是将1-2月归为上一年13-14月后,3-14月的总天数总和。这一步通过近似计算得到调整后的月份(3-14对应原公历的3-12月、1-2月)。
计算当月日期:
f = d - e * 30 - e * 601 / 1000;通过年内天数减去整月的近似天数,得到具体的日期数值。
修正年份和月份到公历规则:
if(e <= 13) { c -= 4716; e -= 1; } else { c -= 4715; e -= 13; }4716是儒略历的基准年份(公元前4716年),通过减法将年份索引转换为公历年份;同时将调整后的月份(3-14)转换回标准的1-12月。
二、适配“2025年1月1日以来的天数”作为输入基准
原算法的输入t是1970-01-01以来的天数,要换成2025-01-01以来的天数(记为t_new),只需调整前两行的常量,后续逻辑完全不变:
步骤1:计算基准偏移天数
2025-01-01对应的Unix时间戳是1735689600,转换为天数:1735689600 / 86400 = 19973,即1970-01-01到2025-01-01共19973天。
步骤2:调整前两行的常量
将原算法中的t替换为t_new + 19973,合并常量后得到:
// 适配新基准的前两行代码 a = (uint32_t) ((4 * t_new + 181924) / 146097 + 15); b = (uint32_t) (t_new + 2462086 + a - (a / 4));
其中:
- 181924 = 4×19973 + 102032(原第一行常量的合并结果)
- 2462086 = 19973 + 2442113(原第二行常量的合并结果)
步骤3:保留后续所有逻辑
从计算c到年份月份修正的代码完全不需要修改,直接复用即可。
内容的提问来源于stack exchange,提问作者J. Doe

