Skip to content

Commit 072679c

Browse files
Koan-Botclaude
andcommitted
fix: strftime() sets epoch index for %G and %s format codes
strftime() never assigned $me->[9] (the epoch timestamp), so format codes that read it — %G (GPS week) and %s (epoch seconds) — produced wrong results. %G returned -522 instead of the correct GPS week number because the uninitialized value was treated as zero. Set $me->[9] in both the timezone and non-timezone code paths, matching what time2str() already does. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0ca347f commit 072679c

2 files changed

Lines changed: 51 additions & 1 deletion

File tree

lib/Date/Format/Generic.pm

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,13 @@ sub strftime
5656
$epoch = timelocal(@{$time}[0..5]);
5757

5858
@$me = gmtime($epoch + tz_offset($tzname));
59+
$me->[9] = $epoch;
5960
}
6061
else
6162
{
6263
@$me = @$time;
63-
undef $epoch;
64+
$epoch = timelocal(@$me[0..5]);
65+
$me->[9] = $epoch;
6466
}
6567

6668
_subs($me,$fmt);

t/strftime-epoch.t

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use strict;
2+
use warnings;
3+
use Test::More;
4+
use Date::Format qw(time2str strftime);
5+
use Time::Local qw(timegm);
6+
7+
# strftime() was missing $me->[9] (epoch timestamp), causing format codes
8+
# that depend on it (%G, %s) to produce wrong results.
9+
10+
my $t = timegm(0, 0, 12, 28, 3, 124); # 2024-04-28 12:00:00 UTC
11+
my @gmt = gmtime($t);
12+
13+
# %G (GPS week) - was returning -522 instead of 2312
14+
is(time2str("%G", $t, "UTC"), "2312",
15+
"time2str %G gives correct GPS week");
16+
is(strftime("%G", @gmt, "UTC"), "2312",
17+
"strftime %G with timezone gives correct GPS week");
18+
19+
# %s (epoch seconds) - strftime with localtime should match time2str
20+
my @lt = localtime($t);
21+
is(time2str("%s", $t), strftime("%s", @lt),
22+
"strftime %s (localtime, no tz) matches time2str %s");
23+
24+
# GPS epoch boundary via strftime
25+
my $gps_epoch = 315964800;
26+
my @gps_gmt = gmtime($gps_epoch);
27+
is(strftime("%G", @gps_gmt, "UTC"), "0",
28+
"strftime %G at GPS epoch is week 0");
29+
30+
my @week1_gmt = gmtime($gps_epoch + 7 * 86400);
31+
is(strftime("%G", @week1_gmt, "UTC"), "1",
32+
"strftime %G one week after GPS epoch is week 1");
33+
34+
# Verify strftime and time2str agree on %G for several dates
35+
for my $pair (
36+
[timegm(0, 0, 0, 6, 0, 80), "0", "GPS epoch"],
37+
[timegm(0, 0, 0, 13, 0, 80), "1", "start of week 1"],
38+
[936709362, "1026", "Sep 7, 1999"],
39+
) {
40+
my ($epoch, $expected, $label) = @$pair;
41+
my @g = gmtime($epoch);
42+
is(strftime("%G", @g, "UTC"), $expected,
43+
"strftime %G: $label");
44+
is(time2str("%G", $epoch, "UTC"), $expected,
45+
"time2str %G: $label (cross-check)");
46+
}
47+
48+
done_testing;

0 commit comments

Comments
 (0)