[musl] strptime("UTC", "%Z", &tm) in musl
Alejandro Colomar
alx@kernel.org
Sun Apr 6 23:54:14 GMT 2025
Hi Haelwenn,
On Sun, Apr 06, 2025 at 10:55:46PM +0200, Haelwenn (lanodan) Monnier wrote:
> [2025-04-06 21:57:35+0200] Alejandro Colomar:
> > I was trying to develop a function that parses a UTC date in the shadow
> > project, and I came up with this:
> > <https://github.com/shadow-maint/shadow/pull/1217/>
> >
> > $ grepc -htfd get_date .
> > static long
> > get_date(const char *s)
> > {
> > struct tm tm;
> > const char *p;
> >
> > bzero(&tm, sizeof(tm));
> >
> > p = strptime("UTC", "%Z", &tm);
> > if (p == NULL || !streq(p, ""))
> > return -1;
>
> That bzero seems like a bit of a bad idea, `struct tm` can have some extra
> fields where 0 isn't the correct value.
> Quite like how `tm_isdst` uses -1 for unknown state, 0 for no-DST, 1 for DST.
>
> Could probably use `if(!gmtime_r(0, &tm)) { /* handle err */ }` instead
> which also has the nice effect of initializing tm for UTC,
> allowing to skip the problematic strptime %Z.
Thanks! This is quite clever. I've changed this to my patch:
diff --git i/lib/strtoday.c w/lib/strtoday.c
index 2d88e8b6..ab03b921 100644
--- i/lib/strtoday.c
+++ w/lib/strtoday.c
@@ -47,13 +47,13 @@ strtoday(const char *str)
static long
get_date(const char *s)
{
+ time_t t;
struct tm tm;
const char *p;
- bzero(&tm, sizeof(tm));
-
- p = strptime("UTC", "%Z", &tm);
- if (p == NULL || !streq(p, ""))
+ // Set timezone to UTC
+ t = 0;
+ if (gmtime_r(&t, &tm) == NULL)
return -1;
p = strptime(s, "%F", &tm);
If you don't mind, I'd like to add you as a co-author of the patch, and
assign you copyright in that file. Please sign the following commit, if
you approve it.
Have a lovely night!
Alex
---
<https://github.com/shadow-maint/shadow/pull/1217>
Author: Alejandro Colomar <alx@kernel.org>
Date: Tue Feb 18 23:25:29 2025 +0100
lib/getdate.c: Use strptime(3) to simplify
The following trick:
t = 0;
gmtime_r(&t, &tm);
is a clever way to clear the tm(3type) structure, and set it to use UTC.
We need to set it to set UTC with this trick, because strptime(3)
doesn't set the timezone. I (Alex) tried previously using
bzero(&tm, sizeof(tm));
strptime("UTC", "%Z", &tm);
but glibc ignores the timezone, and musl (at least I tried in an Alpine
container) seems to report an error.
The idea to use gmtime_r(3) was from lanodan.
Link: <https://inbox.sourceware.org/libc-alpha/Z_LqUgildoq33vI-@cloudsdale.the-delta.net.eu.org/T/#u>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Rich Felker <dalias@libc.org>
Co-authored-by: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
diff --git a/lib/getdate.c b/lib/getdate.c
index 31a5c25b..fa2df83e 100644
--- a/lib/getdate.c
+++ b/lib/getdate.c
@@ -1,81 +1,31 @@
// SPDX-FileCopyrightText: 2025, Alejandro Colomar <alx@kernel.org>
+// SPDX-FileCopyrightText: 2025, "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
// SPDX-License-Identifier: BSD-3-Clause
#include <config.h>
-#include <errno.h>
-#include <limits.h>
#include <stddef.h>
-#include <string.h>
#include <time.h>
-#include "atoi/a2i/a2s.h"
#include "getdate.h"
-#include "string/strchr/strchrcnt.h"
#include "string/strcmp/streq.h"
-#include "string/strcmp/strprefix.h"
-#include "string/strcmp/strsuffix.h"
-#include "string/strspn/stpspn.h"
-
-
-#define TM_YEAR_ORIGIN 1900
-
-
-static long yyDay;
-static long yyMonth;
-static long yyYear;
-
-
-static int parse_date(const char *s);
time_t
-get_date(const char *s);
+get_date(const char *s)
{
- struct tm tm;
+ time_t t;
+ struct tm tm;
+ const char *p;
- if (parse_date(p) == -1)
+ t = 0;
+ if (gmtime_r(&t, &tm) == NULL)
return -1;
- tm.tm_year = yyYear - TM_YEAR_ORIGIN;
- tm.tm_mon = yyMonth - 1;
- tm.tm_mday = yyDay;
- tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
- tm.tm_isdst = 0;
+ p = strptime(s, "%F", &tm);
+ if (p == NULL || !streq(p, ""))
+ return -1;
return timegm(&tm);
}
-
-
-static int
-parse_date(const char *s)
-{
- long n;
-
- if (!streq(stpspn(s, "0123456789-"), "")
- || strchrcnt(s, '-') != 2
- || strprefix(s, "-")
- || strsuffix(s, "-")
- || strstr(s, "--"))
- {
- return -1;
- }
-
- if (a2sl(&yyYear, s, &s, 10, LONG_MIN, LONG_MAX) == -1 && errno != ENOTSUP)
- return -1;
-
- if (!strprefix(s++, "-"))
- return -1;
-
- if (a2sl(&yyMonth, s, &s, 10, LONG_MIN, LONG_MAX) == -1 && errno != ENOTSUP)
- return -1;
-
- if (!strprefix(s++, "-"))
- return -1;
-
- if (a2sl(&yyDay, s, NULL, 10, LONG_MIN, LONG_MAX) == -1)
- return -1;
-
- return 0;
-}
--
<https://www.alejandro-colomar.es/>
<https://www.alejandro-colomar.es:8443/>
<http://www.alejandro-colomar.es:8080/>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20250407/f304cabb/attachment.sig>
More information about the Libc-alpha
mailing list