* Differences between strftime in musl and glibc
@ 2018-01-18 16:25 Adrián López Tejedor
2018-01-18 16:34 ` Rich Felker
0 siblings, 1 reply; 2+ messages in thread
From: Adrián López Tejedor @ 2018-01-18 16:25 UTC (permalink / raw)
To: musl
[-- Attachment #1.1: Type: text/plain, Size: 1276 bytes --]
Hi,
I was having a problem parsing dates with python in an Alpine container and
after some time digging I have found a difference in how musl and
glibc calculate the unix Epoch using strftime.
The format specifier to get the unix epoch is "%s", which is an extension
of GNU (
https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html
).
In Glibc they use mktime (
https://github.com/bminor/glibc/blob/master/time/strftime_l.c#L1127), being
this function aware of time zone.
In musl is calculated without mktime, adding the seconds of each part of
the tm struct (
https://git.musl-libc.org/cgit/musl/tree/src/time/strftime.c?h=v1.1.18#n132)
and substracting the GMT offset. This method is unaware of the TZ data (I
have not seen how to define that gmt offset when using strptime).
Calling directly to musl/mktime work as expected.
I have attached a small program which shows the difference between musl and
glibc.
Compiled with glibc:
$ TZ=Europe/Madrid ./a.out
strftime: -3600
mktime: -3600
$ TZ=America/New_York ./a.out
strftime: 18000
mktime: 18000
Compiled with musl:
$ TZ=Europe/Madrid ./a.out
strftime: 0
mktime: -3600
$ TZ=America/New_York ./a.out
strftime: 0
mktime: 18000
Thanks!
Adrián
[-- Attachment #1.2: Type: text/html, Size: 2684 bytes --]
[-- Attachment #2: date_musl_glibc.c --]
[-- Type: text/x-csrc, Size: 498 bytes --]
#define _XOPEN_SOURCE
#include "stdio.h"
#include "stdlib.h"
#include "time.h"
#include "string.h"
int main(void) {
char buf[100];
struct tm tm1, tm2;
memset(&tm1, 0, sizeof(struct tm));
memset(&tm2, 0, sizeof(struct tm));
strptime("1/1/1970 00:00:00", "%d/%m/%Y %H:%M:%S", &tm1);
strptime("1/1/1970 00:00:00", "%d/%m/%Y %H:%M:%S", &tm2);
strftime(buf, 100, "%s", &tm1);
printf("strftime: %s\n", buf);
time_t seg = mktime(&tm2);
printf("mktime: %ld\n", seg);
return 0;
}
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: Differences between strftime in musl and glibc
2018-01-18 16:25 Differences between strftime in musl and glibc Adrián López Tejedor
@ 2018-01-18 16:34 ` Rich Felker
0 siblings, 0 replies; 2+ messages in thread
From: Rich Felker @ 2018-01-18 16:34 UTC (permalink / raw)
To: musl
On Thu, Jan 18, 2018 at 04:25:07PM +0000, Adrián López Tejedor wrote:
> Hi,
>
> I was having a problem parsing dates with python in an Alpine container and
> after some time digging I have found a difference in how musl and
> glibc calculate the unix Epoch using strftime.
>
> The format specifier to get the unix epoch is "%s", which is an extension
> of GNU (
> https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time..html
> ).
>
> In Glibc they use mktime (
> https://github.com/bminor/glibc/blob/master/time/strftime_l.c#L1127), being
> this function aware of time zone.
>
> In musl is calculated without mktime, adding the seconds of each part of
> the tm struct (
> https://git.musl-libc.org/cgit/musl/tree/src/time/strftime.c?h=v1.1.18#n132)
> and substracting the GMT offset. This method is unaware of the TZ data (I
> have not seen how to define that gmt offset when using strptime).
>
> Calling directly to musl/mktime work as expected.
>
> I have attached a small program which shows the difference between musl and
> glibc.
>
> Compiled with glibc:
> $ TZ=Europe/Madrid ./a.out
> strftime: -3600
> mktime: -3600
> $ TZ=America/New_York ./a.out
> strftime: 18000
> mktime: 18000
>
>
> Compiled with musl:
> $ TZ=Europe/Madrid ./a.out
> strftime: 0
> mktime: -3600
> $ TZ=America/New_York ./a.out
> strftime: 0
> mktime: 18000
>
>
> Thanks!
> Adrián
> #define _XOPEN_SOURCE
> #include "stdio.h"
> #include "stdlib.h"
> #include "time.h"
> #include "string.h"
>
>
> int main(void) {
> char buf[100];
> struct tm tm1, tm2;
> memset(&tm1, 0, sizeof(struct tm));
> memset(&tm2, 0, sizeof(struct tm));
> strptime("1/1/1970 00:00:00", "%d/%m/%Y %H:%M:%S", &tm1);
> strptime("1/1/1970 00:00:00", "%d/%m/%Y %H:%M:%S", &tm2);
>
> strftime(buf, 100, "%s", &tm1);
> printf("strftime: %s\n", buf);
>
> time_t seg = mktime(&tm2);
> printf("mktime: %ld\n", seg);
>
> return 0;
> }
The glibc behavior assumes the tm object is in units of local time (in
the current time zone), which is a really bad assumption, since
everything else about the strftime API is timezone-agnostic and works
with tm objects produced by gmtime() as well as local times. So I
believe the musl behavior is correct and the glibc behavior is wrong,
but I'm open to further discussion. It probably needs to happen on the
Austin Group tracker/list, as %s is scheduled for inclusion in future
versions of POSIX but grossly underspecified:
http://austingroupbugs.net/view.php?id=169
In particular, the glibc behavior requires that strftime become aware
of [changes in] the timezone, which it's currently not specified to
do, and there's no specification of if or how strftime determines if
the argument is a local or UTC time.
My preference would be to say that, unless the struct tm was produced
by localtime[_r] or derived from such a struct tm, it's unspecified
what time zone %s is referenced against. But I'm open to discussion as
part of the standardization process.
Rich
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2018-01-18 16:34 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-18 16:25 Differences between strftime in musl and glibc Adrián López Tejedor
2018-01-18 16:34 ` Rich Felker
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/musl/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).