Upgrade to Time::Local 1.12_01
[p5sagit/p5-mst-13.2.git] / lib / Time / Local.pm
1 package Time::Local;
2
3 require Exporter;
4 use Carp;
5 use Config;
6 use strict;
7 use integer;
8
9 use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK );
10 $VERSION   = '1.12_01';
11 $VERSION   = eval $VERSION;
12 @ISA       = qw( Exporter );
13 @EXPORT    = qw( timegm timelocal );
14 @EXPORT_OK = qw( timegm_nocheck timelocal_nocheck );
15
16 my @MonthDays = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
17
18 # Determine breakpoint for rolling century
19 my $ThisYear    = ( localtime() )[5];
20 my $Breakpoint  = ( $ThisYear + 50 ) % 100;
21 my $NextCentury = $ThisYear - $ThisYear % 100;
22 $NextCentury += 100 if $Breakpoint < 50;
23 my $Century = $NextCentury - 100;
24 my $SecOff  = 0;
25
26 my ( %Options, %Cheat );
27
28 use constant SECS_PER_MINUTE => 60;
29 use constant SECS_PER_HOUR   => 3600;
30 use constant SECS_PER_DAY    => 86400;
31
32 my $MaxInt = ( ( 1 << ( 8 * $Config{intsize} - 2 ) ) -1 ) * 2 + 1;
33 my $MaxDay = int( ( $MaxInt - ( SECS_PER_DAY / 2 ) ) / SECS_PER_DAY ) - 1;
34
35 if ( $^O eq 'MacOS' ) {
36     # time_t is unsigned...
37     $MaxInt = ( 1 << ( 8 * $Config{intsize} ) ) - 1;
38 }
39 else {
40     $MaxInt = ( ( 1 << ( 8 * $Config{intsize} - 2 ) ) - 1 ) * 2 + 1;
41 }
42
43 # Determine the EPOC day for this machine
44 my $Epoc = 0;
45 if ( $^O eq 'vos' ) {
46     # work around posix-977 -- VOS doesn't handle dates in the range
47     # 1970-1980.
48     $Epoc = _daygm( 0, 0, 0, 1, 0, 70, 4, 0 );
49 }
50 elsif ( $^O eq 'MacOS' ) {
51     $MaxDay *=2 if $^O eq 'MacOS';  # time_t unsigned ... quick hack?
52     # MacOS time() is seconds since 1 Jan 1904, localtime
53     # so we need to calculate an offset to apply later
54     $Epoc = 693901;
55     $SecOff = timelocal( localtime(0)) - timelocal( gmtime(0) ) ;
56     $Epoc += _daygm( gmtime(0) );
57 }
58 else {
59     $Epoc = _daygm( gmtime(0) );
60 }
61
62 %Cheat = ();    # clear the cache as epoc has changed
63
64 sub _daygm {
65
66     # This is written in such a byzantine way in order to avoid
67     # lexical variables and sub calls, for speed
68     return $_[3] + (
69         $Cheat{ pack( 'ss', @_[ 4, 5 ] ) } ||= do {
70             my $month = ( $_[4] + 10 ) % 12;
71             my $year  = $_[5] + 1900 - $month / 10;
72
73             ( ( 365 * $year )
74               + ( $year / 4 )
75               - ( $year / 100 )
76               + ( $year / 400 )
77               + ( ( ( $month * 306 ) + 5 ) / 10 )
78             )
79             - $Epoc;
80         }
81     );
82 }
83
84 sub _timegm {
85     my $sec =
86         $SecOff + $_[0] + ( SECS_PER_MINUTE * $_[1] ) + ( SECS_PER_HOUR * $_[2] );
87
88     return $sec + ( SECS_PER_DAY * &_daygm );
89 }
90
91 sub timegm {
92     my ( $sec, $min, $hour, $mday, $month, $year ) = @_;
93
94     if ( $year >= 1000 ) {
95         $year -= 1900;
96     }
97     elsif ( $year < 100 and $year >= 0 ) {
98         $year += ( $year > $Breakpoint ) ? $Century : $NextCentury;
99     }
100
101     unless ( $Options{no_range_check} ) {
102         if ( abs($year) >= 0x7fff ) {
103             $year += 1900;
104             croak
105                 "Cannot handle date ($sec, $min, $hour, $mday, $month, *$year*)";
106         }
107
108         croak "Month '$month' out of range 0..11"
109             if $month > 11
110             or $month < 0;
111
112         my $md = $MonthDays[$month];
113         ++$md
114             unless $month != 1 or $year % 4 or !( $year % 400 );
115
116         croak "Day '$mday' out of range 1..$md"  if $mday > $md or $mday < 1;
117         croak "Hour '$hour' out of range 0..23"  if $hour > 23  or $hour < 0;
118         croak "Minute '$min' out of range 0..59" if $min > 59   or $min < 0;
119         croak "Second '$sec' out of range 0..59" if $sec > 59   or $sec < 0;
120     }
121
122     my $days = _daygm( undef, undef, undef, $mday, $month, $year );
123
124     unless ($Options{no_range_check} or abs($days) < $MaxDay) {
125         my $msg = '';
126         $msg .= "Day too big - $days > $MaxDay\n" if $days > $MaxDay;
127
128         $year += 1900;
129         $msg .=  "Cannot handle date ($sec, $min, $hour, $mday, $month, $year)";
130
131         croak $msg;
132     }
133
134     return $sec
135            + $SecOff
136            + ( SECS_PER_MINUTE * $min )
137            + ( SECS_PER_HOUR * $hour )
138            + ( SECS_PER_DAY * $days );
139 }
140
141 sub timegm_nocheck {
142     local $Options{no_range_check} = 1;
143     return &timegm;
144 }
145
146 sub timelocal {
147     my $ref_t = &timegm;
148     my $loc_t = _timegm( localtime($ref_t) );
149
150     # Is there a timezone offset from GMT or are we done?
151     my $zone_off = $ref_t - $loc_t
152         or return $loc_t;
153
154     # This hack is needed to always pick the first matching time
155     # during a DST change when time would otherwise be ambiguous
156     $zone_off -= SECS_PER_HOUR if $ref_t >= SECS_PER_HOUR;
157
158     # Adjust for timezone
159     $loc_t = $ref_t + $zone_off;
160
161     # Are we close to a DST change or are we done
162     my $dst_off = $ref_t - _timegm( localtime($loc_t) )
163         or return $loc_t;
164
165     # Adjust for DST change
166     $loc_t += $dst_off;
167
168     return $loc_t if $dst_off >= 0;
169
170     # for a negative offset from GMT, and if the original date
171     # was a non-extent gap in a forward DST jump, we should
172     # now have the wrong answer - undo the DST adjust;
173     my ( $s, $m, $h ) = localtime($loc_t);
174     $loc_t -= $dst_off if $s != $_[0] || $m != $_[1] || $h != $_[2];
175
176     return $loc_t;
177 }
178
179 sub timelocal_nocheck {
180     local $Options{no_range_check} = 1;
181     return &timelocal;
182 }
183
184 1;
185
186 __END__
187
188 =head1 NAME
189
190 Time::Local - efficiently compute time from local and GMT time
191
192 =head1 SYNOPSIS
193
194     $time = timelocal($sec,$min,$hour,$mday,$mon,$year);
195     $time = timegm($sec,$min,$hour,$mday,$mon,$year);
196
197 =head1 DESCRIPTION
198
199 These routines are the inverse of built-in perl functions localtime()
200 and gmtime().  They accept a date as a six-element array, and return
201 the corresponding time(2) value in seconds since the system epoch
202 (Midnight, January 1, 1970 GMT on Unix, for example).  This value can
203 be positive or negative, though POSIX only requires support for
204 positive values, so dates before the system's epoch may not work on
205 all operating systems.
206
207 It is worth drawing particular attention to the expected ranges for
208 the values provided.  The value for the day of the month is the actual
209 day (ie 1..31), while the month is the number of months since January
210 (0..11).  This is consistent with the values returned from localtime()
211 and gmtime().
212
213 The timelocal() and timegm() functions perform range checking on the
214 input $sec, $min, $hour, $mday, and $mon values by default.  If you
215 are confident that your data is good, you can explicitly import the
216 timelocal_nocheck() and timegm_nocheck() functions, which may provide
217 a small performance improvement.
218
219     use Time::Local 'timelocal_nocheck';
220
221     # The 365th day of 1999
222     print scalar localtime timelocal_nocheck 0,0,0,365,0,99;
223
224 Strictly speaking, the year should also be specified in a form
225 consistent with localtime(), i.e. the offset from 1900.  In order to
226 make the interpretation of the year easier for humans, however, who
227 are more accustomed to seeing years as two-digit or four-digit values,
228 the following conventions are followed:
229
230 =over 4
231
232 =item *
233
234 Years greater than 999 are interpreted as being the actual year,
235 rather than the offset from 1900.  Thus, 1964 would indicate the year
236 Martin Luther King won the Nobel prize, not the year 3864.
237
238 =item *
239
240 Years in the range 100..999 are interpreted as offset from 1900, 
241 so that 112 indicates 2012.  This rule also applies to years less than zero
242 (but see note below regarding date range).
243
244 =item *
245
246 Years in the range 0..99 are interpreted as shorthand for years in the
247 rolling "current century," defined as 50 years on either side of the
248 current year.  Thus, today, in 1999, 0 would refer to 2000, and 45 to
249 2045, but 55 would refer to 1955.  Twenty years from now, 55 would
250 instead refer to 2055.  This is messy, but matches the way people
251 currently think about two digit dates.  Whenever possible, use an
252 absolute four digit year instead.
253
254 =back
255
256 The scheme above allows interpretation of a wide range of dates,
257 particularly if 4-digit years are used.
258
259 Please note, however, that the range of dates that can be actually be
260 handled depends on the size of an integer (time_t) on a given
261 platform. Currently, this is 32 bits for most systems, yielding an
262 approximate range from Dec 1901 to Jan 2038.
263
264 Both timelocal() and timegm() croak if given dates outside the
265 supported range.
266
267 =head2 Ambiguous Local Times (DST)
268
269 Because of DST changes, there are many time zones where the same local
270 time occurs for two different GMT times on the same day.  For example,
271 in the "Europe/Paris" time zone, the local time of 2001-10-28 02:30:00
272 can represent either 2001-10-28 00:30:00 GMT, B<or> 2001-10-28
273 01:30:00 GMT.
274
275 When given an ambiguous local time, the timelocal() function should
276 always return the epoch for the I<earlier> of the two possible GMT
277 times.
278
279 =head2 Non-Existent Local Times (DST)
280
281 When a DST change causes a locale clock to skip one hour forward,
282 there will be an hour's worth of local times that don't exist.  Again,
283 for the "Europe/Paris" time zone, the local clock jumped from
284 2001-03-25 01:59:59 to 2001-03-25 03:00:00.
285
286 If the timelocal() function is given a non-existent local time, it
287 will simply return an epoch value for the time one hour later.
288
289 =head2 Negative Epoch Values
290
291 Negative epoch (time_t) values are not officially supported by the
292 POSIX standards, so this module's tests do not test them.  On some
293 systems, they are known not to work.  These include MacOS (pre-OSX)
294 and Win32.
295
296 On systems which do support negative epoch values, this module should
297 be able to cope with dates before the start of the epoch, down the
298 minimum value of time_t for the system.
299
300 =head1 IMPLEMENTATION
301
302 These routines are quite efficient and yet are always guaranteed to
303 agree with localtime() and gmtime().  We manage this by caching the
304 start times of any months we've seen before.  If we know the start
305 time of the month, we can always calculate any time within the month.
306 The start times are calculated using a mathematical formula. Unlike
307 other algorithms that do multiple calls to gmtime().
308
309 timelocal() is implemented using the same cache.  We just assume that
310 we're translating a GMT time, and then fudge it when we're done for
311 the timezone and daylight savings arguments.  Note that the timezone
312 is evaluated for each date because countries occasionally change their
313 official timezones.  Assuming that localtime() corrects for these
314 changes, this routine will also be correct.
315
316 =head1 BUGS
317
318 The whole scheme for interpreting two-digit years can be considered a
319 bug.
320
321 =head1 SUPPORT
322
323 Support for this module is provided via the datetime@perl.org email
324 list.  See http://lists.perl.org/ for more details.
325
326 Please submit bugs using the RT system at rt.cpan.org, or as a last
327 resort, to the datetime@perl.org list.
328
329 =head1 AUTHOR
330
331 This module is based on a Perl 4 library, timelocal.pl, that was
332 included with Perl 4.036, and was most likely written by Tom
333 Christiansen.
334
335 The current version was written by Graham Barr.
336
337 It is now being maintained separately from the Perl core by Dave
338 Rolsky, <autarch@urth.org>.
339
340 =cut
341