From e0c6f4d4d6c7083f8e353503567836dacbda3e28 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 16 Jun 2026 08:58:36 +0200 Subject: [PATCH] tool_writeout: fix %time{} output for %s Now testing both %s and %% in test 1981 Reported-by: wulin-nudt on github Fixes #22038 Closes #22039 --- src/tool_writeout.c | 37 +++++++++++++++++++++++++++++-------- tests/data/test1981 | 4 ++-- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/tool_writeout.c b/src/tool_writeout.c index 8023fc47ab..ac8d5434b8 100644 --- a/src/tool_writeout.c +++ b/src/tool_writeout.c @@ -562,18 +562,39 @@ static const char *outtime(const char *ptr, /* %time{ ... */ vlen = end - ptr; curlx_dyn_init(&format, 1024); - /* insert sub-seconds for %f */ - /* insert +0000 for %z because it is otherwise not portable */ - /* insert UTC for %Z because it is otherwise not portable */ + /* Insert: + - sub-seconds for %f + - epoch seconds for %s; strftime %s uses mktime() and assumes + local time, which breaks UTC output on non-UTC hosts + - +0000 for %z because it is otherwise not portable + - UTC for %Z because it is otherwise not portable + - Keep '%%' as-is so that strftime() makes a single % out of them + */ for(i = 0; !result && i < vlen; i++) { - if((i < vlen - 1) && ptr[i] == '%' && - ((ptr[i + 1] == 'f') || ((ptr[i + 1] | 0x20) == 'z'))) { - if(ptr[i + 1] == 'f') + if((i < vlen - 1) && ptr[i] == '%') { + switch(ptr[i + 1]) { + case 'f': result = curlx_dyn_addf(&format, "%06u", usecs); - else if(ptr[i + 1] == 'Z') + break; + case 's': { + /* time_t might be either 32 or 64 bits big */ + curl_off_t tsecs = secs; + result = curlx_dyn_addf(&format, "%" CURL_FORMAT_CURL_OFF_T, tsecs); + break; + } + case 'Z': result = curlx_dyn_addn(&format, "UTC", 3); - else + break; + case 'z': result = curlx_dyn_addn(&format, "+0000", 5); + break; + case '%': + result = curlx_dyn_addn(&format, "%%", 2); + break; + default: + result = curlx_dyn_addn(&format, &ptr[i], 1); + continue; + } i++; } else diff --git a/tests/data/test1981 b/tests/data/test1981 index 9c9c1f35f1..e1fb24bf35 100644 --- a/tests/data/test1981 +++ b/tests/data/test1981 @@ -41,7 +41,7 @@ CURL_TIME=1754037103 LC_TIME=C -http://%HOSTIP:%HTTPPORT/%TESTNUMBER --write-out='Time: %time{%d/%b/%Y %H:%M:%S.%f %z %Z}\n' -s -o %LOGDIR/dump +http://%HOSTIP:%HTTPPORT/%TESTNUMBER --write-out='Time: %time{%d/%b/%Y %H:%M:%S.%f %z %Z%%s %s}\n' -s -o %LOGDIR/dump @@ -55,7 +55,7 @@ Accept: */* -Time: 01/Aug/2025 08:31:43.037103 +0000 UTC +Time: 01/Aug/2025 08:31:43.037103 +0000 UTC%s 1754037103