Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

strftime time zone bug #4518

Closed
p5pRT opened this issue Oct 22, 2001 · 9 comments
Closed

strftime time zone bug #4518

p5pRT opened this issue Oct 22, 2001 · 9 comments

Comments

@p5pRT
Copy link

p5pRT commented Oct 22, 2001

Migrated from rt.perl.org#7835 (status was 'resolved')

Searchable as RT7835$

@p5pRT
Copy link
Author

p5pRT commented Oct 22, 2001

From spencer@zanshin.com

The workaround for NETaa14816 contained in ext/POSIX/POSIX.xs introduces
a different bug, namely that the time zone name and offset reported
by strftime %Z and %z are incorrect -- they report the time zone name and
offset of the current time, even if the time you pass has a different DST
setting.

I have a patch which fixes the problem, at least for our configuration.
I have no idea how portable it is and I have no hope of figuring out all
the ifdefs necessary, but I'll just show you my patch and hope you can
make some use of it (so long as I get credited if you do :-) ). If not,
oh well, and if you've already dealt with it, so much the better.

First, a sample script which demonstrates the problem​:

#!/usr/bin/perl

use strict;
use POSIX qw(strftime);

my $t = 1003803105; # approx. 7​:12 PM on Oct. 22, 2001, PDT

print_stuff($t);
print "\n";

# now add 10 days, which takes us into PST

print_stuff($t+864000);

sub print_stuff
{
  my $t = shift;
  my ($sec, $min, $hour, $mday, $mon, $year,
  $wday, $yday, $isdst) = localtime($t);
  printf("%02d/%02d/%04d %02d​:%02d​:%02d DST​: %d\n",
  $mon+1, $mday, $year+1900, $hour, $min, $sec, $isdst);
  print strftime("%A, %d-%b-%g %I​:%M %p %Z %z\n",
  $sec, $min, $hour, $mday, $mon, $year, $wday, $yday,
$isdst);
}

Using 5.6.0 on RedHat 6.2, version 2.2.16 of the kernel (also
reproduced on perl 5.6.0/Linux 2.2.14 and perl 5.6.1/linux 2.2.19), the
above script prints out​:

10/22/2001 19​:11​:45 DST​: 1
Monday, 22-Oct-01 07​:11 PM PDT -0700

11/01/2001 18​:11​:45 DST​: 0
Thursday, 01-Nov-01 06​:11 PM PDT -0700

As you can see, for the second date, even though $isdst == 0, %Z and %z
still say PDT and -0700, when they should say PST and -0800. The problem
is that init_tm uses localtime(&now) to initialize the tm structure, which
is incorrect when the actual date we are considering is on the other side
of the DST boundary (because 10/22/2001 is in DST, but 11/01/2001 is not).

I've attached my patch (diff against 5.6.0) so that Outlook won't mangle the
whitespace.

Obviously the patch depends on the correct value of isdst being passed in
to whichever function is calling init_tm, and also on tzname and timezone
being valid. But like I said, it does work for us. Post-patch​:

10/22/2001 19​:11​:45 DST​: 1
Monday, 22-Oct-01 07​:11 PM PDT -0700

11/01/2001 18​:11​:45 DST​: 0
Thursday, 01-Nov-01 06​:11 PM PST -0800

@p5pRT
Copy link
Author

p5pRT commented Oct 22, 2001

From spencer@zanshin.com

Inline Patch
--- ext/POSIX/POSIX.xs.orig	Mon Oct 22 19:04:43 2001
+++ ext/POSIX/POSIX.xs	Mon Oct 22 19:08:03 2001
@@ -320,15 +320,17 @@
 
 #ifdef STRUCT_TM_HASZONE
 static void
-init_tm(struct tm *ptm)		/* see mktime, strftime and asctime	*/
+init_tm(struct tm *ptm, int isdst)		/* see mktime, strftime and asctime	*/
 {
     Time_t now;
     (void)time(&now);
     Copy(localtime(&now), ptm, 1, struct tm);
+    ptm->tm_zone = tzname[isdst];
+    ptm->tm_gmtoff = isdst * 3600 - timezone;
 }
 
 #else
-# define init_tm(ptm)
+# define init_tm(ptm, isdst)
 #endif
 
 /*
@@ -3749,7 +3751,7 @@
     CODE:
 	{
 	    struct tm mytm;
-	    init_tm(&mytm);	/* XXX workaround - see init_tm() above */
+	    init_tm(&mytm, isdst);	/* XXX workaround - see init_tm() above */
 	    mytm.tm_sec = sec;
 	    mytm.tm_min = min;
 	    mytm.tm_hour = hour;
@@ -3803,7 +3805,7 @@
     CODE:
 	{
 	    struct tm mytm;
-	    init_tm(&mytm);	/* XXX workaround - see init_tm() above */
+	    init_tm(&mytm, isdst);	/* XXX workaround - see init_tm() above */
 	    mytm.tm_sec = sec;
 	    mytm.tm_min = min;
 	    mytm.tm_hour = hour;
@@ -3835,7 +3837,7 @@
 	    char tmpbuf[128];
 	    struct tm mytm;
 	    int len;
-	    init_tm(&mytm);	/* XXX workaround - see init_tm() above */
+	    init_tm(&mytm, isdst);	/* XXX workaround - see init_tm() above */
 	    mytm.tm_sec = sec;
 	    mytm.tm_min = min;
 	    mytm.tm_hour = hour;

@p5pRT
Copy link
Author

p5pRT commented Dec 14, 2002

From dlux@dlux.hu

This bug is still exists in 5.8.0. The proposed solution is good for BSD
systems, but systems, which does not contain the the extra struct tm
fields, can cause compilation error.

I suppose to bzero the mytm structure, it is more acceptable than the
init_tm fixes.

Other solution would be to check the linux time.h header and check what
it does with the extra fields.

@p5pRT
Copy link
Author

p5pRT commented Dec 14, 2002

From dlux@dlux.hu

Every bug needs a test case, so I attached one to avoid this problem
happening again.

@p5pRT
Copy link
Author

p5pRT commented Dec 14, 2002

From dlux@dlux.hu

minial_test.pl

@p5pRT
Copy link
Author

p5pRT commented Dec 14, 2002

From dlux@dlux.hu

[dlux - Sat Dec 14 04​:52​:44 2002]​:

Every bug needs a test case, so I attached one to avoid this problem
happening again.

Oops. It is buggy.

I forgot one line from the beginning

Here is the file again.

@p5pRT
Copy link
Author

p5pRT commented Dec 14, 2002

From dlux@dlux.hu

minial_test.pl

@p5pRT
Copy link
Author

p5pRT commented Dec 31, 2004

From @smpeters

[spencer@​zanshin.com - Mon Oct 22 12​:28​:09 2001]​:

The workaround for NETaa14816 contained in ext/POSIX/POSIX.xs introduces
a different bug, namely that the time zone name and offset reported
by strftime %Z and %z are incorrect -- they report the time zone name and
offset of the current time, even if the time you pass has a different DST
setting.

I have a patch which fixes the problem, at least for our configuration.
I have no idea how portable it is and I have no hope of figuring out all
the ifdefs necessary, but I'll just show you my patch and hope you can
make some use of it (so long as I get credited if you do :-) ). If not,
oh well, and if you've already dealt with it, so much the better.

First, a sample script which demonstrates the problem​:

#!/usr/bin/perl

use strict;
use POSIX qw(strftime);

my $t = 1003803105; # approx. 7​:12 PM on Oct. 22, 2001, PDT

print_stuff($t);
print "\n";

# now add 10 days, which takes us into PST

print_stuff($t+864000);

sub print_stuff
{
my $t = shift;
my ($sec, $min, $hour, $mday, $mon, $year,
$wday, $yday, $isdst) = localtime($t);
printf("%02d/%02d/%04d %02d​:%02d​:%02d DST​: %d\n",
$mon+1, $mday, $year+1900, $hour, $min, $sec, $isdst);
print strftime("%A, %d-%b-%g %I​:%M %p %Z %z\n",
$sec, $min, $hour, $mday, $mon, $year, $wday, $yday,
$isdst);
}

Using 5.6.0 on RedHat 6.2, version 2.2.16 of the kernel (also
reproduced on perl 5.6.0/Linux 2.2.14 and perl 5.6.1/linux 2.2.19), the
above script prints out​:

10/22/2001 19​:11​:45 DST​: 1
Monday, 22-Oct-01 07​:11 PM PDT -0700

11/01/2001 18​:11​:45 DST​: 0
Thursday, 01-Nov-01 06​:11 PM PDT -0700

As you can see, for the second date, even though $isdst == 0, %Z and %z
still say PDT and -0700, when they should say PST and -0800. The problem
is that init_tm uses localtime(&now) to initialize the tm structure, which
is incorrect when the actual date we are considering is on the other side
of the DST boundary (because 10/22/2001 is in DST, but 11/01/2001 is not).

I've attached my patch (diff against 5.6.0) so that Outlook won't
mangle the
whitespace.

Obviously the patch depends on the correct value of isdst being passed in
to whichever function is calling init_tm, and also on tzname and timezone
being valid. But like I said, it does work for us. Post-patch​:

10/22/2001 19​:11​:45 DST​: 1
Monday, 22-Oct-01 07​:11 PM PDT -0700

11/01/2001 18​:11​:45 DST​: 0
Thursday, 01-Nov-01 06​:11 PM PST -0800

This appears to have been implemented with change 18267.

@p5pRT
Copy link
Author

p5pRT commented Dec 31, 2004

@smpeters - Status changed from 'open' to 'resolved'

@p5pRT p5pRT closed this as completed Dec 31, 2004
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant