Repository navigation
Conversation
gmtime_r() split the timestamp with C division, which truncates toward zero:
work = *timep % (24*60*60); /* negative remainder for *timep < 0 */
work = (int)(*timep / (24*60*60));
For a negative timestamp both the day count and the remainder come out
negative, and the year loop below could only walk forward from 1970, so the
result was returned as a valid struct tm holding impossible fields:
-1 -> 1970-01-01 00:00:-1 (want 1969-12-31 23:59:59)
-86400 -> 1970-01-00 00:00:00 (want 1969-12-31 00:00:00)
-31536000 -> 1970-01--364 00:00:00 (want 1969-01-01 00:00:00)
-2208988800 -> 1970-01--25566 00:00:00 (want 1900-01-01 00:00:00)
Normalise to floor division first (borrow one day when the remainder is
negative), compute tm_wday from the normalised day count while keeping the
modulo result non-negative, and let the year walk run backwards for negative
day counts.
Verified on bsp/qemu-vexpress-a9 (QEMU 11.0.0, arm-none-eabi-gcc 15.2.1,
sizeof(time_t) = 8), same probe run against master and against this patch:
t master patched
0 1970-01-01 00:00:00 wday=4 1970-01-01 00:00:00 wday=4
86399 1970-01-01 23:59:59 wday=4 1970-01-01 23:59:59 wday=4
86400 1970-01-02 00:00:00 wday=5 1970-01-02 00:00:00 wday=5
-1 1970-01-01 00:00:-1 wday=4 1969-12-31 23:59:59 wday=3
-86400 1970-01-00 00:00:00 wday=3 1969-12-31 00:00:00 wday=3
-31536000 1970-01--364 wday=-4 1969-01-01 00:00:00 wday=3
-2208988800 1970-01--25566 wday=-6 1900-01-01 00:00:00 wday=1
Non-negative timestamps are unchanged; 1900-01-01 correctly reports Monday.
Refs RT-Thread#11923
|
👋 感谢您对 RT-Thread 的贡献!Thank you for your contribution to RT-Thread! 为确保代码符合 RT-Thread 的编码规范,请在你的仓库中执行以下步骤运行代码格式化工作流(如果格式化CI运行失败)。 🛠 操作步骤 | Steps
完成后,提交将自动更新至 如有问题欢迎联系我们,再次感谢您的贡献!💐 |
📌 Code Review Assignment🏷️ Tag: componentsReviewers: @Maihuanyi Changed Files (Click to expand)
🏷️ Tag: components_libcReviewers: @GorrayLi @mysterywolf Changed Files (Click to expand)
📊 Current Review Status (Last Updated: 2026-10-25 01:27 CST)
📝 Review Instructions
|
|
拉取/合并请求描述:(PR description)
[
为什么提交这份PR (why to submit this PR)
修复 #11923。
gmtime_r()用 C 的除法拆时间戳,而 C 的除法向零截断:于是负时间戳会返回一个非 NULL、但字段非法的结构体:
1970-01-01 00:00:-1(wday=4 yday=0)1969-12-31 23:59:591970-01-00 00:00:00(yday=-1)1969-12-31 00:00:001970-01--364 00:00:00(wday=-4 yday=-365)1969-01-01 00:00:001970-01--25566 00:00:00(wday=-6 yday=-25567)1900-01-01 00:00:00不只是秒为负,
tm_mday和tm_wday也会变成明显的非法值。你的解决方案是什么 (what is your solution)
只改
gmtime_r()一个函数,三步:tm_sec/tm_min/tm_hour非负tm_wday用规范化后的天数计算,并保证结果落在 0~6(原来(4 + work) % 7在天数为负时返回负值)while (work < 0) { --i; work += 闰年?366:365; },让早于 1970 的时间戳也能定位到正确年份__isleap()对 1970 之前的年份本身就有效,直接复用。请提供验证的bsp和config (provide the config and bsp)
bsp/qemu-vexpress-a9(sizeof(time_t)=8)1c801efa同一份固件、同一个探针,改前/改后各跑一次:
非负时间戳行为完全未变;1900-01-01 的 wday=1(周一)也对。
两点未包含的内容
int work的类型没改。天数在进入年份循环时仍转int,对 64 位time_t的极端值(超过约 ±580 万年)依然会截断。glibc 在那种情况下返回EOVERFLOW,但这与 [Bug] [libc] gmtime_r 对负时间戳返回非法日历字段 #11923 是两件事,没有混进本次改动。utest 暂未加入。可以在
components/libc/compilers/common/utest/time_tc.c里挂 -1 与 -86400 两个用例,但需要先确认它归属哪个 Kconfig、以及哪些跑 utest 的 BSP 会执行到。若维护者认可当前改法,我可以补上用例后更新本 PR。]
当前拉取/合并请求的状态 Intent for your PR
必须选择一项 Choose one (Mandatory):
代码质量 Code Quality:
我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:
#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up