1package Time::Local; 2 3use strict; 4 5use Carp (); 6use Exporter; 7 8our $VERSION = '1.35'; 9 10use parent 'Exporter'; 11 12our @EXPORT = qw( timegm timelocal ); 13our @EXPORT_OK = qw( 14 timegm_modern 15 timelocal_modern 16 timegm_nocheck 17 timelocal_nocheck 18 timegm_posix 19 timelocal_posix 20); 21 22my @MonthDays = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); 23 24# Determine breakpoint for rolling century 25my $ThisYear = ( localtime() )[5]; 26my $Breakpoint = ( $ThisYear + 50 ) % 100; 27my $NextCentury = $ThisYear - $ThisYear % 100; 28$NextCentury += 100 if $Breakpoint < 50; 29my $Century = $NextCentury - 100; 30my $SecOff = 0; 31 32my ( %Options, %Cheat ); 33 34use constant SECS_PER_MINUTE => 60; 35use constant SECS_PER_HOUR => 3600; 36use constant SECS_PER_DAY => 86400; 37 38my $MaxDay; 39if ( $] < 5.012000 ) { 40 require Config; 41 ## no critic (Variables::ProhibitPackageVars) 42 43 my $MaxInt; 44 if ( $^O eq 'MacOS' ) { 45 46 # time_t is unsigned... 47 $MaxInt = ( 1 << ( 8 * $Config::Config{ivsize} ) ) 48 - 1; ## no critic qw(ProhibitPackageVars) 49 } 50 else { 51 $MaxInt 52 = ( ( 1 << ( 8 * $Config::Config{ivsize} - 2 ) ) - 1 ) * 2 53 + 1; ## no critic qw(ProhibitPackageVars) 54 } 55 56 $MaxDay = int( ( $MaxInt - ( SECS_PER_DAY / 2 ) ) / SECS_PER_DAY ) - 1; 57} 58else { 59 # recent localtime()'s limit is the year 2**31 60 $MaxDay = 365 * ( 2**31 ); 61 62 # On (some?) 32-bit platforms this overflows and we end up with a negative 63 # $MaxDay, which totally breaks this module. This is the old calculation 64 # we used from the days before Perl always had 64-bit time_t. 65 if ( $MaxDay < 0 ) { 66 require Config; 67 ## no critic (Variables::ProhibitPackageVars) 68 my $max_int 69 = ( ( 1 << ( 8 * $Config::Config{intsize} - 2 ) ) - 1 ) * 2 + 1; 70 $MaxDay 71 = int( ( $max_int - ( SECS_PER_DAY / 2 ) ) / SECS_PER_DAY ) - 1; 72 } 73} 74 75# Determine the EPOC day for this machine 76my $Epoc = 0; 77if ( $^O eq 'vos' ) { 78 79 # work around posix-977 -- VOS doesn't handle dates in the range 80 # 1970-1980. 81 $Epoc = _daygm( 0, 0, 0, 1, 0, 70, 4, 0 ); 82} 83elsif ( $^O eq 'MacOS' ) { 84 $MaxDay *= 2; # time_t unsigned ... quick hack? 85 # MacOS time() is seconds since 1 Jan 1904, localtime 86 # so we need to calculate an offset to apply later 87 $Epoc = 693901; 88 $SecOff = timelocal( localtime(0) ) - timelocal( gmtime(0) ); 89 $Epoc += _daygm( gmtime(0) ); 90} 91else { 92 $Epoc = _daygm( gmtime(0) ); 93} 94 95%Cheat = (); # clear the cache as epoc has changed 96 97sub _daygm { 98 99 # This is written in such a byzantine way in order to avoid 100 # lexical variables and sub calls, for speed 101 return $_[3] + ( 102 $Cheat{ pack( 'ss', @_[ 4, 5 ] ) } ||= do { 103 my $month = ( $_[4] + 10 ) % 12; 104 my $year = $_[5] + 1900 - int( $month / 10 ); 105 106 ( ( 365 * $year ) 107 + int( $year / 4 ) 108 - int( $year / 100 ) 109 + int( $year / 400 ) 110 + int( ( ( $month * 306 ) + 5 ) / 10 ) ) 111 - $Epoc; 112 } 113 ); 114} 115 116sub _timegm { 117 my $sec 118 = $SecOff + $_[0] 119 + ( SECS_PER_MINUTE * $_[1] ) 120 + ( SECS_PER_HOUR * $_[2] ); 121 122 return $sec + ( SECS_PER_DAY * &_daygm ); 123} 124 125sub timegm { 126 my ( $sec, $min, $hour, $mday, $month, $year ) = @_; 127 my $subsec = $sec - int($sec); 128 $sec = int($sec); 129 130 if ( $Options{no_year_munging} ) { 131 $year -= 1900; 132 } 133 elsif ( !$Options{posix_year} ) { 134 if ( $year >= 1000 ) { 135 $year -= 1900; 136 } 137 elsif ( $year < 100 and $year >= 0 ) { 138 $year += ( $year > $Breakpoint ) ? $Century : $NextCentury; 139 } 140 } 141 142 unless ( $Options{no_range_check} ) { 143 Carp::croak("Month '$month' out of range 0..11") 144 if $month > 11 145 or $month < 0; 146 147 my $md = $MonthDays[$month]; 148 ++$md 149 if $month == 1 && _is_leap_year( $year + 1900 ); 150 151 Carp::croak("Day '$mday' out of range 1..$md") 152 if $mday > $md or $mday < 1; 153 Carp::croak("Hour '$hour' out of range 0..23") 154 if $hour > 23 or $hour < 0; 155 Carp::croak("Minute '$min' out of range 0..59") 156 if $min > 59 or $min < 0; 157 Carp::croak("Second '$sec' out of range 0..59") 158 if $sec >= 60 or $sec < 0; 159 } 160 161 my $days = _daygm( undef, undef, undef, $mday, $month, $year ); 162 163 if ( abs($days) > $MaxDay && !$Options{no_range_check} ) { 164 my $msg = "Day too big - abs($days) > $MaxDay\n"; 165 166 $year += 1900; 167 $msg 168 .= "Cannot handle date ($sec, $min, $hour, $mday, $month, $year)"; 169 170 Carp::croak($msg); 171 } 172 173 # Adding in the $subsec value last seems to prevent floating point errors 174 # from creeping in. 175 return ( 176 ( 177 $sec + $SecOff 178 + ( SECS_PER_MINUTE * $min ) 179 + ( SECS_PER_HOUR * $hour ) 180 + ( SECS_PER_DAY * $days ) 181 ) + $subsec 182 ); 183} 184 185sub _is_leap_year { 186 return 0 if $_[0] % 4; 187 return 1 if $_[0] % 100; 188 return 0 if $_[0] % 400; 189 190 return 1; 191} 192 193sub timegm_nocheck { 194 local $Options{no_range_check} = 1; 195 return &timegm; 196} 197 198sub timegm_modern { 199 local $Options{no_year_munging} = 1; 200 return &timegm; 201} 202 203sub timegm_posix { 204 local $Options{posix_year} = 1; 205 return &timegm; 206} 207 208sub timelocal { 209 my $sec = shift; 210 my $subsec = $sec - int($sec); 211 $sec = int($sec); 212 unshift @_, $sec; 213 214 my $ref_t = &timegm; 215 my $loc_for_ref_t = _timegm( localtime($ref_t) ); 216 217 my $zone_off = $loc_for_ref_t - $ref_t 218 or return $loc_for_ref_t + $subsec; 219 220 # Adjust for timezone 221 my $loc_t = $ref_t - $zone_off; 222 223 # Are we close to a DST change or are we done 224 my $dst_off = $ref_t - _timegm( localtime($loc_t) ); 225 226 # If this evaluates to true, it means that the value in $loc_t is 227 # the _second_ hour after a DST change where the local time moves 228 # backward. 229 if ( 230 !$dst_off 231 && ( ( $ref_t - SECS_PER_HOUR ) 232 - _timegm( localtime( $loc_t - SECS_PER_HOUR ) ) < 0 ) 233 ) { 234 return ( $loc_t - SECS_PER_HOUR ) + $subsec; 235 } 236 237 # Adjust for DST change 238 $loc_t += $dst_off; 239 240 return $loc_t + $subsec if $dst_off > 0; 241 242 # If the original date was a non-existent gap in a forward DST jump, we 243 # should now have the wrong answer - undo the DST adjustment 244 my ( $s, $m, $h ) = localtime($loc_t); 245 $loc_t -= $dst_off if $s != $_[0] || $m != $_[1] || $h != $_[2]; 246 247 return $loc_t + $subsec; 248} 249 250sub timelocal_nocheck { 251 local $Options{no_range_check} = 1; 252 return &timelocal; 253} 254 255sub timelocal_modern { 256 local $Options{no_year_munging} = 1; 257 return &timelocal; 258} 259 260sub timelocal_posix { 261 local $Options{posix_year} = 1; 262 return &timelocal; 263} 264 2651; 266 267# ABSTRACT: Efficiently compute time from local and GMT time 268 269__END__ 270 271=pod 272 273=encoding UTF-8 274 275=head1 NAME 276 277Time::Local - Efficiently compute time from local and GMT time 278 279=head1 VERSION 280 281version 1.35 282 283=head1 SYNOPSIS 284 285 use Time::Local qw( timelocal_posix timegm_posix ); 286 287 my $time = timelocal_posix( $sec, $min, $hour, $mday, $mon, $year ); 288 my $time = timegm_posix( $sec, $min, $hour, $mday, $mon, $year ); 289 290=head1 DESCRIPTION 291 292This module provides functions that are the inverse of built-in perl functions 293C<localtime()> and C<gmtime()>. They accept a date as a six-element array, and 294return the corresponding C<time(2)> value in seconds since the system epoch 295(Midnight, January 1, 1970 GMT on Unix, for example). This value can be 296positive or negative, though POSIX only requires support for positive values, 297so dates before the system's epoch may not work on all operating systems. 298 299It is worth drawing particular attention to the expected ranges for the values 300provided. The value for the day of the month is the actual day (i.e. 1..31), 301while the month is the number of months since January (0..11). This is 302consistent with the values returned from C<localtime()> and C<gmtime()>. 303 304=head1 FUNCTIONS 305 306=head2 C<timelocal_posix()> and C<timegm_posix()> 307 308I<Since version 1.30.> 309 310These functions are the exact inverse of Perl's built-in C<localtime> and 311C<gmtime> functions. That means that calling C<< timelocal_posix( 312localtime($value) ) >> will always give you the same C<$value> you started 313with. The same applies to C<< timegm_posix( gmtime($value) ) >>. 314 315The one exception is when the value returned from C<localtime()> represents an 316ambiguous local time because of a DST change. See the documentation below for 317more details. 318 319These functions expect the year value to be the number of years since 1900, 320which is what the C<localtime()> and C<gmtime()> built-ins returns. 321 322They perform range checking by default on the input C<$sec>, C<$min>, C<$hour>, 323C<$mday>, and C<$mon> values and will croak (using C<Carp::croak()>) if given a 324value outside the allowed ranges. 325 326While it would be nice to make this the default behavior, that would almost 327certainly break a lot of code, so you must explicitly import these functions 328and use them instead of the default C<timelocal()> and C<timegm()>. 329 330You are B<strongly> encouraged to use these functions in any new code which 331uses this module. It will almost certainly make your code's behavior less 332surprising. 333 334=head2 C<timelocal_modern()> and C<timegm_modern()> 335 336I<Since version 1.27.> 337 338When C<Time::Local> was first written, it was a common practice to represent 339years as a two-digit value like C<99> for C<1999> or C<1> for C<2001>. This 340caused all sorts of problems (google "Y2K problem" if you're very young) and 341developers eventually realized that this was a terrible idea. 342 343The default exports of C<timelocal()> and C<timegm()> do a complicated 344calculation when given a year value less than 1000. This leads to surprising 345results in many cases. See L</Year Value Interpretation> for details. 346 347The C<time*_modern()> functions do not do this year munging and simply take the 348year value as provided. 349 350They perform range checking by default on the input C<$sec>, C<$min>, C<$hour>, 351C<$mday>, and C<$mon> values and will croak (using C<Carp::croak()>) if given a 352value outside the allowed ranges. 353 354=head2 C<timelocal()> and C<timegm()> 355 356This module exports two functions by default, C<timelocal()> and C<timegm()>. 357 358They perform range checking by default on the input C<$sec>, C<$min>, C<$hour>, 359C<$mday>, and C<$mon> values and will croak (using C<Carp::croak()>) if given a 360value outside the allowed ranges. 361 362B<Warning: The year value interpretation that these functions and their nocheck 363variants use will almost certainly lead to bugs in your code, if not now, then 364in the future. You are strongly discouraged from using these in new code, and 365you should convert old code to using either the C<*_posix> or C<*_modern> 366functions if possible.> 367 368=head2 C<timelocal_nocheck()> and C<timegm_nocheck()> 369 370If you are working with data you know to be valid, you can use the "nocheck" 371variants, C<timelocal_nocheck()> and C<timegm_nocheck()>. These variants must 372be explicitly imported. 373 374If you supply data which is not valid (month 27, second 1,000) the results will 375be unpredictable (so don't do that). 376 377Note that my benchmarks show that this is just a 3% speed increase over the 378checked versions, so unless calling C<Time::Local> is the hottest spot in your 379application, using these nocheck variants is unlikely to have much impact on 380your application. 381 382=head2 Year Value Interpretation 383 384B<This does not apply to the C<*_posix> or C<*_modern> functions. Use those 385exports if you want to ensure consistent behavior as your code ages.> 386 387Strictly speaking, the year should be specified in a form consistent with 388C<localtime()>, i.e. the offset from 1900. In order to make the interpretation 389of the year easier for humans, however, who are more accustomed to seeing years 390as two-digit or four-digit values, the following conventions are followed: 391 392=over 4 393 394=item * 395 396Years greater than 999 are interpreted as being the actual year, rather than 397the offset from 1900. Thus, 1964 would indicate the year Martin Luther King won 398the Nobel prize, not the year 3864. 399 400=item * 401 402Years in the range 100..999 are interpreted as offset from 1900, so that 112 403indicates 2012. This rule also applies to years less than zero (but see note 404below regarding date range). 405 406=item * 407 408Years in the range 0..99 are interpreted as shorthand for years in the rolling 409"current century," defined as 50 years on either side of the current year. 410Thus, today, in 1999, 0 would refer to 2000, and 45 to 2045, but 55 would refer 411to 1955. Twenty years from now, 55 would instead refer to 2055. This is messy, 412but matches the way people currently think about two digit dates. Whenever 413possible, use an absolute four digit year instead. 414 415=back 416 417The scheme above allows interpretation of a wide range of dates, particularly 418if 4-digit years are used. But it also means that the behavior of your code 419changes as time passes, because the rolling "current century" changes each 420year. 421 422=head2 Limits of time_t 423 424On perl versions older than 5.12.0, the range of dates that can be actually be 425handled depends on the size of C<time_t> (usually a signed integer) on the 426given platform. Currently, this is 32 bits for most systems, yielding an 427approximate range from Dec 1901 to Jan 2038. 428 429Both C<timelocal()> and C<timegm()> croak if given dates outside the supported 430range. 431 432As of version 5.12.0, perl has stopped using the time implementation of the 433operating system it's running on. Instead, it has its own implementation of 434those routines with a safe range of at least +/- 2**52 (about 142 million 435years) 436 437=head2 Ambiguous Local Times (DST) 438 439Because of DST changes, there are many time zones where the same local time 440occurs for two different GMT times on the same day. For example, in the 441"Europe/Paris" time zone, the local time of 2001-10-28 02:30:00 can represent 442either 2001-10-28 00:30:00 GMT, B<or> 2001-10-28 01:30:00 GMT. 443 444When given an ambiguous local time, the timelocal() function will always return 445the epoch for the I<earlier> of the two possible GMT times. 446 447=head2 Non-Existent Local Times (DST) 448 449When a DST change causes a locale clock to skip one hour forward, there will be 450an hour's worth of local times that don't exist. Again, for the "Europe/Paris" 451time zone, the local clock jumped from 2001-03-25 01:59:59 to 2001-03-25 45203:00:00. 453 454If the C<timelocal()> function is given a non-existent local time, it will 455simply return an epoch value for the time one hour later. 456 457=head2 Negative Epoch Values 458 459On perl version 5.12.0 and newer, negative epoch values are fully supported. 460 461On older versions of perl, negative epoch (C<time_t>) values, which are not 462officially supported by the POSIX standards, are known not to work on some 463systems. These include MacOS (pre-OSX) and Win32. 464 465On systems which do support negative epoch values, this module should be able 466to cope with dates before the start of the epoch, down the minimum value of 467time_t for the system. 468 469=head1 IMPLEMENTATION 470 471These routines are quite efficient and yet are always guaranteed to agree with 472C<localtime()> and C<gmtime()>. We manage this by caching the start times of 473any months we've seen before. If we know the start time of the month, we can 474always calculate any time within the month. The start times are calculated 475using a mathematical formula. Unlike other algorithms that do multiple calls to 476C<gmtime()>. 477 478The C<timelocal()> function is implemented using the same cache. We just assume 479that we're translating a GMT time, and then fudge it when we're done for the 480timezone and daylight savings arguments. Note that the timezone is evaluated 481for each date because countries occasionally change their official timezones. 482Assuming that C<localtime()> corrects for these changes, this routine will also 483be correct. 484 485=head1 AUTHORS EMERITUS 486 487This module is based on a Perl 4 library, timelocal.pl, that was included with 488Perl 4.036, and was most likely written by Tom Christiansen. 489 490The current version was written by Graham Barr. 491 492=head1 BUGS 493 494The whole scheme for interpreting two-digit years can be considered a bug. 495 496Bugs may be submitted at L<https://github.com/houseabsolute/Time-Local/issues>. 497 498There is a mailing list available for users of this distribution, 499L<mailto:datetime@perl.org>. 500 501=head1 SOURCE 502 503The source code repository for Time-Local can be found at L<https://github.com/houseabsolute/Time-Local>. 504 505=head1 AUTHOR 506 507Dave Rolsky <autarch@urth.org> 508 509=head1 CONTRIBUTORS 510 511=for stopwords Florian Ragwitz Gregory Oschwald J. Nick Koston Tom Wyant Unknown 512 513=over 4 514 515=item * 516 517Florian Ragwitz <rafl@debian.org> 518 519=item * 520 521Gregory Oschwald <oschwald@gmail.com> 522 523=item * 524 525J. Nick Koston <nick@cpanel.net> 526 527=item * 528 529Tom Wyant <wyant@cpan.org> 530 531=item * 532 533Unknown <unknown@example.com> 534 535=back 536 537=head1 COPYRIGHT AND LICENSE 538 539This software is copyright (c) 1997 - 2023 by Graham Barr & Dave Rolsky. 540 541This is free software; you can redistribute it and/or modify it under 542the same terms as the Perl 5 programming language system itself. 543 544The full text of the license can be found in the 545F<LICENSE> file included with this distribution. 546 547=cut 548