mailing list of musl libc
 help / color / mirror / code / Atom feed
* 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).