1;# timelocal.pl 2;# 3;# Usage: 4;# $time = timelocal($sec,$min,$hours,$mday,$mon,$year,$junk,$junk,$isdst); 5;# $time = timegm($sec,$min,$hours,$mday,$mon,$year); 6 7;# These routines are quite efficient and yet are always guaranteed to agree 8;# with localtime() and gmtime(). We manage this by caching the start times 9;# of any months we've seen before. If we know the start time of the month, 10;# we can always calculate any time within the month. The start times 11;# themselves are guessed by successive approximation starting at the 12;# current time, since most dates seen in practice are close to the 13;# current date. Unlike algorithms that do a binary search (calling gmtime 14;# once for each bit of the time value, resulting in 32 calls), this algorithm 15;# calls it at most 6 times, and usually only once or twice. If you hit 16;# the month cache, of course, it doesn't call it at all. 17 18;# timelocal is implemented using the same cache. We just assume that we're 19;# translating a GMT time, and then fudge it when we're done for the timezone 20;# and daylight savings arguments. The timezone is determined by examining 21;# the result of localtime(0) when the package is initialized. The daylight 22;# savings offset is currently assumed to be one hour. 23 24CONFIG: { 25 package timelocal; 26 27 @epoch = localtime(0); 28 $tzmin = $epoch[2] * 60 + $epoch[1]; # minutes east of GMT 29 if ($tzmin > 0) { 30 $tzmin = 24 * 60 - $tzmin; # minutes west of GMT 31 $tzmin -= 24 * 60 if $epoch[5] == 70; # account for the date line 32 } 33 34 $SEC = 1; 35 $MIN = 60 * $SEC; 36 $HR = 60 * $MIN; 37 $DAYS = 24 * $HR; 38 $YearFix = ((gmtime(946684800))[5] == 100) ? 100 : 0; 39} 40 41sub timegm { 42 package timelocal; 43 44 $ym = pack(C2, @_[5,4]); 45 $cheat = $cheat{$ym} || &cheat; 46 $cheat + $_[0] * $SEC + $_[1] * $MIN + $_[2] * $HR + ($_[3]-1) * $DAYS; 47} 48 49sub timelocal { 50 package timelocal; 51 52 $ym = pack(C2, @_[5,4]); 53 $cheat = $cheat{$ym} || &cheat; 54 $cheat + $_[0] * $SEC + $_[1] * $MIN + $_[2] * $HR + ($_[3]-1) * $DAYS 55 + $tzmin * $MIN - 60 * 60 * ($_[8] != 0); 56} 57 58package timelocal; 59 60sub cheat { 61 $year = $_[5]; 62 $month = $_[4]; 63 $guess = $^T; 64 @g = gmtime($guess); 65 $year += $YearFix if $year < $epoch[5]; 66 while ($diff = $year - $g[5]) { 67 $guess += $diff * (364 * $DAYS); 68 @g = gmtime($guess); 69 } 70 while ($diff = $month - $g[4]) { 71 $guess += $diff * (28 * $DAYS); 72 @g = gmtime($guess); 73 } 74 $g[3]--; 75 $guess -= $g[0] * $SEC + $g[1] * $MIN + $g[2] * $HR + $g[3] * $DAYS; 76 $cheat{$ym} = $guess; 77} 78