package Time::Local; require 5.000; require Exporter; use Carp; @ISA = qw( Exporter ); @EXPORT = qw( timegm timelocal ); @EXPORT_OK = qw( timegm_nocheck timelocal_nocheck ); # Set up constants $SEC = 1; $MIN = 60 * $SEC; $HR = 60 * $MIN; $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 %options; sub timegm { my (@date) = @_; if ($date[5] > 999) { $date[5] -= 1900; } elsif ($date[5] >= 0 && $date[5] < 100) { $date[5] -= 100 if $date[5] > $breakpoint; $date[5] += $nextCentury; } $ym = pack(C2, @date[5,4]); $cheat = $cheat{$ym} || &cheat(@date); $cheat + $date[0] * $SEC + $date[1] * $MIN + $date[2] * $HR + ($date[3]-1) * $DAY; } sub timegm_nocheck { local $options{no_range_check} = 1; &timegm; } sub timelocal { my $t = &timegm; my $tt = $t; my (@lt) = localtime($t); my (@gt) = gmtime($t); if ($t < $DAY and ($lt[5] >= 70 or $gt[5] >= 70 )) { # Wrap error, too early a date # Try a safer date $tt += $DAY; @lt = localtime($tt); @gt = gmtime($tt); } my $tzsec = ($gt[1] - $lt[1]) * $MIN + ($gt[2] - $lt[2]) * $HR; if($lt[5] > $gt[5]) { $tzsec -= $DAY; } elsif($gt[5] > $lt[5]) { $tzsec += $DAY; } else { $tzsec += ($gt[7] - $lt[7]) * $DAY; } $tzsec += $HR if($lt[8]); $time = $t + $tzsec; @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]; unless ($options{no_range_check}) { 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; $guess += $diff * (363 * $DAY); @g = gmtime($guess); if (($thisguess = "@g") eq $lastguess){ croak "Can't handle date (".join(", ",@_).")"; #date beyond this machine's integer limit } $lastguess = $thisguess; } while ($diff = $month - $g[4]) { croak "Can't handle date (".join(", ",@_).")" if ++$counter > 255; $guess += $diff * (27 * $DAY); @g = gmtime($guess); if (($thisguess = "@g") eq $lastguess){ croak "Can't handle date (".join(", ",@_).")"; #date beyond this machine's integer limit } $lastguess = $thisguess; } @gfake = gmtime($guess-1); #still being sceptic if ("@gfake" eq $lastguess){ croak "Can't handle date (".join(", ",@_).")"; #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; } 1;