summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorFlorian Ragwitz <rafl@debian.org>2011-01-02 16:25:52 +0100
committerFlorian Ragwitz <rafl@debian.org>2011-01-02 16:34:49 +0100
commit23046b7e6ff1fe67d95bf72477e961d488fd2d27 (patch)
treecfe8bfe8d489ad4992ce471016042170b62b43f6 /ext
parentb99c822f5c5b52c35b7eb52dd8936b00e664b01c (diff)
downloadperl-23046b7e6ff1fe67d95bf72477e961d488fd2d27.tar.gz
Make Time::Local run on perls older than 5.12 again
With 5.12, this module was made y2038-safe, even on systems with a 32-bit time_t. Unfortunately, that broke things on older perl versions and blead became this module's upstream as the y2038-safety couldn't easily be backported. This change also doesn't attempt to backport y2038 support. It merely restores the old behaviour including the y2038 limitations on older versions of perl on platforms without a 64-bit time_t. With this, we can at least move Time::Locale's upstream back to CPAN. Making it y2038-safe for old perls on 32-bit time_t platforms probably shouldn't be a priority anyway. There's Time::y2038, which does everything this module does, and then some, while being y2038-safe. At some point, this module should probably be deprecated.
Diffstat (limited to 'ext')
-rw-r--r--ext/Time-Local/lib/Time/Local.pm49
-rw-r--r--ext/Time-Local/t/Local.t80
2 files changed, 94 insertions, 35 deletions
diff --git a/ext/Time-Local/lib/Time/Local.pm b/ext/Time-Local/lib/Time/Local.pm
index 96a688d92c..0e9c4ac467 100644
--- a/ext/Time-Local/lib/Time/Local.pm
+++ b/ext/Time-Local/lib/Time/Local.pm
@@ -6,7 +6,7 @@ use Config;
use strict;
use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK );
-$VERSION = '1.1901_01';
+$VERSION = '1.2000';
@ISA = qw( Exporter );
@EXPORT = qw( timegm timelocal );
@@ -28,8 +28,23 @@ use constant SECS_PER_MINUTE => 60;
use constant SECS_PER_HOUR => 3600;
use constant SECS_PER_DAY => 86400;
-# localtime()'s limit is the year 2**31
-my $MaxDay = 365 * (2**31);
+my $MaxDay;
+if ($] < 5.012000) {
+ my $MaxInt;
+ if ( $^O eq 'MacOS' ) {
+ # time_t is unsigned...
+ $MaxInt = ( 1 << ( 8 * $Config{ivsize} ) ) - 1;
+ }
+ else {
+ $MaxInt = ( ( 1 << ( 8 * $Config{ivsize} - 2 ) ) - 1 ) * 2 + 1;
+ }
+
+ $MaxDay = int( ( $MaxInt - ( SECS_PER_DAY / 2 ) ) / SECS_PER_DAY ) - 1;
+}
+else {
+ # recent localtime()'s limit is the year 2**31
+ $MaxDay = 365 * (2**31);
+}
# Determine the EPOC day for this machine
my $Epoc = 0;
@@ -266,6 +281,21 @@ absolute four digit year instead.
The scheme above allows interpretation of a wide range of dates,
particularly if 4-digit years are used.
+=head2 Limits of time_t
+
+On perl versions older than 5.12.0, the range of dates that can be
+actually be handled depends on the size of C<time_t> (usually a signed
+integer) on the given platform. Currently, this is 32 bits for most
+systems, yielding an approximate range from Dec 1901 to Jan 2038.
+
+Both C<timelocal()> and C<timegm()> croak if given dates outside the
+supported range.
+
+As of version 5.12.0, perl has stopped using the underlying time
+library of the operating system it's running on and has its own
+implementation of those routines with a safe range of at least
++/ 2**52 (about 142 million years).
+
=head2 Ambiguous Local Times (DST)
Because of DST changes, there are many time zones where the same local
@@ -288,6 +318,19 @@ for the "Europe/Paris" time zone, the local clock jumped from
If the C<timelocal()> function is given a non-existent local time, it
will simply return an epoch value for the time one hour later.
+=head2 Negative Epoch Values
+
+On perl version 5.12.0 and newer, negative epoch values are fully
+supported.
+
+On older versions of perl, negative epoch (C<time_t>) values, which
+are not officially supported by the POSIX standards, are known not to
+work on some systems. These include MacOS (pre-OSX) and Win32.
+
+On systems which do support negative epoch values, this module should
+be able to cope with dates before the start of the epoch, down the
+minimum value of time_t for the system.
+
=head1 IMPLEMENTATION
These routines are quite efficient and yet are always guaranteed to
diff --git a/ext/Time-Local/t/Local.t b/ext/Time-Local/t/Local.t
index 61a15a8b16..521cac0bb3 100644
--- a/ext/Time-Local/t/Local.t
+++ b/ext/Time-Local/t/Local.t
@@ -19,12 +19,17 @@ my @time =
# leap day
[2020, 2, 29, 12, 59, 59],
[2030, 7, 4, 17, 07, 06],
- [2038, 1, 17, 23, 59, 59], # last full day in any tz
- # more than 2**31 time_t
- [2258, 8, 11, 1, 49, 17],
+# The following test fails on a surprising number of systems
+# so it is commented out. The end of the Epoch for a 32-bit signed
+# implementation of time_t should be Jan 19, 2038 03:14:07 UTC.
+# [2038, 1, 17, 23, 59, 59], # last full day in any tz
);
+# more than 2**31 time_t - requires a 64bit safe localtime/gmtime
+push @time, [2258, 8, 11, 1, 49, 17]
+ if $] >= 5.012000;
+
my @bad_time =
(
# month too large
@@ -82,35 +87,42 @@ for (@time, @neg_time) {
$year -= 1900;
$mon--;
- # Test timelocal()
- {
- my $year_in = $year < 70 ? $year + 1900 : $year;
- my $time = timelocal($sec,$min,$hour,$mday,$mon,$year_in);
-
- my($s,$m,$h,$D,$M,$Y) = localtime($time);
-
- is($s, $sec, "timelocal second for @$_");
- is($m, $min, "timelocal minute for @$_");
- is($h, $hour, "timelocal hour for @$_");
- is($D, $mday, "timelocal day for @$_");
- is($M, $mon, "timelocal month for @$_");
- is($Y, $year, "timelocal year for @$_");
- }
-
-
- # Test timegm()
- {
- my $year_in = $year < 70 ? $year + 1900 : $year;
- my $time = timegm($sec,$min,$hour,$mday,$mon,$year_in);
-
- my($s,$m,$h,$D,$M,$Y) = gmtime($time);
-
- is($s, $sec, "timegm second for @$_");
- is($m, $min, "timegm minute for @$_");
- is($h, $hour, "timegm hour for @$_");
- is($D, $mday, "timegm day for @$_");
- is($M, $mon, "timegm month for @$_");
- is($Y, $year, "timegm year for @$_");
+ SKIP: {
+ skip '1970 test on VOS fails.', 12
+ if $^O eq 'vos' && $year == 70;
+ skip 'this platform does not support negative epochs.', 12
+ if $year < 70 && ! $neg_epoch_ok;
+
+ # Test timelocal()
+ {
+ my $year_in = $year < 70 ? $year + 1900 : $year;
+ my $time = timelocal($sec,$min,$hour,$mday,$mon,$year_in);
+
+ my($s,$m,$h,$D,$M,$Y) = localtime($time);
+
+ is($s, $sec, "timelocal second for @$_");
+ is($m, $min, "timelocal minute for @$_");
+ is($h, $hour, "timelocal hour for @$_");
+ is($D, $mday, "timelocal day for @$_");
+ is($M, $mon, "timelocal month for @$_");
+ is($Y, $year, "timelocal year for @$_");
+ }
+
+
+ # Test timegm()
+ {
+ my $year_in = $year < 70 ? $year + 1900 : $year;
+ my $time = timegm($sec,$min,$hour,$mday,$mon,$year_in);
+
+ my($s,$m,$h,$D,$M,$Y) = gmtime($time);
+
+ is($s, $sec, "timegm second for @$_");
+ is($m, $min, "timegm minute for @$_");
+ is($h, $hour, "timegm hour for @$_");
+ is($D, $mday, "timegm day for @$_");
+ is($M, $mon, "timegm month for @$_");
+ is($Y, $year, "timegm year for @$_");
+ }
}
}
@@ -157,7 +169,11 @@ for my $p (@years) {
"$year $string a leap year" );
}
+SKIP:
{
+ skip 'this platform does not support negative epochs.', 6
+ unless $neg_epoch_ok;
+
eval { timegm(0,0,0,29,1,1900) };
like($@, qr/Day '29' out of range 1\.\.28/,
'does not accept leap day in 1900');