From 813c4dda8b6d75dc1f8e7ab1237d0efc468d3fbb Mon Sep 17 00:00:00 2001 From: David Seifert Date: Sun, 8 Nov 2026 10:59:01 +0100 Subject: [PATCH] Fix parsing of ordinal ISO 8601 dates on musl. POSIX does not require strptime() to derive tm_mon/tm_mday from %j, and musl does not, so ordinal ISO 8601 dates (e.g. "2001-34") were mis-parsed on musl. Compute tm_mon and tm_mday from tm_yday after parsing. Bug: https://bugs.gentoo.org/922481 --- src/unix.c | 7 ++++++- src/utils.c | 21 +++++++++++++++++++++ src/utils.h | 4 ++++ src/win32.c | 20 +------------------- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/unix.c b/src/unix.c index 746b42f..9158d3e 100644 --- a/src/unix.c +++ b/src/unix.c @@ -4,6 +4,7 @@ #include #include "compiler.h" /* _hidden */ #include "libdatovka/isds.h" +#include "utils.h" #if HAVE_LIBCURL /* Convert UTF-8 @string representation of ISO 8601 date to @time. @@ -22,8 +23,12 @@ _hidden isds_error _isds_datestring2tm(const xmlChar *string, struct tm *time) { return IE_SUCCESS; offset = strptime((char*)string, "%Y-%j", time); - if (offset && *offset == '\0') + if (offset && *offset == '\0') { + /* POSIX does not require strptime() to set tm_mon and tm_mday + * from %j, and musl only sets tm_yday. */ + _isds_yday2mday(time); return IE_SUCCESS; + } return IE_NOTSUP; } diff --git a/src/utils.c b/src/utils.c index 514403d..8f31fdc 100644 --- a/src/utils.c +++ b/src/utils.c @@ -378,3 +378,24 @@ _hidden int _isds_hex2i(char digit) { _hidden int _isds_sizet2int(size_t val) { return (val <= INT_MAX) ? (int) val : -1; } + +/* Set tm_mon and tm_mday from tm_year and tm_yday. */ +_hidden void _isds_yday2mday(struct tm *time) { + static const int mtab[12] = + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + int i, mdays, year = 1900 + time->tm_year; + const int leap = (!(year % 4) && ((year % 100) || !(year %400))) ? 1 : 0; + + time->tm_mday = time->tm_yday + 1; + + for (i = 0; i < 12; i++) { + mdays = mtab[i] + ((i == 1) ? leap : 0); + if (time->tm_mday > mdays) { + time->tm_mday -= mdays; + } else { + break; + } + } + + time->tm_mon = i; +} diff --git a/src/utils.h b/src/utils.h index b9718d0..721dbae 100644 --- a/src/utils.h +++ b/src/utils.h @@ -4,6 +4,7 @@ #include #include #include +#include /* PANIC macro aborts current process without any clean up. * Use it as last resort fatal error solution */ @@ -103,4 +104,7 @@ int _isds_sizet2int(size_t val); (memory) = NULL; \ } +/* Set tm_mon and tm_mday from tm_year and tm_yday. */ +void _isds_yday2mday(struct tm *time); + #endif diff --git a/src/win32.c b/src/win32.c index 431a4e8..d4593cc 100644 --- a/src/win32.c +++ b/src/win32.c @@ -7,24 +7,6 @@ #include "win32.h" #if HAVE_LIBCURL -static void yday2mday(struct tm *time) { - static int mtab[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - int i, year = 1900 + time->tm_year; - - mtab[1] = (!(year % 4) && ((year % 100) || !(year %400))) ? 29 : 28; - time->tm_mday = time->tm_yday + 1; - - for (i = 0; i < 12; i++) { - if (time->tm_mday > mtab[i]) { - time->tm_mday -= mtab[i]; - } else { - break; - } - } - - time->tm_mon = i; -} - /* Convert UTF-8 @string representation of ISO 8601 date to @time. * XXX: Not all ISO formats are supported */ isds_error _isds_datestring2tm(const xmlChar *string, struct tm *time) { @@ -49,7 +31,7 @@ isds_error _isds_datestring2tm(const xmlChar *string, struct tm *time) { && tmp == strlen((const char*)string)) { time->tm_yday--; time->tm_year -= 1900; - yday2mday(time); + _isds_yday2mday(time); return IE_SUCCESS; } -- 2.56.0