diff --git a/lib/Date/Format/Generic.pm b/lib/Date/Format/Generic.pm index b3b8bdf..1f7c496 100644 --- a/lib/Date/Format/Generic.pm +++ b/lib/Date/Format/Generic.pm @@ -207,7 +207,9 @@ sub format_Z { sub format_z { my $t = $_[0]->[9]; my $o = defined $tzname ? tz_offset($tzname, $t) : tz_offset(undef,$t); - sprintf("%+03d%02d", int($o / 3600), int(abs($o) % 3600) / 60); + my $sign = $o < 0 ? '-' : '+'; + my $abs = abs($o); + sprintf("%s%02d%02d", $sign, int($abs / 3600), int($abs % 3600) / 60); } sub format_c { &format_x . " " . &format_X } diff --git a/t/format-z-sign.t b/t/format-z-sign.t new file mode 100644 index 0000000..9c4b6ac --- /dev/null +++ b/t/format-z-sign.t @@ -0,0 +1,22 @@ +use strict; +use warnings; +use Test::More tests => 6; +use Date::Format qw(time2str); + +# Regression: format_z lost the sign for negative sub-hour timezone offsets +# because int(-1800/3600) truncates to 0, and sprintf("%+03d",...) renders +# 0 as "+00" instead of "-00". + +my $epoch = 946684800; # 2000-01-01 00:00:00 UTC + +# Negative sub-hour offsets (the bug) +is(time2str("%z", $epoch, "-0030"), "-0030", "%z preserves sign for -0030"); +is(time2str("%z", $epoch, "-0015"), "-0015", "%z preserves sign for -0015"); +is(time2str("%z", $epoch, "-0045"), "-0045", "%z preserves sign for -0045"); + +# Positive sub-hour offsets (control) +is(time2str("%z", $epoch, "+0030"), "+0030", "%z correct for +0030"); +is(time2str("%z", $epoch, "+0545"), "+0545", "%z correct for +0545 (Nepal)"); + +# Zero offset +is(time2str("%z", $epoch, "+0000"), "+0000", "%z correct for UTC");