git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Ben Walton <bdwalton@gmail.com>
To: Junio C Hamano <gitster@pobox.com>
Cc: Eric Raymond <esr@thyrsus.com>, git <git@vger.kernel.org>
Subject: Re: [PATCH 2/3] Allow Git::get_tz_offset to properly handle DST boundary times
Date: Sun, 20 Jan 2013 20:06:13 +0000	[thread overview]
Message-ID: <CAP30j14Og7YLaZj0dbpAhUHFfuy0Y=bEn_3EqGzxR5PRA7vQXA@mail.gmail.com> (raw)
In-Reply-To: <7vy5frtymt.fsf@alter.siamese.dyndns.org>

On Thu, Jan 17, 2013 at 7:09 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Ben Walton <bdwalton@gmail.com> writes:
>
>> The Git::get_tz_offset is meant to provide a workalike replacement for
>> the GNU strftime %z format specifier.  The algorithm used failed to
>> properly handle DST boundary cases.
>>
>> For example, the unix time 1162105199 in CST6CDT saw set_tz_offset
>> improperly return -0600 instead of -0500.
>>
>> TZ=CST6CDT date -d @1162105199 +"%c %z"
>> Sun 29 Oct 2006 01:59:59 AM CDT -0500
>>
>> $ zdump -v /usr/share/zoneinfo/CST6CDT | grep 2006
>> /usr/share/zoneinfo/CST6CDT  Sun Apr  2 07:59:59 2006 UTC = Sun Apr  2
>> 01:59:59 2006 CST isdst=0 gmtoff=-21600
>> /usr/share/zoneinfo/CST6CDT  Sun Apr  2 08:00:00 2006 UTC = Sun Apr  2
>> 03:00:00 2006 CDT isdst=1 gmtoff=-18000
>> /usr/share/zoneinfo/CST6CDT  Sun Oct 29 06:59:59 2006 UTC = Sun Oct 29
>> 01:59:59 2006 CDT isdst=1 gmtoff=-18000
>> /usr/share/zoneinfo/CST6CDT  Sun Oct 29 07:00:00 2006 UTC = Sun Oct 29
>> 01:00:00 2006 CST isdst=0 gmtoff=-21600
>>
>> To determine how many hours/minutes away from GMT a particular time
>> was, we calculated the gmtime() of the requested time value and then
>> used Time::Local's timelocal() function to turn the GMT-based time
>> back into a scalar value representing seconds from the epoch.  Because
>> GMT has no daylight savings time, timelocal() cannot handle the
>> ambiguous times that occur at DST boundaries since there are two
>> possible correct results.
>>
>> To work around the ambiguity at these boundaries, we must take into
>> account the pre and post conversion values for is_dst as provided by
>> both the original time value and the value that has been run through
>> timelocal().  If the is_dst field of the two times disagree then we
>> must modify the value returned from timelocal() by an hour in the
>> correct direction.
>
> It seems to me that it is a very roundabout way.  It may be correct,
> but it is unclear why the magic +/-3600 shift is the right solution
> and I suspect even you wouldn't notice if I sent you back your patch
> with a slight change to swap $gm += 3600 and $gm -= 3600 lines ;-).
>
> For that timestamp in question, the human-readable representation of
> gmtime($t) and localtime($t) look like these two strings:
>
>         my $t = 1162105199;
>         print gmtime($t), "\n";    # Sun Oct 29 06:59:59 2006
>         print localtime($t), "\n"; # Sun Oct 29 01:59:59 2006
>
> As a human, you can easily see that these two stringified timestamps
> look 5 hours apart.  Think how you managed to do so.
>
> If we convert these back to the seconds-since-epoch, as if these
> broken-down times were both in a single timezone that does not have
> any DST issues, you can get the offset (in seconds) by subtraction,
> and that is essentially the same as the way in which your eyes saw
> they are 5 hours apart, no?  In other words, why do you need to run
> timelocal() at all?
>
>         my $t = 1162105199;
>         my $lct = timegm(localtime($t));
>         # of course, timegm(gmtime($t)) == $t
>
>         my $minutes = int(($lct - $t)/60);
>         my $sign "+";
>         if ($minutes < 0) {
>                 $sign = "-";
>                 $minutes = -$minutes;
>         }
>         my $hours = int($minutes/60);
>         $minutes -= $hours * 60;
>         sprintf("%s%02d%02d", $sign, $hours, $minutes);
>
> Confused...
>
>>
>> Signed-off-by: Ben Walton <bdwalton@gmail.com>
>> ---
>>  perl/Git.pm |   20 ++++++++++++++++++++
>>  1 file changed, 20 insertions(+)
>>
>> diff --git a/perl/Git.pm b/perl/Git.pm
>> index 5649bcc..788b9b4 100644
>> --- a/perl/Git.pm
>> +++ b/perl/Git.pm
>> @@ -528,7 +528,27 @@ If TIME is not supplied, the current local time is used.
>>  sub get_tz_offset {
>>       # some systmes don't handle or mishandle %z, so be creative.
>>       my $t = shift || time;
>> +     # timelocal() has a problem when it comes to DST ambiguity so
>> +     # times that are on a DST boundary cannot be properly converted
>> +     # using it.  we will possibly adjust its result depending on whehter
>> +     # pre and post conversions agree on DST
>>       my $gm = timelocal(gmtime($t));
>> +
>> +     # we need to know whether we were originally in DST or not
>> +     my $orig_dst = (localtime($t))[8];
>> +     # and also whether timelocal thinks we're in DST
>> +     my $conv_dst = (localtime($gm))[8];
>> +
>> +     # re-adjust $gm based on the DST value for the two times we're
>> +     # handling.
>> +     if ($orig_dst != $conv_dst) {
>> +             if ($orig_dst == 1) {
>> +                     $gm -= 3600;
>> +             } else {
>> +                     $gm += 3600;
>> +             }
>> +     }
>> +
>>       my $sign = qw( + + - )[ $t <=> $gm ];
>>       return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
>>  }


Sorry for the slow response, I didn't have a good chance to look at
this until now.  You are correct; your solution appears simpler and
also avoids the oddball 1/2 hour DST shift.  I can re-roll the series
with your code (and credit for it) or you can apply you change on top
of my series...whichever is easiest for you.

Thanks
-Ben
--
---------------------------------------------------------------------------------------------------------------------------
Take the risk of thinking for yourself.  Much more happiness,
truth, beauty and wisdom will come to you that way.

-Christopher Hitchens
---------------------------------------------------------------------------------------------------------------------------

  reply	other threads:[~2013-01-20 20:09 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-01-15 23:10 [PATCH 0/3] Fix a portability issue with git-cvsimport Ben Walton
2013-01-15 23:10 ` [PATCH 1/3] Move Git::SVN::get_tz to Git::get_tz_offset Ben Walton
2013-01-16 15:37   ` Junio C Hamano
2013-01-16 20:16     ` Ben Walton
2013-01-16 20:36       ` Junio C Hamano
2013-01-15 23:10 ` [PATCH 2/3] Allow Git::get_tz_offset to properly handle DST boundary times Ben Walton
2013-01-17 19:09   ` Junio C Hamano
2013-01-20 20:06     ` Ben Walton [this message]
2013-01-20 21:03       ` Junio C Hamano
2013-01-15 23:10 ` [PATCH 3/3] Avoid non-portable strftime format specifiers in git-cvsimport Ben Walton
2013-01-16  1:53   ` Chris Rorvick
2013-01-16 10:38     ` Ben Walton
2013-01-15 23:43 ` [PATCH 0/3] Fix a portability issue with git-cvsimport Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAP30j14Og7YLaZj0dbpAhUHFfuy0Y=bEn_3EqGzxR5PRA7vQXA@mail.gmail.com' \
    --to=bdwalton@gmail.com \
    --cc=esr@thyrsus.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).