timelocal.pl revision 54359
1193323Sed;# timelocal.pl 2193323Sed;# 3193323Sed;# Usage: 4193323Sed;# $time = timelocal($sec,$min,$hours,$mday,$mon,$year,$junk,$junk,$isdst); 5193323Sed;# $time = timegm($sec,$min,$hours,$mday,$mon,$year); 6193323Sed 7193323Sed;# These routines are quite efficient and yet are always guaranteed to agree 8193323Sed;# with localtime() and gmtime(). We manage this by caching the start times 9193323Sed;# of any months we've seen before. If we know the start time of the month, 10193323Sed;# we can always calculate any time within the month. The start times 11193323Sed;# themselves are guessed by successive approximation starting at the 12193323Sed;# current time, since most dates seen in practice are close to the 13193323Sed;# current date. Unlike algorithms that do a binary search (calling gmtime 14193323Sed;# once for each bit of the time value, resulting in 32 calls), this algorithm 15193323Sed;# calls it at most 6 times, and usually only once or twice. If you hit 16249423Sdim;# the month cache, of course, it doesn't call it at all. 17218893Sdim 18263508Sdim;# timelocal is implemented using the same cache. We just assume that we're 19249423Sdim;# translating a GMT time, and then fudge it when we're done for the timezone 20249423Sdim;# and daylight savings arguments. The timezone is determined by examining 21249423Sdim;# the result of localtime(0) when the package is initialized. The daylight 22249423Sdim;# savings offset is currently assumed to be one hour. 23249423Sdim 24249423SdimCONFIG: { 25249423Sdim package timelocal; 26249423Sdim 27249423Sdim @epoch = localtime(0); 28234353Sdim $tzmin = $epoch[2] * 60 + $epoch[1]; # minutes east of GMT 29193323Sed if ($tzmin > 0) { 30193323Sed $tzmin = 24 * 60 - $tzmin; # minutes west of GMT 31218893Sdim $tzmin -= 24 * 60 if $epoch[5] == 70; # account for the date line 32193323Sed } 33193323Sed 34218893Sdim $SEC = 1; 35193323Sed $MIN = 60 * $SEC; 36218893Sdim $HR = 60 * $MIN; 37218893Sdim $DAYS = 24 * $HR; 38218893Sdim $YearFix = ((gmtime(946684800))[5] == 100) ? 100 : 0; 39218893Sdim} 40243830Sdim 41218893Sdimsub timegm { 42218893Sdim package timelocal; 43263508Sdim 44263508Sdim $ym = pack(C2, @_[5,4]); 45218893Sdim $cheat = $cheat{$ym} || &cheat; 46218893Sdim $cheat + $_[0] * $SEC + $_[1] * $MIN + $_[2] * $HR + ($_[3]-1) * $DAYS; 47234353Sdim} 48234353Sdim 49234353Sdimsub timelocal { 50243830Sdim package timelocal; 51234353Sdim 52234353Sdim $ym = pack(C2, @_[5,4]); 53234353Sdim $cheat = $cheat{$ym} || &cheat; 54234353Sdim $cheat + $_[0] * $SEC + $_[1] * $MIN + $_[2] * $HR + ($_[3]-1) * $DAYS 55234353Sdim + $tzmin * $MIN - 60 * 60 * ($_[8] != 0); 56234353Sdim} 57234353Sdim 58234353Sdimpackage timelocal; 59234353Sdim 60234353Sdimsub cheat { 61234353Sdim $year = $_[5]; 62249423Sdim $month = $_[4]; 63234353Sdim $guess = $^T; 64234353Sdim @g = gmtime($guess); 65234353Sdim $year += $YearFix if $year < $epoch[5]; 66234353Sdim while ($diff = $year - $g[5]) { 67234353Sdim $guess += $diff * (364 * $DAYS); 68234353Sdim @g = gmtime($guess); 69234353Sdim } 70234353Sdim while ($diff = $month - $g[4]) { 71234353Sdim $guess += $diff * (28 * $DAYS); 72234353Sdim @g = gmtime($guess); 73234353Sdim } 74234353Sdim $g[3]--; 75234353Sdim $guess -= $g[0] * $SEC + $g[1] * $MIN + $g[2] * $HR + $g[3] * $DAYS; 76234353Sdim $cheat{$ym} = $guess; 77234353Sdim} 78234353Sdim