integrate mainline changes
[p5sagit/p5-mst-13.2.git] / lib / Time / Local.pm
CommitLineData
a0d0e21e 1package Time::Local;
2require 5.000;
3require Exporter;
4use Carp;
5
6e7c9e4d 6@ISA = qw( Exporter );
7@EXPORT = qw( timegm timelocal );
1d7c1841 8@EXPORT_OK = qw( timegm_nocheck timelocal_nocheck );
a0d0e21e 9
06ef4121 10# Set up constants
16bb4654 11 $SEC = 1;
12 $MIN = 60 * $SEC;
13 $HR = 60 * $MIN;
14 $DAY = 24 * $HR;
06ef4121 15# Determine breakpoint for rolling century
16 my $thisYear = (localtime())[5];
17 $nextCentury = int($thisYear / 100) * 100;
18 $breakpoint = ($thisYear + 50) % 100;
19 $nextCentury += 100 if $breakpoint < 50;
9bb8015a 20
1d7c1841 21my %options;
22
9bb8015a 23sub timegm {
06ef4121 24 my (@date) = @_;
25 if ($date[5] > 999) {
26 $date[5] -= 1900;
27 }
28 elsif ($date[5] >= 0 && $date[5] < 100) {
29 $date[5] -= 100 if $date[5] > $breakpoint;
30 $date[5] += $nextCentury;
31 }
32 $ym = pack(C2, @date[5,4]);
33 $cheat = $cheat{$ym} || &cheat(@date);
34 $cheat
35 + $date[0] * $SEC
36 + $date[1] * $MIN
37 + $date[2] * $HR
38 + ($date[3]-1) * $DAY;
9bb8015a 39}
40
1d7c1841 41sub timegm_nocheck {
42 local $options{no_range_check} = 1;
43 &timegm;
44}
45
9bb8015a 46sub timelocal {
47 my $t = &timegm;
84902520 48 my $tt = $t;
9bb8015a 49
50 my (@lt) = localtime($t);
51 my (@gt) = gmtime($t);
84902520 52 if ($t < $DAY and ($lt[5] >= 70 or $gt[5] >= 70 )) {
06ef4121 53 # Wrap error, too early a date
54 # Try a safer date
e85ca32b 55 $tt += $DAY;
06ef4121 56 @lt = localtime($tt);
57 @gt = gmtime($tt);
84902520 58 }
a0d0e21e 59
9bb8015a 60 my $tzsec = ($gt[1] - $lt[1]) * $MIN + ($gt[2] - $lt[2]) * $HR;
16bb4654 61
16bb4654 62 if($lt[5] > $gt[5]) {
63 $tzsec -= $DAY;
64 }
65 elsif($gt[5] > $lt[5]) {
66 $tzsec += $DAY;
67 }
68 else {
69 $tzsec += ($gt[7] - $lt[7]) * $DAY;
70 }
71
9bb8015a 72 $tzsec += $HR if($lt[8]);
73
74 $time = $t + $tzsec;
84902520 75 @test = localtime($time + ($tt - $t));
a0d0e21e 76 $time -= $HR if $test[2] != $_[2];
77 $time;
78}
79
1d7c1841 80sub timelocal_nocheck {
81 local $options{no_range_check} = 1;
82 &timelocal;
83}
84
a0d0e21e 85sub cheat {
86 $year = $_[5];
87 $month = $_[4];
1d7c1841 88 unless ($options{no_range_check}) {
6e7c9e4d 89 croak "Month '$month' out of range 0..11" if $month > 11 || $month < 0;
90 croak "Day '$_[3]' out of range 1..31" if $_[3] > 31 || $_[3] < 1;
91 croak "Hour '$_[2]' out of range 0..23" if $_[2] > 23 || $_[2] < 0;
92 croak "Minute '$_[1]' out of range 0..59" if $_[1] > 59 || $_[1] < 0;
93 croak "Second '$_[0]' out of range 0..59" if $_[0] > 59 || $_[0] < 0;
94 }
a0d0e21e 95 $guess = $^T;
96 @g = gmtime($guess);
a0d0e21e 97 $lastguess = "";
390badbd 98 $counter = 0;
a0d0e21e 99 while ($diff = $year - $g[5]) {
390badbd 100 croak "Can't handle date (".join(", ",@_).")" if ++$counter > 255;
16bb4654 101 $guess += $diff * (363 * $DAY);
a0d0e21e 102 @g = gmtime($guess);
103 if (($thisguess = "@g") eq $lastguess){
06ef4121 104 croak "Can't handle date (".join(", ",@_).")";
105 #date beyond this machine's integer limit
a0d0e21e 106 }
107 $lastguess = $thisguess;
108 }
109 while ($diff = $month - $g[4]) {
390badbd 110 croak "Can't handle date (".join(", ",@_).")" if ++$counter > 255;
16bb4654 111 $guess += $diff * (27 * $DAY);
a0d0e21e 112 @g = gmtime($guess);
113 if (($thisguess = "@g") eq $lastguess){
06ef4121 114 croak "Can't handle date (".join(", ",@_).")";
115 #date beyond this machine's integer limit
a0d0e21e 116 }
117 $lastguess = $thisguess;
118 }
119 @gfake = gmtime($guess-1); #still being sceptic
120 if ("@gfake" eq $lastguess){
06ef4121 121 croak "Can't handle date (".join(", ",@_).")";
122 #date beyond this machine's integer limit
a0d0e21e 123 }
124 $g[3]--;
16bb4654 125 $guess -= $g[0] * $SEC + $g[1] * $MIN + $g[2] * $HR + $g[3] * $DAY;
a0d0e21e 126 $cheat{$ym} = $guess;
127}
128
1291;
06ef4121 130
131__END__
132
133=head1 NAME
134
135Time::Local - efficiently compute time from local and GMT time
136
137=head1 SYNOPSIS
138
139 $time = timelocal($sec,$min,$hours,$mday,$mon,$year);
140 $time = timegm($sec,$min,$hours,$mday,$mon,$year);
141
142=head1 DESCRIPTION
143
144These routines are the inverse of built-in perl fuctions localtime()
145and gmtime(). They accept a date as a six-element array, and return
146the corresponding time(2) value in seconds since the Epoch (Midnight,
147January 1, 1970). This value can be positive or negative.
148
149It is worth drawing particular attention to the expected ranges for
150the values provided. While the day of the month is expected to be in
151the range 1..31, the month should be in the range 0..11.
152This is consistent with the values returned from localtime() and gmtime().
153
1d7c1841 154The timelocal() and timegm() functions perform range checking on the
155input $sec, $min, $hours, $mday, and $mon values by default. If you'd
156rather they didn't, you can explicitly import the timelocal_nocheck()
157and timegm_nocheck() functions.
6e7c9e4d 158
1d7c1841 159 use Time::Local 'timelocal_nocheck';
160
161 {
162 # The 365th day of 1999
163 print scalar localtime timelocal_nocheck 0,0,0,365,0,99;
6e7c9e4d 164
1d7c1841 165 # The twenty thousandth day since 1970
166 print scalar localtime timelocal_nocheck 0,0,0,20000,0,70;
6e7c9e4d 167
1d7c1841 168 # And even the 10,000,000th second since 1999!
169 print scalar localtime timelocal_nocheck 10000000,0,0,1,0,99;
170 }
6e7c9e4d 171
1d7c1841 172Your mileage may vary when trying these with minutes and hours,
6e7c9e4d 173and it doesn't work at all for months.
174
06ef4121 175Strictly speaking, the year should also be specified in a form consistent
176with localtime(), i.e. the offset from 1900.
177In order to make the interpretation of the year easier for humans,
178however, who are more accustomed to seeing years as two-digit or four-digit
179values, the following conventions are followed:
180
181=over 4
182
183=item *
184
185Years greater than 999 are interpreted as being the actual year,
186rather than the offset from 1900. Thus, 1963 would indicate the year
90ca0aaa 187Martin Luther King won the Nobel prize, not the year 2863.
06ef4121 188
189=item *
190
191Years in the range 100..999 are interpreted as offset from 1900,
192so that 112 indicates 2012. This rule also applies to years less than zero
193(but see note below regarding date range).
194
195=item *
196
197Years in the range 0..99 are interpreted as shorthand for years in the
198rolling "current century," defined as 50 years on either side of the current
199year. Thus, today, in 1999, 0 would refer to 2000, and 45 to 2045,
200but 55 would refer to 1955. Twenty years from now, 55 would instead refer
201to 2055. This is messy, but matches the way people currently think about
202two digit dates. Whenever possible, use an absolute four digit year instead.
203
204=back
205
206The scheme above allows interpretation of a wide range of dates, particularly
207if 4-digit years are used.
90ca0aaa 208
06ef4121 209Please note, however, that the range of dates that can be actually be handled
210depends on the size of an integer (time_t) on a given platform.
211Currently, this is 32 bits for most systems, yielding an approximate range
212from Dec 1901 to Jan 2038.
213
214Both timelocal() and timegm() croak if given dates outside the supported
215range.
216
217=head1 IMPLEMENTATION
218
219These routines are quite efficient and yet are always guaranteed to agree
220with localtime() and gmtime(). We manage this by caching the start times
221of any months we've seen before. If we know the start time of the month,
222we can always calculate any time within the month. The start times
223themselves are guessed by successive approximation starting at the
224current time, since most dates seen in practice are close to the
225current date. Unlike algorithms that do a binary search (calling gmtime
226once for each bit of the time value, resulting in 32 calls), this algorithm
227calls it at most 6 times, and usually only once or twice. If you hit
228the month cache, of course, it doesn't call it at all.
229
230timelocal() is implemented using the same cache. We just assume that we're
231translating a GMT time, and then fudge it when we're done for the timezone
232and daylight savings arguments. Note that the timezone is evaluated for
233each date because countries occasionally change their official timezones.
234Assuming that localtime() corrects for these changes, this routine will
235also be correct. The daylight savings offset is currently assumed
236to be one hour.
237
238=head1 BUGS
239
240The whole scheme for interpreting two-digit years can be considered a bug.
241
242Note that the cache currently handles only years from 1900 through 2155.
243
244The proclivity to croak() is probably a bug.
245
246=cut