perl/Git.pm: fix get_tz_offset to properly handle DST boundary cases
authorBen Walton <bdwalton@gmail.com>
Sat, 9 Feb 2013 21:46:57 +0000 (21:46 +0000)
committerJunio C Hamano <gitster@pobox.com>
Sat, 9 Feb 2013 22:34:18 +0000 (14:34 -0800)
When passed a local time that was on the boundary of a DST change,
get_tz_offset returned a GMT offset that was incorrect (off by one
hour). This is because the time was converted to GMT and then back to
a time stamp via timelocal() which cannot disambiguate boundary cases
as noted in its documentation.

Modify this algorithm, using an approach suggested in

http://article.gmane.org/gmane.comp.version-control.git/213871

to first convert the timestamp in question to two broken down forms
with localtime() and gmtime(), and then compute what timestamps
these two broken down forms would represent in GMT (i.e. a timezone
that does not have DST issues) by applying timegm() on them. The
difference between the resulting timestamps is the timezone offset.

This avoids the ambigious conversion and allows a correct time to be
returned on every occassion.

Signed-off-by: Ben Walton <bdwalton@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
perl/Git.pm
index 5649bcc3b1461d0beb703289b4608283df05081d..a56d1e76f797cdba83510a5488945425f1936c2d 100644 (file)
@@ -103,7 +103,7 @@ =head1 DESCRIPTION
 use Cwd qw(abs_path cwd);
 use IPC::Open2 qw(open2);
 use Fcntl qw(SEEK_SET SEEK_CUR);
-use Time::Local qw(timelocal);
+use Time::Local qw(timegm);
 }
 
 
@@ -528,8 +528,8 @@ sub version {
 sub get_tz_offset {
        # some systmes don't handle or mishandle %z, so be creative.
        my $t = shift || time;
-       my $gm = timelocal(gmtime($t));
-       my $sign = qw( + + - )[ $t <=> $gm ];
+       my $gm = timegm(localtime($t));
+       my $sign = qw( + + - )[ $gm <=> $t ];
        return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
 }