Skip to content

Commit 008c40e

Browse files
Koan-Botclaude
andcommitted
fix: str2time rejects epoch -1 (Dec 31, 1969 23:59:59 UTC)
The epoch -1 detection logic compares parsed date components against a hardcoded string to distinguish the legitimate -1 return value from timegm/timelocal errors. However, since two-digit years are now normalized to four-digit years before the timegm call, the comparison always fails — the join produces "59592331111969" (year=1969) but the check expected "595923311169" (year=69). Fix: update the UTC check to use the 4-digit year string, and adjust the local-time check to add 1900 to the localtime(-1) year component. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent de1fb47 commit 008c40e

2 files changed

Lines changed: 24 additions & 2 deletions

File tree

lib/Date/Parse.pm

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ sub str2time
303303
if !defined $result
304304
or $result == -1
305305
&& join("",$ss,$mm,$hh,$day,$month,$year)
306-
ne "595923311169";
306+
ne "59592331111969";
307307
# Detect integer overflow: post-1970 dates must produce a non-negative epoch
308308
return undef if $result < 0 && $year >= 1970;
309309
$result -= $zone;
@@ -313,11 +313,13 @@ sub str2time
313313
local $SIG{__DIE__} = sub {}; # Ick!
314314
timelocal($ss,$mm,$hh,$day,$month,$year);
315315
};
316+
my @_neg1 = localtime(-1);
317+
$_neg1[5] += 1900;
316318
return undef
317319
if !defined $result
318320
or $result == -1
319321
&& join("",$ss,$mm,$hh,$day,$month,$year)
320-
ne join("",(localtime(-1))[0..5]);
322+
ne join("",@_neg1[0..5]);
321323
# Detect integer overflow: post-1970 dates must produce a non-negative epoch
322324
# Use 1971 to avoid false positives from timezone offsets near epoch 0
323325
return undef if $result < 0 && $year >= 1971;

t/edge-cases.t

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,4 +254,24 @@ ok(!defined str2time("not a date at all"), "str2time('not a date at all') return
254254
}
255255
}
256256

257+
# --- Epoch -1 (Dec 31, 1969 23:59:59 UTC) parsing ---
258+
# timegm() returns -1 for this date, which collides with Perl's error
259+
# convention. str2time must distinguish the legitimate -1 from errors.
260+
{
261+
my $t = str2time("31 Dec 1969 23:59:59 GMT");
262+
is($t, -1, "epoch -1: 4-digit year with GMT");
263+
264+
my $t2 = str2time("1969-12-31T23:59:59Z");
265+
is($t2, -1, "epoch -1: ISO 8601 with Z");
266+
267+
my $t3 = str2time("Wed, 31 Dec 1969 23:59:59 +0000");
268+
is($t3, -1, "epoch -1: RFC 2822 with +0000");
269+
270+
my $t4 = str2time("31 Dec 69 23:59:59 GMT");
271+
is($t4, -1, "epoch -1: 2-digit year with GMT");
272+
273+
my $t5 = str2time("1969-12-31 23:59:59 +0000");
274+
is($t5, -1, "epoch -1: ISO with space separator");
275+
}
276+
257277
done_testing;

0 commit comments

Comments
 (0)