Skip to content

Instantly share code, notes, and snippets.

@robbat2
Created November 10, 2021 23:43
Show Gist options
  • Save robbat2/d2c01d97fe2b7f9c69356efc06a4b8cf to your computer and use it in GitHub Desktop.
Save robbat2/d2c01d97fe2b7f9c69356efc06a4b8cf to your computer and use it in GitHub Desktop.
glibc strptime ignores timezone
1. strptime isn't using the timezone specifier from "%z" to correct convert non-UTC back to UTC
2. conversion when local tz is UTC or PST to the same value suggests there might be a second bug, depending on implementation.
#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
const time_t correct_t = 1636573045;
const char* s = "Wed, 10 Nov 2021 14:37:25 -0500";
const char* strptime_fmt = "%a, %d %b %Y %H:%M:%S %z";
void testcase() {
// forcibly zero it between calls
struct tm *tm;
time_t t = 0;
tm = gmtime(&t);
// s -> tm
char *remaining_s = strptime(s, strptime_fmt, tm);
// tm -> t
t = mktime(tm);
// explicit that it's a signed value
long signed int delta_t = (long signed int)(correct_t) - (long signed int)(t);
if(NULL == remaining_s) { remaining_s = (char*)"(NULL)"; }
// Used for printing only
char* tz = getenv("TZ");
if(!tz) { tz = (char*)"(unset)"; };
printf("TZ=%s input='%s' correct=%ld parsed=%ld remaining_input='%s' delta=%ld\n",
tz,
s,
correct_t,
t,
remaining_s,
delta_t
);
}
int main(int argn, char** argv) {
unsetenv("TZ");
testcase();
setenv("TZ", "UTC", 1);
testcase();
setenv("TZ", "EST", 1);
testcase();
setenv("TZ", "PST", 1);
testcase();
}
$ g++ glibc-strptime.cc -o glibc-strptime
$ echo "host '$(date --iso=sec)' '$(date -R)'" ; env -u TZ ./glibc-strptime
host '2021-11-10T11:53:18-08:00' 'Wed, 10 Nov 2021 11:53:18 -0800'
TZ=(unset) input='Wed, 10 Nov 2021 14:37:25 -0500' correct=1636573045 parsed=-1 delta=1636573046
TZ=UTC input='Wed, 10 Nov 2021 14:37:25 -0500' correct=1636573045 parsed=1636555045 delta=18000
TZ=EST input='Wed, 10 Nov 2021 14:37:25 -0500' correct=1636573045 parsed=1636573045 delta=0
TZ=PST input='Wed, 10 Nov 2021 14:37:25 -0500' correct=1636573045 parsed=1636555045 delta=18000
Manpage extract:
Glibc notes
For reasons of symmetry, glibc tries to support for strptime() the same
format characters as for strftime(3). (In most cases, the corresponding
fields are parsed, but no field in tm is changed.) This leads to
...
%z An RFC-822/ISO 8601 standard timezone specification.
%Z The timezone name.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment