Created
November 10, 2021 23:43
-
-
Save robbat2/d2c01d97fe2b7f9c69356efc06a4b8cf to your computer and use it in GitHub Desktop.
glibc strptime ignores timezone
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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