diff options
-rwxr-xr-x | Porting/Maintainers.pl | 2 | ||||
-rw-r--r-- | ext/Time-Local/lib/Time/Local.pm | 49 | ||||
-rw-r--r-- | ext/Time-Local/t/Local.t | 80 | ||||
-rw-r--r-- | pod/perldelta.pod | 2 |
4 files changed, 96 insertions, 37 deletions
diff --git a/Porting/Maintainers.pl b/Porting/Maintainers.pl index 89deb84f02..a0f3e2c689 100755 --- a/Porting/Maintainers.pl +++ b/Porting/Maintainers.pl @@ -1520,7 +1520,7 @@ use File::Glob qw(:case); 'Time::Local' => { 'MAINTAINER' => 'drolsky', - 'DISTRIBUTION' => 'DROLSKY/Time-Local-1.1901.tar.gz', + 'DISTRIBUTION' => 'FLORA/Time-Local-1.2000.tar.gz', 'FILES' => q[ext/Time-Local], 'EXCLUDED' => [ qw(t/pod-coverage.t t/pod.t) ], 'UPSTREAM' => 'blead', 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'); diff --git a/pod/perldelta.pod b/pod/perldelta.pod index 42c4c42457..3a846a9f5e 100644 --- a/pod/perldelta.pod +++ b/pod/perldelta.pod @@ -112,7 +112,7 @@ C<threads::shared> has been upgraded from version 1.35 to 1.36 =item * -XXX +C<Time::Local> has been upgraded from version 1.1901_01 to 1.2000. =back |