This behaviour bit me recently, and when I went digging I learned more
than I really wanted to know (as is always the case with date times). I
summarize below...
Show quoted text> When I use strptime to parse a date with a timezone offset like -0600
> the resulting time is offset +6 hours from the local timezone when it
> should be offset from GMT.
>
> [...]
>
> # prints 1984-01-01 05:00 CST -0600
> # but should be 1983-12-31 23:00 CST -0600
> $ENV{TZ} = "CST6CDT";
> my $t = Time::Piece->strptime("1984-01-01 00:00 -0500", "%Y-%m-%d %H:%M %z");
> print $t->strftime("%Y-%m-%d %H:%M %Z %z\n");
I believe the problem you're seeing is in formatting, not parsing. Your
examples touch both strptime and strftime, which I think leads to some
confusion over where the fault lies. It'd be good to break the examples
into tests that only exercise one function at a time and show the
failures more clearly.
The formatting bug is that Time::Piece doesn't actually pass any time
zone offset information to the underlying strftime XS/C function it
calls, so these parts of the C struct tm are initialized to the
machine's localtime (usually via init_tm provided by Perl's util.c) [1].
Hence the time values are in GMT but the local zone (%z or %Z) is
returned without any conversion being done.
When the format contains %z or %Z, strftime needs to either a) convert
to local time first (from GMT or whatever offset is in the object) or b)
set the appropriate offsets and name in the C struct so a zone other
than the local time is reported.
All that said, note that the strptime provided by Time::Piece ignores
the got_GMT flag it gets from the parser [2]. The effect of this is
that Time::Piece always treats strings without %z as GMT, not the local
zone. This may be unintuitive and certainly should be documented.
Strings *with* %z are converted to GMT while parsing, so if you're
explicit, such as in your examples, you're OK.
Show quoted text> Also %Z seems completely broken:
Real strptime support for %Z is pretty hard to find, including in glibc.
Time::Piece's strptime is no different, and it only recogizes "GMT" [3].
It is worth noting that GNU date(1) can handle lots of timezone
specifications (refer to the parse_datetime function in GNU coreutils),
though it does recommend against ambiguous names like "EST" [4].
[1]
http://perl5.git.perl.org/perl.git/blob/HEAD:/util.c#l3599
[2]
https://metacpan.org/source/RJBS/Time-Piece-1.27/Piece.xs#L1107
[3]
https://metacpan.org/source/RJBS/Time-Piece-1.27/Piece.xs#L894
[4]
https://www.gnu.org/software/coreutils/manual/html_node/Time-zone-items.html#Time-zone-items