diff mbox series

[uclibc-ng-devel,1/3] libc: time: use the right length for a 400-year cycle in mktime

Message ID 20260831081353.3557354-1-lordrasmus@gmail.com
State New
Headers show
Series [uclibc-ng-devel,1/3] libc: time: use the right length for a 400-year cycle in mktime | expand

Commit Message

Ramin Moussavi Aug. 31, 2026, 8:13 a.m. UTC
From: ramin <lordrasmus@gmail.com>

_time_mktime_tzi() splits tm_year into whole 400-year blocks and a
remainder, then multiplies the blocks by their length in days.  A
Gregorian 400-year cycle is 146097 days; the constant said 146073, so
every complete block lost 24 days.

The first complete block is reached at tm_year 400, which is why nothing
before the year 2300 could see it:

  mktime(2299-12-31) = 10413705600   correct
  mktime(2300-01-01) = 10411718400   24 days short
  mktime(2700-01-01) = 23032425600   48 days short, two blocks

Measured against glibc on i686 (UCLIBC_USE_TIME64) and x86_64; both were
identical, so this is not specific to the time64 layer.  gmtime() and
localtime() were right all along, which makes mktime(gmtime(t)) != t.

Checked at every 400-year block boundary from 1970 to 3000, in both
directions through gmtime().

Signed-off-by: Ramin Moussavi <lordrasmus@gmail.com>
---
 libc/misc/time/time.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Waldemar Brodkorb Sept. 8, 2026, 4:35 a.m. UTC | #1
Hi,
Ramin Moussavi wrote,

> From: ramin <lordrasmus@gmail.com>
> 
> _time_mktime_tzi() splits tm_year into whole 400-year blocks and a
> remainder, then multiplies the blocks by their length in days.  A
> Gregorian 400-year cycle is 146097 days; the constant said 146073, so
> every complete block lost 24 days.
> 
> The first complete block is reached at tm_year 400, which is why nothing
> before the year 2300 could see it:
> 
>   mktime(2299-12-31) = 10413705600   correct
>   mktime(2300-01-01) = 10411718400   24 days short
>   mktime(2700-01-01) = 23032425600   48 days short, two blocks
> 
> Measured against glibc on i686 (UCLIBC_USE_TIME64) and x86_64; both were
> identical, so this is not specific to the time64 layer.  gmtime() and
> localtime() were right all along, which makes mktime(gmtime(t)) != t.
> 
> Checked at every 400-year block boundary from 1970 to 3000, in both
> directions through gmtime().

Patch series applied and pushed,
 best regards
  Waldemar
diff mbox series

Patch

diff --git a/libc/misc/time/time.c b/libc/misc/time/time.c
index f7dd1313a..e67f3dfd7 100644
--- a/libc/misc/time/time.c
+++ b/libc/misc/time/time.c
@@ -2513,7 +2513,7 @@  DST_CORRECT:
 		+ tzi[default_dst].gmt_offset
 		+ 60*( p[1]
 			   + 60*(p[2]
-					 + 24*(((146073L * ((long long)(p[6])) + d)
+					 + 24*(((146097L * ((long long)(p[6])) + d)
 							+ p[3]) + p[7])));
 
 DST_CORRECT: