Change use|require 5.005_64 to use|require 5.6.1.
[p5sagit/p5-mst-13.2.git] / lib / Time / Local.pm
index f2f1672..6180584 100644 (file)
@@ -1,21 +1,26 @@
 package Time::Local;
-require 5.000;
+require 5.6.0;
 require Exporter;
 use Carp;
+use strict;
 
-@ISA = qw(Exporter);
-@EXPORT = qw(timegm timelocal);
+our $VERSION    = '1.02';
+our @ISA       = qw( Exporter );
+our @EXPORT    = qw( timegm timelocal );
+our @EXPORT_OK = qw( timegm_nocheck timelocal_nocheck );
 
 # Set up constants
-    $SEC  = 1;
-    $MIN  = 60 * $SEC;
-    $HR   = 60 * $MIN;
-    $DAY  = 24 * $HR;
+our $SEC  = 1;
+our $MIN  = 60 * $SEC;
+our $HR   = 60 * $MIN;
+our $DAY  = 24 * $HR;
 # Determine breakpoint for rolling century
-    my $thisYear = (localtime())[5];
-    $nextCentury = int($thisYear / 100) * 100;
-    $breakpoint = ($thisYear + 50) % 100;
-    $nextCentury += 100 if $breakpoint < 50;
+    my $ThisYear = (localtime())[5];
+    my $NextCentury = int($ThisYear / 100) * 100;
+    my $Breakpoint = ($ThisYear + 50) % 100;
+       $NextCentury += 100 if $Breakpoint < 50;
+
+our(%Options, %Cheat);
 
 sub timegm {
     my (@date) = @_;
@@ -23,11 +28,11 @@ sub timegm {
         $date[5] -= 1900;
     }
     elsif ($date[5] >= 0 && $date[5] < 100) {
-        $date[5] -= 100 if $date[5] > $breakpoint;
-        $date[5] += $nextCentury;
+        $date[5] -= 100 if $date[5] > $Breakpoint;
+        $date[5] += $NextCentury;
     }
-    $ym = pack(C2, @date[5,4]);
-    $cheat = $cheat{$ym} || &cheat(@date);
+    my $ym = pack('C2', @date[5,4]);
+    my $cheat = $Cheat{$ym} || &cheat($ym, @date);
     $cheat
     + $date[0] * $SEC
     + $date[1] * $MIN
@@ -35,6 +40,11 @@ sub timegm {
     + ($date[3]-1) * $DAY;
 }
 
+sub timegm_nocheck {
+    local $Options{no_range_check} = 1;
+    &timegm;
+}
+
 sub timelocal {
     my $t = &timegm;
     my $tt = $t;
@@ -51,7 +61,6 @@ sub timelocal {
 
     my $tzsec = ($gt[1] - $lt[1]) * $MIN + ($gt[2] - $lt[2]) * $HR;
 
-    my($lday,$gday) = ($lt[7],$gt[7]);
     if($lt[5] > $gt[5]) {
        $tzsec -= $DAY;
     }
@@ -64,52 +73,64 @@ sub timelocal {
 
     $tzsec += $HR if($lt[8]);
     
-    $time = $t + $tzsec;
-    @test = localtime($time + ($tt - $t));
+    my $time = $t + $tzsec;
+    my @test = localtime($time + ($tt - $t));
     $time -= $HR if $test[2] != $_[2];
     $time;
 }
 
+sub timelocal_nocheck {
+    local $Options{no_range_check} = 1;
+    &timelocal;
+}
+
 sub cheat {
-    $year = $_[5];
-    $month = $_[4];
-    croak "Month '$month' out of range 0..11"  if $month > 11 || $month < 0;
-    croak "Day '$_[3]' out of range 1..31"     if $_[3] > 31 || $_[3] < 1;
-    croak "Hour '$_[2]' out of range 0..23"    if $_[2] > 23 || $_[2] < 0;
-    croak "Minute '$_[1]' out of range 0..59"  if $_[1] > 59 || $_[1] < 0;
-    croak "Second '$_[0]' out of range 0..59"  if $_[0] > 59 || $_[0] < 0;
-    $guess = $^T;
-    @g = gmtime($guess);
-    $lastguess = "";
-    $counter = 0;
-    while ($diff = $year - $g[5]) {
-       croak "Can't handle date (".join(", ",@_).")" if ++$counter > 255;
+    my($ym, @date) = @_;
+    my($sec, $min, $hour, $day, $month, $year) = @date;
+    unless ($Options{no_range_check}) {
+ croak "Month '$month' out of range 0..11" if $month > 11   || $month < 0;
+        my $md = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[$month];
+       $md++ if $month == 1 &&
+           $year % 4 == 0 && ($year % 100 > 0 || $year % 400 == 100);  # leap
+ croak "Day '$day' out of range 1..$md"    if $day   > $md  || $day   < 1;
+ croak "Hour '$hour' out of range 0..23"   if $hour  > 23   || $hour  < 0;
+ croak "Minute '$min' out of range 0..59"  if $min   > 59   || $min   < 0;
+ croak "Second '$sec' out of range 0..59"  if $sec   > 59   || $sec   < 0;
+    }
+    my $guess = $^T;
+    my @g = gmtime($guess);
+    my $lastguess = "";
+    my $counter = 0;
+    while (my $diff = $year - $g[5]) {
+        my $thisguess;
+       croak "Can't handle date (".join(", ",@date).")" if ++$counter > 255;
        $guess += $diff * (363 * $DAY);
        @g = gmtime($guess);
        if (($thisguess = "@g") eq $lastguess){
-           croak "Can't handle date (".join(", ",@_).")";
+           croak "Can't handle date (".join(", ",@date).")";
            #date beyond this machine's integer limit
        }
        $lastguess = $thisguess;
     }
-    while ($diff = $month - $g[4]) {
-       croak "Can't handle date (".join(", ",@_).")" if ++$counter > 255;
+    while (my $diff = $month - $g[4]) {
+        my $thisguess;
+       croak "Can't handle date (".join(", ",@date).")" if ++$counter > 255;
        $guess += $diff * (27 * $DAY);
        @g = gmtime($guess);
        if (($thisguess = "@g") eq $lastguess){
-           croak "Can't handle date (".join(", ",@_).")";
+           croak "Can't handle date (".join(", ",@date).")";
            #date beyond this machine's integer limit
        }
        $lastguess = $thisguess;
     }
-    @gfake = gmtime($guess-1); #still being sceptic
+    my @gfake = gmtime($guess-1); #still being sceptic
     if ("@gfake" eq $lastguess){
-        croak "Can't handle date (".join(", ",@_).")";
+        croak "Can't handle date (".join(", ",@date).")";
         #date beyond this machine's integer limit
     }
     $g[3]--;
     $guess -= $g[0] * $SEC + $g[1] * $MIN + $g[2] * $HR + $g[3] * $DAY;
-    $cheat{$ym} = $guess;
+    $Cheat{$ym} = $guess;
 }
 
 1;
@@ -122,21 +143,42 @@ Time::Local - efficiently compute time from local and GMT time
 
 =head1 SYNOPSIS
 
-    $time = timelocal($sec,$min,$hours,$mday,$mon,$year);
-    $time = timegm($sec,$min,$hours,$mday,$mon,$year);
+    $time = timelocal($sec,$min,$hour,$mday,$mon,$year);
+    $time = timegm($sec,$min,$hour,$mday,$mon,$year);
 
 =head1 DESCRIPTION
 
-These routines are the inverse of built-in perl fuctions localtime()
+These routines are the inverse of built-in perl functions localtime()
 and gmtime().  They accept a date as a six-element array, and return
 the corresponding time(2) value in seconds since the Epoch (Midnight,
 January 1, 1970).  This value can be positive or negative.
 
 It is worth drawing particular attention to the expected ranges for
-the values provided.  While the day of the month is expected to be in
-the range 1..31, the month should be in the range 0..11.  
+the values provided.  The value for the day of the month is the actual day
+(ie 1..31), while the month is the number of months since January (0..11).
 This is consistent with the values returned from localtime() and gmtime().
 
+The timelocal() and timegm() functions perform range checking on the
+input $sec, $min, $hour, $mday, and $mon values by default.  If you'd
+rather they didn't, you can explicitly import the timelocal_nocheck()
+and timegm_nocheck() functions.
+
+       use Time::Local 'timelocal_nocheck';
+
+       {
+           # The 365th day of 1999
+           print scalar localtime timelocal_nocheck 0,0,0,365,0,99;
+
+           # The twenty thousandth day since 1970
+           print scalar localtime timelocal_nocheck 0,0,0,20000,0,70;
+
+           # And even the 10,000,000th second since 1999!
+           print scalar localtime timelocal_nocheck 10000000,0,0,1,0,99;
+       }
+
+Your mileage may vary when trying these with minutes and hours,
+and it doesn't work at all for months.
+
 Strictly speaking, the year should also be specified in a form consistent
 with localtime(), i.e. the offset from 1900.
 In order to make the interpretation of the year easier for humans,