1898184e3Ssthenpackage Time::Local; 2898184e3Ssthen 3898184e3Ssthenuse strict; 4898184e3Ssthen 55759b3d2Safresh1use Carp (); 65759b3d2Safresh1use Exporter; 7898184e3Ssthen 8*5486feefSafresh1our $VERSION = '1.35'; 95759b3d2Safresh1 105759b3d2Safresh1use parent 'Exporter'; 115759b3d2Safresh1 125759b3d2Safresh1our @EXPORT = qw( timegm timelocal ); 13256a93a4Safresh1our @EXPORT_OK = qw( 14256a93a4Safresh1 timegm_modern 15256a93a4Safresh1 timelocal_modern 16256a93a4Safresh1 timegm_nocheck 17256a93a4Safresh1 timelocal_nocheck 18256a93a4Safresh1 timegm_posix 19256a93a4Safresh1 timelocal_posix 20256a93a4Safresh1); 21898184e3Ssthen 22898184e3Ssthenmy @MonthDays = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); 23898184e3Ssthen 24898184e3Ssthen# Determine breakpoint for rolling century 25898184e3Ssthenmy $ThisYear = ( localtime() )[5]; 26898184e3Ssthenmy $Breakpoint = ( $ThisYear + 50 ) % 100; 27898184e3Ssthenmy $NextCentury = $ThisYear - $ThisYear % 100; 28898184e3Ssthen$NextCentury += 100 if $Breakpoint < 50; 29898184e3Ssthenmy $Century = $NextCentury - 100; 30898184e3Ssthenmy $SecOff = 0; 31898184e3Ssthen 32898184e3Ssthenmy ( %Options, %Cheat ); 33898184e3Ssthen 34898184e3Ssthenuse constant SECS_PER_MINUTE => 60; 35898184e3Ssthenuse constant SECS_PER_HOUR => 3600; 36898184e3Ssthenuse constant SECS_PER_DAY => 86400; 37898184e3Ssthen 38898184e3Ssthenmy $MaxDay; 39898184e3Ssthenif ( $] < 5.012000 ) { 405759b3d2Safresh1 require Config; 415759b3d2Safresh1 ## no critic (Variables::ProhibitPackageVars) 425759b3d2Safresh1 43898184e3Ssthen my $MaxInt; 44898184e3Ssthen if ( $^O eq 'MacOS' ) { 455759b3d2Safresh1 46898184e3Ssthen # time_t is unsigned... 475759b3d2Safresh1 $MaxInt = ( 1 << ( 8 * $Config::Config{ivsize} ) ) 485759b3d2Safresh1 - 1; ## no critic qw(ProhibitPackageVars) 49898184e3Ssthen } 50898184e3Ssthen else { 515759b3d2Safresh1 $MaxInt 525759b3d2Safresh1 = ( ( 1 << ( 8 * $Config::Config{ivsize} - 2 ) ) - 1 ) * 2 535759b3d2Safresh1 + 1; ## no critic qw(ProhibitPackageVars) 54898184e3Ssthen } 55898184e3Ssthen 56898184e3Ssthen $MaxDay = int( ( $MaxInt - ( SECS_PER_DAY / 2 ) ) / SECS_PER_DAY ) - 1; 57898184e3Ssthen} 58898184e3Ssthenelse { 59898184e3Ssthen # recent localtime()'s limit is the year 2**31 60898184e3Ssthen $MaxDay = 365 * ( 2**31 ); 61*5486feefSafresh1 62*5486feefSafresh1 # On (some?) 32-bit platforms this overflows and we end up with a negative 63*5486feefSafresh1 # $MaxDay, which totally breaks this module. This is the old calculation 64*5486feefSafresh1 # we used from the days before Perl always had 64-bit time_t. 65*5486feefSafresh1 if ( $MaxDay < 0 ) { 66*5486feefSafresh1 require Config; 67*5486feefSafresh1 ## no critic (Variables::ProhibitPackageVars) 68*5486feefSafresh1 my $max_int 69*5486feefSafresh1 = ( ( 1 << ( 8 * $Config::Config{intsize} - 2 ) ) - 1 ) * 2 + 1; 70*5486feefSafresh1 $MaxDay 71*5486feefSafresh1 = int( ( $max_int - ( SECS_PER_DAY / 2 ) ) / SECS_PER_DAY ) - 1; 72*5486feefSafresh1 } 73898184e3Ssthen} 74898184e3Ssthen 75898184e3Ssthen# Determine the EPOC day for this machine 76898184e3Ssthenmy $Epoc = 0; 77898184e3Ssthenif ( $^O eq 'vos' ) { 785759b3d2Safresh1 79898184e3Ssthen # work around posix-977 -- VOS doesn't handle dates in the range 80898184e3Ssthen # 1970-1980. 81898184e3Ssthen $Epoc = _daygm( 0, 0, 0, 1, 0, 70, 4, 0 ); 82898184e3Ssthen} 83898184e3Ssthenelsif ( $^O eq 'MacOS' ) { 84f3efcd01Safresh1 $MaxDay *= 2; # time_t unsigned ... quick hack? 85898184e3Ssthen # MacOS time() is seconds since 1 Jan 1904, localtime 86898184e3Ssthen # so we need to calculate an offset to apply later 87898184e3Ssthen $Epoc = 693901; 88898184e3Ssthen $SecOff = timelocal( localtime(0) ) - timelocal( gmtime(0) ); 89898184e3Ssthen $Epoc += _daygm( gmtime(0) ); 90898184e3Ssthen} 91898184e3Ssthenelse { 92898184e3Ssthen $Epoc = _daygm( gmtime(0) ); 93898184e3Ssthen} 94898184e3Ssthen 95898184e3Ssthen%Cheat = (); # clear the cache as epoc has changed 96898184e3Ssthen 97898184e3Ssthensub _daygm { 98898184e3Ssthen 99898184e3Ssthen # This is written in such a byzantine way in order to avoid 100898184e3Ssthen # lexical variables and sub calls, for speed 101898184e3Ssthen return $_[3] + ( 102898184e3Ssthen $Cheat{ pack( 'ss', @_[ 4, 5 ] ) } ||= do { 103898184e3Ssthen my $month = ( $_[4] + 10 ) % 12; 104898184e3Ssthen my $year = $_[5] + 1900 - int( $month / 10 ); 105898184e3Ssthen 106898184e3Ssthen ( ( 365 * $year ) 107898184e3Ssthen + int( $year / 4 ) 108898184e3Ssthen - int( $year / 100 ) 109898184e3Ssthen + int( $year / 400 ) 110*5486feefSafresh1 + int( ( ( $month * 306 ) + 5 ) / 10 ) ) 111*5486feefSafresh1 - $Epoc; 112898184e3Ssthen } 113898184e3Ssthen ); 114898184e3Ssthen} 115898184e3Ssthen 116898184e3Ssthensub _timegm { 1175759b3d2Safresh1 my $sec 1185759b3d2Safresh1 = $SecOff + $_[0] 1195759b3d2Safresh1 + ( SECS_PER_MINUTE * $_[1] ) 1205759b3d2Safresh1 + ( SECS_PER_HOUR * $_[2] ); 121898184e3Ssthen 122898184e3Ssthen return $sec + ( SECS_PER_DAY * &_daygm ); 123898184e3Ssthen} 124898184e3Ssthen 125898184e3Ssthensub timegm { 126898184e3Ssthen my ( $sec, $min, $hour, $mday, $month, $year ) = @_; 127*5486feefSafresh1 my $subsec = $sec - int($sec); 128*5486feefSafresh1 $sec = int($sec); 129898184e3Ssthen 130f3efcd01Safresh1 if ( $Options{no_year_munging} ) { 131f3efcd01Safresh1 $year -= 1900; 132f3efcd01Safresh1 } 133256a93a4Safresh1 elsif ( !$Options{posix_year} ) { 134898184e3Ssthen if ( $year >= 1000 ) { 135898184e3Ssthen $year -= 1900; 136898184e3Ssthen } 137898184e3Ssthen elsif ( $year < 100 and $year >= 0 ) { 138898184e3Ssthen $year += ( $year > $Breakpoint ) ? $Century : $NextCentury; 139898184e3Ssthen } 140f3efcd01Safresh1 } 141898184e3Ssthen 142898184e3Ssthen unless ( $Options{no_range_check} ) { 1435759b3d2Safresh1 Carp::croak("Month '$month' out of range 0..11") 144898184e3Ssthen if $month > 11 145898184e3Ssthen or $month < 0; 146898184e3Ssthen 147898184e3Ssthen my $md = $MonthDays[$month]; 148898184e3Ssthen ++$md 149898184e3Ssthen if $month == 1 && _is_leap_year( $year + 1900 ); 150898184e3Ssthen 1515759b3d2Safresh1 Carp::croak("Day '$mday' out of range 1..$md") 1525759b3d2Safresh1 if $mday > $md or $mday < 1; 1535759b3d2Safresh1 Carp::croak("Hour '$hour' out of range 0..23") 1545759b3d2Safresh1 if $hour > 23 or $hour < 0; 1555759b3d2Safresh1 Carp::croak("Minute '$min' out of range 0..59") 1565759b3d2Safresh1 if $min > 59 or $min < 0; 1575759b3d2Safresh1 Carp::croak("Second '$sec' out of range 0..59") 1585759b3d2Safresh1 if $sec >= 60 or $sec < 0; 159898184e3Ssthen } 160898184e3Ssthen 161898184e3Ssthen my $days = _daygm( undef, undef, undef, $mday, $month, $year ); 162898184e3Ssthen 163*5486feefSafresh1 if ( abs($days) > $MaxDay && !$Options{no_range_check} ) { 164*5486feefSafresh1 my $msg = "Day too big - abs($days) > $MaxDay\n"; 165898184e3Ssthen 166898184e3Ssthen $year += 1900; 1675759b3d2Safresh1 $msg 1685759b3d2Safresh1 .= "Cannot handle date ($sec, $min, $hour, $mday, $month, $year)"; 169898184e3Ssthen 1705759b3d2Safresh1 Carp::croak($msg); 171898184e3Ssthen } 172898184e3Ssthen 173*5486feefSafresh1 # Adding in the $subsec value last seems to prevent floating point errors 174*5486feefSafresh1 # from creeping in. 175*5486feefSafresh1 return ( 176*5486feefSafresh1 ( 1775759b3d2Safresh1 $sec + $SecOff 178898184e3Ssthen + ( SECS_PER_MINUTE * $min ) 179898184e3Ssthen + ( SECS_PER_HOUR * $hour ) 180*5486feefSafresh1 + ( SECS_PER_DAY * $days ) 181*5486feefSafresh1 ) + $subsec 182*5486feefSafresh1 ); 183898184e3Ssthen} 184898184e3Ssthen 185898184e3Ssthensub _is_leap_year { 186898184e3Ssthen return 0 if $_[0] % 4; 187898184e3Ssthen return 1 if $_[0] % 100; 188898184e3Ssthen return 0 if $_[0] % 400; 189898184e3Ssthen 190898184e3Ssthen return 1; 191898184e3Ssthen} 192898184e3Ssthen 193898184e3Ssthensub timegm_nocheck { 194898184e3Ssthen local $Options{no_range_check} = 1; 195898184e3Ssthen return &timegm; 196898184e3Ssthen} 197898184e3Ssthen 198f3efcd01Safresh1sub timegm_modern { 199f3efcd01Safresh1 local $Options{no_year_munging} = 1; 200f3efcd01Safresh1 return &timegm; 201f3efcd01Safresh1} 202f3efcd01Safresh1 203256a93a4Safresh1sub timegm_posix { 204256a93a4Safresh1 local $Options{posix_year} = 1; 205256a93a4Safresh1 return &timegm; 206256a93a4Safresh1} 207256a93a4Safresh1 208898184e3Ssthensub timelocal { 209*5486feefSafresh1 my $sec = shift; 210*5486feefSafresh1 my $subsec = $sec - int($sec); 211*5486feefSafresh1 $sec = int($sec); 212*5486feefSafresh1 unshift @_, $sec; 213*5486feefSafresh1 214898184e3Ssthen my $ref_t = &timegm; 215898184e3Ssthen my $loc_for_ref_t = _timegm( localtime($ref_t) ); 216898184e3Ssthen 217898184e3Ssthen my $zone_off = $loc_for_ref_t - $ref_t 218*5486feefSafresh1 or return $loc_for_ref_t + $subsec; 219898184e3Ssthen 220898184e3Ssthen # Adjust for timezone 221898184e3Ssthen my $loc_t = $ref_t - $zone_off; 222898184e3Ssthen 223898184e3Ssthen # Are we close to a DST change or are we done 224898184e3Ssthen my $dst_off = $ref_t - _timegm( localtime($loc_t) ); 225898184e3Ssthen 226898184e3Ssthen # If this evaluates to true, it means that the value in $loc_t is 227898184e3Ssthen # the _second_ hour after a DST change where the local time moves 228898184e3Ssthen # backward. 2295759b3d2Safresh1 if ( 2305759b3d2Safresh1 !$dst_off 2315759b3d2Safresh1 && ( ( $ref_t - SECS_PER_HOUR ) 2325759b3d2Safresh1 - _timegm( localtime( $loc_t - SECS_PER_HOUR ) ) < 0 ) 233898184e3Ssthen ) { 234*5486feefSafresh1 return ( $loc_t - SECS_PER_HOUR ) + $subsec; 235898184e3Ssthen } 236898184e3Ssthen 237898184e3Ssthen # Adjust for DST change 238898184e3Ssthen $loc_t += $dst_off; 239898184e3Ssthen 240*5486feefSafresh1 return $loc_t + $subsec if $dst_off > 0; 241898184e3Ssthen 242256a93a4Safresh1 # If the original date was a non-existent gap in a forward DST jump, we 243256a93a4Safresh1 # should now have the wrong answer - undo the DST adjustment 244898184e3Ssthen my ( $s, $m, $h ) = localtime($loc_t); 245898184e3Ssthen $loc_t -= $dst_off if $s != $_[0] || $m != $_[1] || $h != $_[2]; 246898184e3Ssthen 247*5486feefSafresh1 return $loc_t + $subsec; 248898184e3Ssthen} 249898184e3Ssthen 250898184e3Ssthensub timelocal_nocheck { 251898184e3Ssthen local $Options{no_range_check} = 1; 252898184e3Ssthen return &timelocal; 253898184e3Ssthen} 254898184e3Ssthen 255f3efcd01Safresh1sub timelocal_modern { 256f3efcd01Safresh1 local $Options{no_year_munging} = 1; 257f3efcd01Safresh1 return &timelocal; 258f3efcd01Safresh1} 259f3efcd01Safresh1 260256a93a4Safresh1sub timelocal_posix { 261256a93a4Safresh1 local $Options{posix_year} = 1; 262256a93a4Safresh1 return &timelocal; 263256a93a4Safresh1} 264256a93a4Safresh1 265898184e3Ssthen1; 266898184e3Ssthen 2675759b3d2Safresh1# ABSTRACT: Efficiently compute time from local and GMT time 2685759b3d2Safresh1 269898184e3Ssthen__END__ 270898184e3Ssthen 2715759b3d2Safresh1=pod 2725759b3d2Safresh1 2735759b3d2Safresh1=encoding UTF-8 2745759b3d2Safresh1 275898184e3Ssthen=head1 NAME 276898184e3Ssthen 2775759b3d2Safresh1Time::Local - Efficiently compute time from local and GMT time 2785759b3d2Safresh1 2795759b3d2Safresh1=head1 VERSION 2805759b3d2Safresh1 281*5486feefSafresh1version 1.35 282898184e3Ssthen 283898184e3Ssthen=head1 SYNOPSIS 284898184e3Ssthen 285256a93a4Safresh1 use Time::Local qw( timelocal_posix timegm_posix ); 2865759b3d2Safresh1 287256a93a4Safresh1 my $time = timelocal_posix( $sec, $min, $hour, $mday, $mon, $year ); 288256a93a4Safresh1 my $time = timegm_posix( $sec, $min, $hour, $mday, $mon, $year ); 289898184e3Ssthen 290898184e3Ssthen=head1 DESCRIPTION 291898184e3Ssthen 2925759b3d2Safresh1This module provides functions that are the inverse of built-in perl functions 2935759b3d2Safresh1C<localtime()> and C<gmtime()>. They accept a date as a six-element array, and 2945759b3d2Safresh1return the corresponding C<time(2)> value in seconds since the system epoch 2955759b3d2Safresh1(Midnight, January 1, 1970 GMT on Unix, for example). This value can be 2965759b3d2Safresh1positive or negative, though POSIX only requires support for positive values, 2975759b3d2Safresh1so dates before the system's epoch may not work on all operating systems. 298898184e3Ssthen 2995759b3d2Safresh1It is worth drawing particular attention to the expected ranges for the values 3005759b3d2Safresh1provided. The value for the day of the month is the actual day (i.e. 1..31), 3015759b3d2Safresh1while the month is the number of months since January (0..11). This is 3025759b3d2Safresh1consistent with the values returned from C<localtime()> and C<gmtime()>. 303898184e3Ssthen 304898184e3Ssthen=head1 FUNCTIONS 305898184e3Ssthen 306256a93a4Safresh1=head2 C<timelocal_posix()> and C<timegm_posix()> 307256a93a4Safresh1 308*5486feefSafresh1I<Since version 1.30.> 309*5486feefSafresh1 310256a93a4Safresh1These functions are the exact inverse of Perl's built-in C<localtime> and 311256a93a4Safresh1C<gmtime> functions. That means that calling C<< timelocal_posix( 312256a93a4Safresh1localtime($value) ) >> will always give you the same C<$value> you started 313256a93a4Safresh1with. The same applies to C<< timegm_posix( gmtime($value) ) >>. 314256a93a4Safresh1 315256a93a4Safresh1The one exception is when the value returned from C<localtime()> represents an 316256a93a4Safresh1ambiguous local time because of a DST change. See the documentation below for 317256a93a4Safresh1more details. 318256a93a4Safresh1 319256a93a4Safresh1These functions expect the year value to be the number of years since 1900, 320256a93a4Safresh1which is what the C<localtime()> and C<gmtime()> built-ins returns. 321256a93a4Safresh1 322*5486feefSafresh1They perform range checking by default on the input C<$sec>, C<$min>, C<$hour>, 323*5486feefSafresh1C<$mday>, and C<$mon> values and will croak (using C<Carp::croak()>) if given a 324*5486feefSafresh1value outside the allowed ranges. 325256a93a4Safresh1 326256a93a4Safresh1While it would be nice to make this the default behavior, that would almost 327256a93a4Safresh1certainly break a lot of code, so you must explicitly import these functions 328256a93a4Safresh1and use them instead of the default C<timelocal()> and C<timegm()>. 329256a93a4Safresh1 330256a93a4Safresh1You are B<strongly> encouraged to use these functions in any new code which 331256a93a4Safresh1uses this module. It will almost certainly make your code's behavior less 332256a93a4Safresh1surprising. 333256a93a4Safresh1 334f3efcd01Safresh1=head2 C<timelocal_modern()> and C<timegm_modern()> 335f3efcd01Safresh1 336*5486feefSafresh1I<Since version 1.27.> 337*5486feefSafresh1 338f3efcd01Safresh1When C<Time::Local> was first written, it was a common practice to represent 339f3efcd01Safresh1years as a two-digit value like C<99> for C<1999> or C<1> for C<2001>. This 340f3efcd01Safresh1caused all sorts of problems (google "Y2K problem" if you're very young) and 341f3efcd01Safresh1developers eventually realized that this was a terrible idea. 342f3efcd01Safresh1 343f3efcd01Safresh1The default exports of C<timelocal()> and C<timegm()> do a complicated 344f3efcd01Safresh1calculation when given a year value less than 1000. This leads to surprising 345f3efcd01Safresh1results in many cases. See L</Year Value Interpretation> for details. 346f3efcd01Safresh1 347*5486feefSafresh1The C<time*_modern()> functions do not do this year munging and simply take the 348*5486feefSafresh1year value as provided. 349f3efcd01Safresh1 350*5486feefSafresh1They perform range checking by default on the input C<$sec>, C<$min>, C<$hour>, 351*5486feefSafresh1C<$mday>, and C<$mon> values and will croak (using C<Carp::croak()>) if given a 352*5486feefSafresh1value outside the allowed ranges. 353f3efcd01Safresh1 354898184e3Ssthen=head2 C<timelocal()> and C<timegm()> 355898184e3Ssthen 3565759b3d2Safresh1This module exports two functions by default, C<timelocal()> and C<timegm()>. 357898184e3Ssthen 358*5486feefSafresh1They perform range checking by default on the input C<$sec>, C<$min>, C<$hour>, 359*5486feefSafresh1C<$mday>, and C<$mon> values and will croak (using C<Carp::croak()>) if given a 360*5486feefSafresh1value outside the allowed ranges. 361256a93a4Safresh1 362*5486feefSafresh1B<Warning: The year value interpretation that these functions and their nocheck 363*5486feefSafresh1variants use will almost certainly lead to bugs in your code, if not now, then 364*5486feefSafresh1in the future. You are strongly discouraged from using these in new code, and 365*5486feefSafresh1you should convert old code to using either the C<*_posix> or C<*_modern> 366*5486feefSafresh1functions if possible.> 367898184e3Ssthen 368898184e3Ssthen=head2 C<timelocal_nocheck()> and C<timegm_nocheck()> 369898184e3Ssthen 370256a93a4Safresh1If you are working with data you know to be valid, you can use the "nocheck" 371256a93a4Safresh1variants, C<timelocal_nocheck()> and C<timegm_nocheck()>. These variants must 372256a93a4Safresh1be explicitly imported. 373898184e3Ssthen 374*5486feefSafresh1If you supply data which is not valid (month 27, second 1,000) the results will 375*5486feefSafresh1be unpredictable (so don't do that). 376898184e3Ssthen 377256a93a4Safresh1Note that my benchmarks show that this is just a 3% speed increase over the 378256a93a4Safresh1checked versions, so unless calling C<Time::Local> is the hottest spot in your 379256a93a4Safresh1application, using these nocheck variants is unlikely to have much impact on 380256a93a4Safresh1your application. 381256a93a4Safresh1 382898184e3Ssthen=head2 Year Value Interpretation 383898184e3Ssthen 384256a93a4Safresh1B<This does not apply to the C<*_posix> or C<*_modern> functions. Use those 385f3efcd01Safresh1exports if you want to ensure consistent behavior as your code ages.> 386f3efcd01Safresh1 3875759b3d2Safresh1Strictly speaking, the year should be specified in a form consistent with 3885759b3d2Safresh1C<localtime()>, i.e. the offset from 1900. In order to make the interpretation 389*5486feefSafresh1of the year easier for humans, however, who are more accustomed to seeing years 390*5486feefSafresh1as two-digit or four-digit values, the following conventions are followed: 391898184e3Ssthen 392898184e3Ssthen=over 4 393898184e3Ssthen 394898184e3Ssthen=item * 395898184e3Ssthen 3965759b3d2Safresh1Years greater than 999 are interpreted as being the actual year, rather than 397*5486feefSafresh1the offset from 1900. Thus, 1964 would indicate the year Martin Luther King won 398*5486feefSafresh1the Nobel prize, not the year 3864. 399898184e3Ssthen 400898184e3Ssthen=item * 401898184e3Ssthen 4025759b3d2Safresh1Years in the range 100..999 are interpreted as offset from 1900, so that 112 4035759b3d2Safresh1indicates 2012. This rule also applies to years less than zero (but see note 4045759b3d2Safresh1below regarding date range). 405898184e3Ssthen 406898184e3Ssthen=item * 407898184e3Ssthen 4085759b3d2Safresh1Years in the range 0..99 are interpreted as shorthand for years in the rolling 409*5486feefSafresh1"current century," defined as 50 years on either side of the current year. 410*5486feefSafresh1Thus, today, in 1999, 0 would refer to 2000, and 45 to 2045, but 55 would refer 411*5486feefSafresh1to 1955. Twenty years from now, 55 would instead refer to 2055. This is messy, 412*5486feefSafresh1but matches the way people currently think about two digit dates. Whenever 413*5486feefSafresh1possible, use an absolute four digit year instead. 414898184e3Ssthen 415898184e3Ssthen=back 416898184e3Ssthen 4175759b3d2Safresh1The scheme above allows interpretation of a wide range of dates, particularly 418256a93a4Safresh1if 4-digit years are used. But it also means that the behavior of your code 419256a93a4Safresh1changes as time passes, because the rolling "current century" changes each 420256a93a4Safresh1year. 421898184e3Ssthen 422898184e3Ssthen=head2 Limits of time_t 423898184e3Ssthen 4245759b3d2Safresh1On perl versions older than 5.12.0, the range of dates that can be actually be 4255759b3d2Safresh1handled depends on the size of C<time_t> (usually a signed integer) on the 4265759b3d2Safresh1given platform. Currently, this is 32 bits for most systems, yielding an 4275759b3d2Safresh1approximate range from Dec 1901 to Jan 2038. 428898184e3Ssthen 4295759b3d2Safresh1Both C<timelocal()> and C<timegm()> croak if given dates outside the supported 4305759b3d2Safresh1range. 431898184e3Ssthen 432f3efcd01Safresh1As of version 5.12.0, perl has stopped using the time implementation of the 433f3efcd01Safresh1operating system it's running on. Instead, it has its own implementation of 434f3efcd01Safresh1those routines with a safe range of at least +/- 2**52 (about 142 million 435f3efcd01Safresh1years) 436898184e3Ssthen 437898184e3Ssthen=head2 Ambiguous Local Times (DST) 438898184e3Ssthen 4395759b3d2Safresh1Because of DST changes, there are many time zones where the same local time 4405759b3d2Safresh1occurs for two different GMT times on the same day. For example, in the 4415759b3d2Safresh1"Europe/Paris" time zone, the local time of 2001-10-28 02:30:00 can represent 4425759b3d2Safresh1either 2001-10-28 00:30:00 GMT, B<or> 2001-10-28 01:30:00 GMT. 443898184e3Ssthen 444*5486feefSafresh1When given an ambiguous local time, the timelocal() function will always return 445*5486feefSafresh1the epoch for the I<earlier> of the two possible GMT times. 446898184e3Ssthen 447898184e3Ssthen=head2 Non-Existent Local Times (DST) 448898184e3Ssthen 449*5486feefSafresh1When a DST change causes a locale clock to skip one hour forward, there will be 450*5486feefSafresh1an hour's worth of local times that don't exist. Again, for the "Europe/Paris" 451*5486feefSafresh1time zone, the local clock jumped from 2001-03-25 01:59:59 to 2001-03-25 452*5486feefSafresh103:00:00. 453898184e3Ssthen 4545759b3d2Safresh1If the C<timelocal()> function is given a non-existent local time, it will 4555759b3d2Safresh1simply return an epoch value for the time one hour later. 456898184e3Ssthen 457898184e3Ssthen=head2 Negative Epoch Values 458898184e3Ssthen 4595759b3d2Safresh1On perl version 5.12.0 and newer, negative epoch values are fully supported. 460898184e3Ssthen 4615759b3d2Safresh1On older versions of perl, negative epoch (C<time_t>) values, which are not 4625759b3d2Safresh1officially supported by the POSIX standards, are known not to work on some 4635759b3d2Safresh1systems. These include MacOS (pre-OSX) and Win32. 464898184e3Ssthen 4655759b3d2Safresh1On systems which do support negative epoch values, this module should be able 4665759b3d2Safresh1to cope with dates before the start of the epoch, down the minimum value of 4675759b3d2Safresh1time_t for the system. 468898184e3Ssthen 469898184e3Ssthen=head1 IMPLEMENTATION 470898184e3Ssthen 4715759b3d2Safresh1These routines are quite efficient and yet are always guaranteed to agree with 4725759b3d2Safresh1C<localtime()> and C<gmtime()>. We manage this by caching the start times of 4735759b3d2Safresh1any months we've seen before. If we know the start time of the month, we can 4745759b3d2Safresh1always calculate any time within the month. The start times are calculated 475*5486feefSafresh1using a mathematical formula. Unlike other algorithms that do multiple calls to 476*5486feefSafresh1C<gmtime()>. 477898184e3Ssthen 478*5486feefSafresh1The C<timelocal()> function is implemented using the same cache. We just assume 479*5486feefSafresh1that we're translating a GMT time, and then fudge it when we're done for the 480*5486feefSafresh1timezone and daylight savings arguments. Note that the timezone is evaluated 481*5486feefSafresh1for each date because countries occasionally change their official timezones. 482*5486feefSafresh1Assuming that C<localtime()> corrects for these changes, this routine will also 483*5486feefSafresh1be correct. 484898184e3Ssthen 4855759b3d2Safresh1=head1 AUTHORS EMERITUS 486898184e3Ssthen 487*5486feefSafresh1This module is based on a Perl 4 library, timelocal.pl, that was included with 488*5486feefSafresh1Perl 4.036, and was most likely written by Tom Christiansen. 489898184e3Ssthen 490898184e3SsthenThe current version was written by Graham Barr. 491898184e3Ssthen 4925759b3d2Safresh1=head1 BUGS 4935759b3d2Safresh1 4945759b3d2Safresh1The whole scheme for interpreting two-digit years can be considered a bug. 4955759b3d2Safresh1 496f3efcd01Safresh1Bugs may be submitted at L<https://github.com/houseabsolute/Time-Local/issues>. 4975759b3d2Safresh1 4985759b3d2Safresh1There is a mailing list available for users of this distribution, 4995759b3d2Safresh1L<mailto:datetime@perl.org>. 5005759b3d2Safresh1 501f3efcd01Safresh1=head1 SOURCE 502f3efcd01Safresh1 503f3efcd01Safresh1The source code repository for Time-Local can be found at L<https://github.com/houseabsolute/Time-Local>. 504f3efcd01Safresh1 5055759b3d2Safresh1=head1 AUTHOR 5065759b3d2Safresh1 5075759b3d2Safresh1Dave Rolsky <autarch@urth.org> 5085759b3d2Safresh1 5095759b3d2Safresh1=head1 CONTRIBUTORS 5105759b3d2Safresh1 511*5486feefSafresh1=for stopwords Florian Ragwitz Gregory Oschwald J. Nick Koston Tom Wyant Unknown 5125759b3d2Safresh1 5135759b3d2Safresh1=over 4 5145759b3d2Safresh1 5155759b3d2Safresh1=item * 5165759b3d2Safresh1 5175759b3d2Safresh1Florian Ragwitz <rafl@debian.org> 5185759b3d2Safresh1 5195759b3d2Safresh1=item * 5205759b3d2Safresh1 521*5486feefSafresh1Gregory Oschwald <oschwald@gmail.com> 522*5486feefSafresh1 523*5486feefSafresh1=item * 524*5486feefSafresh1 5255759b3d2Safresh1J. Nick Koston <nick@cpanel.net> 5265759b3d2Safresh1 5275759b3d2Safresh1=item * 5285759b3d2Safresh1 529*5486feefSafresh1Tom Wyant <wyant@cpan.org> 530*5486feefSafresh1 531*5486feefSafresh1=item * 532*5486feefSafresh1 5335759b3d2Safresh1Unknown <unknown@example.com> 5345759b3d2Safresh1 5355759b3d2Safresh1=back 5365759b3d2Safresh1 5375759b3d2Safresh1=head1 COPYRIGHT AND LICENSE 5385759b3d2Safresh1 539*5486feefSafresh1This software is copyright (c) 1997 - 2023 by Graham Barr & Dave Rolsky. 5405759b3d2Safresh1 5415759b3d2Safresh1This is free software; you can redistribute it and/or modify it under 5425759b3d2Safresh1the same terms as the Perl 5 programming language system itself. 543898184e3Ssthen 544f3efcd01Safresh1The full text of the license can be found in the 545f3efcd01Safresh1F<LICENSE> file included with this distribution. 546f3efcd01Safresh1 547898184e3Ssthen=cut 548