1package Time::Piece; 2 3use strict; 4 5use XSLoader (); 6use Time::Seconds; 7use Carp; 8use Time::Local; 9use Scalar::Util qw/ blessed /; 10 11use Exporter (); 12 13our @EXPORT = qw( 14 localtime 15 gmtime 16); 17 18our %EXPORT_TAGS = ( 19 ':override' => 'internal', 20 ); 21 22our $VERSION = '1.3401_01'; 23 24XSLoader::load( 'Time::Piece', $VERSION ); 25 26my $DATE_SEP = '-'; 27my $TIME_SEP = ':'; 28my @MON_LIST = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); 29my @FULLMON_LIST = qw(January February March April May June July 30 August September October November December); 31my @DAY_LIST = qw(Sun Mon Tue Wed Thu Fri Sat); 32my @FULLDAY_LIST = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday); 33my $IS_WIN32 = ($^O =~ /Win32/); 34 35my $LOCALE; 36 37use constant { 38 'c_sec' => 0, 39 'c_min' => 1, 40 'c_hour' => 2, 41 'c_mday' => 3, 42 'c_mon' => 4, 43 'c_year' => 5, 44 'c_wday' => 6, 45 'c_yday' => 7, 46 'c_isdst' => 8, 47 'c_epoch' => 9, 48 'c_islocal' => 10, 49}; 50 51sub localtime { 52 unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') }; 53 my $class = shift; 54 my $time = shift; 55 $time = time if (!defined $time); 56 $class->_mktime($time, 1); 57} 58 59sub gmtime { 60 unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') }; 61 my $class = shift; 62 my $time = shift; 63 $time = time if (!defined $time); 64 $class->_mktime($time, 0); 65} 66 67 68# Check if the supplied param is either a normal array (as returned from 69# localtime in list context) or a Time::Piece-like wrapper around one. 70# 71# We need to differentiate between an array ref that we can interrogate and 72# other blessed objects (like overloaded values). 73sub _is_time_struct { 74 return 1 if ref($_[1]) eq 'ARRAY'; 75 return 1 if blessed($_[1]) && $_[1]->isa('Time::Piece'); 76 77 return 0; 78} 79 80 81sub new { 82 my $class = shift; 83 my ($time) = @_; 84 85 my $self; 86 87 if ($class->_is_time_struct($time)) { 88 $self = $time->[c_islocal] ? $class->localtime($time) : $class->gmtime($time); 89 } 90 elsif (defined($time)) { 91 $self = $class->localtime($time); 92 } 93 elsif (ref($class) && $class->isa(__PACKAGE__)) { 94 $self = $class->_mktime($class->epoch, $class->[c_islocal]); 95 } 96 else { 97 $self = $class->localtime(); 98 } 99 100 return bless $self, ref($class) || $class; 101} 102 103sub parse { 104 my $proto = shift; 105 my $class = ref($proto) || $proto; 106 my @components; 107 108 warnings::warnif("deprecated", 109 "parse() is deprecated, use strptime() instead."); 110 111 if (@_ > 1) { 112 @components = @_; 113 } 114 else { 115 @components = shift =~ /(\d+)$DATE_SEP(\d+)$DATE_SEP(\d+)(?:(?:T|\s+)(\d+)$TIME_SEP(\d+)(?:$TIME_SEP(\d+)))/; 116 @components = reverse(@components[0..5]); 117 } 118 return $class->new( timelocal(@components )); 119} 120 121sub _mktime { 122 my ($class, $time, $islocal) = @_; 123 124 $class = blessed($class) || $class; 125 126 if ($class->_is_time_struct($time)) { 127 my @new_time = @$time; 128 my @tm_parts = (@new_time[c_sec .. c_mon], $new_time[c_year]+1900); 129 130 $new_time[c_epoch] = $islocal ? timelocal(@tm_parts) : timegm(@tm_parts); 131 132 return wantarray ? @new_time : bless [@new_time[0..9], $islocal], $class; 133 } 134 _tzset(); 135 my @time = $islocal ? 136 CORE::localtime($time) 137 : 138 CORE::gmtime($time); 139 wantarray ? @time : bless [@time, $time, $islocal], $class; 140} 141 142my %_special_exports = ( 143 localtime => sub { my $c = $_[0]; sub { $c->localtime(@_) } }, 144 gmtime => sub { my $c = $_[0]; sub { $c->gmtime(@_) } }, 145); 146 147sub export { 148 my ($class, $to, @methods) = @_; 149 for my $method (@methods) { 150 if (exists $_special_exports{$method}) { 151 no strict 'refs'; 152 no warnings 'redefine'; 153 *{$to . "::$method"} = $_special_exports{$method}->($class); 154 } else { 155 $class->Exporter::export($to, $method); 156 } 157 } 158} 159 160sub import { 161 # replace CORE::GLOBAL localtime and gmtime if passed :override 162 my $class = shift; 163 my %params; 164 map($params{$_}++,@_,@EXPORT); 165 if (delete $params{':override'}) { 166 $class->export('CORE::GLOBAL', keys %params); 167 } 168 else { 169 $class->export(scalar caller, keys %params); 170 } 171} 172 173## Methods ## 174 175sub sec { 176 my $time = shift; 177 $time->[c_sec]; 178} 179 180*second = \&sec; 181 182sub min { 183 my $time = shift; 184 $time->[c_min]; 185} 186 187*minute = \&min; 188 189sub hour { 190 my $time = shift; 191 $time->[c_hour]; 192} 193 194sub mday { 195 my $time = shift; 196 $time->[c_mday]; 197} 198 199*day_of_month = \&mday; 200 201sub mon { 202 my $time = shift; 203 $time->[c_mon] + 1; 204} 205 206sub _mon { 207 my $time = shift; 208 $time->[c_mon]; 209} 210 211sub month { 212 my $time = shift; 213 if (@_) { 214 return $_[$time->[c_mon]]; 215 } 216 elsif (@MON_LIST) { 217 return $MON_LIST[$time->[c_mon]]; 218 } 219 else { 220 return $time->strftime('%b'); 221 } 222} 223 224*monname = \&month; 225 226sub fullmonth { 227 my $time = shift; 228 if (@_) { 229 return $_[$time->[c_mon]]; 230 } 231 elsif (@FULLMON_LIST) { 232 return $FULLMON_LIST[$time->[c_mon]]; 233 } 234 else { 235 return $time->strftime('%B'); 236 } 237} 238 239sub year { 240 my $time = shift; 241 $time->[c_year] + 1900; 242} 243 244sub _year { 245 my $time = shift; 246 $time->[c_year]; 247} 248 249sub yy { 250 my $time = shift; 251 my $res = $time->[c_year] % 100; 252 return $res > 9 ? $res : "0$res"; 253} 254 255sub wday { 256 my $time = shift; 257 $time->[c_wday] + 1; 258} 259 260sub _wday { 261 my $time = shift; 262 $time->[c_wday]; 263} 264 265*day_of_week = \&_wday; 266 267sub wdayname { 268 my $time = shift; 269 if (@_) { 270 return $_[$time->[c_wday]]; 271 } 272 elsif (@DAY_LIST) { 273 return $DAY_LIST[$time->[c_wday]]; 274 } 275 else { 276 return $time->strftime('%a'); 277 } 278} 279 280*day = \&wdayname; 281 282sub fullday { 283 my $time = shift; 284 if (@_) { 285 return $_[$time->[c_wday]]; 286 } 287 elsif (@FULLDAY_LIST) { 288 return $FULLDAY_LIST[$time->[c_wday]]; 289 } 290 else { 291 return $time->strftime('%A'); 292 } 293} 294 295sub yday { 296 my $time = shift; 297 $time->[c_yday]; 298} 299 300*day_of_year = \&yday; 301 302sub isdst { 303 my $time = shift; 304 $time->[c_isdst]; 305} 306 307*daylight_savings = \&isdst; 308 309# Thanks to Tony Olekshy <olekshy@cs.ualberta.ca> for this algorithm 310sub tzoffset { 311 my $time = shift; 312 313 return Time::Seconds->new(0) unless $time->[c_islocal]; 314 315 my $epoch = $time->epoch; 316 317 my $j = sub { 318 319 my ($s,$n,$h,$d,$m,$y) = @_; $m += 1; $y += 1900; 320 321 $time->_jd($y, $m, $d, $h, $n, $s); 322 323 }; 324 325 # Compute floating offset in hours. 326 # 327 # Note use of crt methods so the tz is properly set... 328 # See: http://perlmonks.org/?node_id=820347 329 my $delta = 24 * ($j->(_crt_localtime($epoch)) - $j->(_crt_gmtime($epoch))); 330 331 # Return value in seconds rounded to nearest minute. 332 return Time::Seconds->new( int($delta * 60 + ($delta >= 0 ? 0.5 : -0.5)) * 60 ); 333} 334 335sub epoch { 336 my $time = shift; 337 if (defined($time->[c_epoch])) { 338 return $time->[c_epoch]; 339 } 340 else { 341 my $epoch = $time->[c_islocal] ? 342 timelocal(@{$time}[c_sec .. c_mon], $time->[c_year]+1900) 343 : 344 timegm(@{$time}[c_sec .. c_mon], $time->[c_year]+1900); 345 $time->[c_epoch] = $epoch; 346 return $epoch; 347 } 348} 349 350sub hms { 351 my $time = shift; 352 my $sep = @_ ? shift(@_) : $TIME_SEP; 353 sprintf("%02d$sep%02d$sep%02d", $time->[c_hour], $time->[c_min], $time->[c_sec]); 354} 355 356*time = \&hms; 357 358sub ymd { 359 my $time = shift; 360 my $sep = @_ ? shift(@_) : $DATE_SEP; 361 sprintf("%d$sep%02d$sep%02d", $time->year, $time->mon, $time->[c_mday]); 362} 363 364*date = \&ymd; 365 366sub mdy { 367 my $time = shift; 368 my $sep = @_ ? shift(@_) : $DATE_SEP; 369 sprintf("%02d$sep%02d$sep%d", $time->mon, $time->[c_mday], $time->year); 370} 371 372sub dmy { 373 my $time = shift; 374 my $sep = @_ ? shift(@_) : $DATE_SEP; 375 sprintf("%02d$sep%02d$sep%d", $time->[c_mday], $time->mon, $time->year); 376} 377 378sub datetime { 379 my $time = shift; 380 my %seps = (date => $DATE_SEP, T => 'T', time => $TIME_SEP, @_); 381 return join($seps{T}, $time->date($seps{date}), $time->time($seps{time})); 382} 383 384 385 386# Julian Day is always calculated for UT regardless 387# of local time 388sub julian_day { 389 my $time = shift; 390 # Correct for localtime 391 $time = $time->gmtime( $time->epoch ) if $time->[c_islocal]; 392 393 # Calculate the Julian day itself 394 my $jd = $time->_jd( $time->year, $time->mon, $time->mday, 395 $time->hour, $time->min, $time->sec); 396 397 return $jd; 398} 399 400# MJD is defined as JD - 2400000.5 days 401sub mjd { 402 return shift->julian_day - 2_400_000.5; 403} 404 405# Internal calculation of Julian date. Needed here so that 406# both tzoffset and mjd/jd methods can share the code 407# Algorithm from Hatcher 1984 (QJRAS 25, 53-55), and 408# Hughes et al, 1989, MNRAS, 238, 15 409# See: http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode=1989MNRAS.238.1529H&db_key=AST 410# for more details 411 412sub _jd { 413 my $self = shift; 414 my ($y, $m, $d, $h, $n, $s) = @_; 415 416 # Adjust input parameters according to the month 417 $y = ( $m > 2 ? $y : $y - 1); 418 $m = ( $m > 2 ? $m - 3 : $m + 9); 419 420 # Calculate the Julian Date (assuming Julian calendar) 421 my $J = int( 365.25 *( $y + 4712) ) 422 + int( (30.6 * $m) + 0.5) 423 + 59 424 + $d 425 - 0.5; 426 427 # Calculate the Gregorian Correction (since we have Gregorian dates) 428 my $G = 38 - int( 0.75 * int(49+($y/100))); 429 430 # Calculate the actual Julian Date 431 my $JD = $J + $G; 432 433 # Modify to include hours/mins/secs in floating portion. 434 return $JD + ($h + ($n + $s / 60) / 60) / 24; 435} 436 437sub week { 438 my $self = shift; 439 440 my $J = $self->julian_day; 441 # Julian day is independent of time zone so add on tzoffset 442 # if we are using local time here since we want the week day 443 # to reflect the local time rather than UTC 444 $J += ($self->tzoffset/(24*3600)) if $self->[c_islocal]; 445 446 # Now that we have the Julian day including fractions 447 # convert it to an integer Julian Day Number using nearest 448 # int (since the day changes at midday we convert all Julian 449 # dates to following midnight). 450 $J = int($J+0.5); 451 452 use integer; 453 my $d4 = ((($J + 31741 - ($J % 7)) % 146097) % 36524) % 1461; 454 my $L = $d4 / 1460; 455 my $d1 = (($d4 - $L) % 365) + $L; 456 return $d1 / 7 + 1; 457} 458 459sub _is_leap_year { 460 my $year = shift; 461 return (($year %4 == 0) && !($year % 100 == 0)) || ($year % 400 == 0) 462 ? 1 : 0; 463} 464 465sub is_leap_year { 466 my $time = shift; 467 my $year = $time->year; 468 return _is_leap_year($year); 469} 470 471my @MON_LAST = qw(31 28 31 30 31 30 31 31 30 31 30 31); 472 473sub month_last_day { 474 my $time = shift; 475 my $year = $time->year; 476 my $_mon = $time->_mon; 477 return $MON_LAST[$_mon] + ($_mon == 1 ? _is_leap_year($year) : 0); 478} 479 480my $trans_map_common = { 481 482 'c' => sub { 483 my ( $format ) = @_; 484 if($LOCALE->{PM} && $LOCALE->{AM}){ 485 $format =~ s/%c/%a %d %b %Y %I:%M:%S %p/; 486 } 487 else{ 488 $format =~ s/%c/%a %d %b %Y %H:%M:%S/; 489 } 490 return $format; 491 }, 492 'r' => sub { 493 my ( $format ) = @_; 494 if($LOCALE->{PM} && $LOCALE->{AM}){ 495 $format =~ s/%r/%I:%M:%S %p/; 496 } 497 else{ 498 $format =~ s/%r/%H:%M:%S/; 499 } 500 return $format; 501 }, 502 'X' => sub { 503 my ( $format ) = @_; 504 if($LOCALE->{PM} && $LOCALE->{AM}){ 505 $format =~ s/%X/%I:%M:%S %p/; 506 } 507 else{ 508 $format =~ s/%X/%H:%M:%S/; 509 } 510 return $format; 511 }, 512}; 513 514my $strftime_trans_map = { 515 %{$trans_map_common}, 516 517 'e' => sub { 518 my ( $format, $time ) = @_; 519 $format =~ s/%e/%d/ if $IS_WIN32; 520 return $format; 521 }, 522 'D' => sub { 523 my ( $format, $time ) = @_; 524 $format =~ s/%D/%m\/%d\/%y/; 525 return $format; 526 }, 527 'F' => sub { 528 my ( $format, $time ) = @_; 529 $format =~ s/%F/%Y-%m-%d/; 530 return $format; 531 }, 532 'R' => sub { 533 my ( $format, $time ) = @_; 534 $format =~ s/%R/%H:%M/; 535 return $format; 536 }, 537 's' => sub { 538 #%s not portable if time parts are from gmtime since %s will 539 #cause a call to native mktime (and thus uses local TZ) 540 my ( $format, $time ) = @_; 541 $format =~ s/%s/$time->[c_epoch]/; 542 return $format; 543 }, 544 'T' => sub { 545 my ( $format, $time ) = @_; 546 $format =~ s/%T/%H:%M:%S/ if $IS_WIN32; 547 return $format; 548 }, 549 'u' => sub { 550 my ( $format, $time ) = @_; 551 $format =~ s/%u/%w/ if $IS_WIN32; 552 return $format; 553 }, 554 'V' => sub { 555 my ( $format, $time ) = @_; 556 my $week = sprintf( "%02d", $time->week() ); 557 $format =~ s/%V/$week/ if $IS_WIN32; 558 return $format; 559 }, 560 'x' => sub { 561 my ( $format, $time ) = @_; 562 $format =~ s/%x/%a %d %b %Y/; 563 return $format; 564 }, 565 'z' => sub { #%[zZ] not portable if time parts are from gmtime 566 my ( $format, $time ) = @_; 567 $format =~ s/%z/+0000/ if not $time->[c_islocal]; 568 return $format; 569 }, 570 'Z' => sub { 571 my ( $format, $time ) = @_; 572 $format =~ s/%Z/UTC/ if not $time->[c_islocal]; 573 return $format; 574 }, 575}; 576 577sub strftime { 578 my $time = shift; 579 my $format = @_ ? shift(@_) : '%a, %d %b %Y %H:%M:%S %Z'; 580 $format = _translate_format($format, $strftime_trans_map, $time); 581 582 return $format unless $format =~ /%/; #if translate removes everything 583 584 return _strftime($format, $time->epoch, $time->[c_islocal]); 585} 586 587my $strptime_trans_map = { 588 %{$trans_map_common}, 589}; 590 591sub strptime { 592 my $time = shift; 593 my $string = shift; 594 my $format = @_ ? shift(@_) : "%a, %d %b %Y %H:%M:%S %Z"; 595 my $islocal = (ref($time) ? $time->[c_islocal] : 0); 596 my $locales = $LOCALE || &Time::Piece::_default_locale(); 597 $format = _translate_format($format, $strptime_trans_map); 598 my @vals = _strptime($string, $format, $islocal, $locales); 599# warn(sprintf("got vals: %d-%d-%d %d:%d:%d\n", reverse(@vals[c_sec..c_year]))); 600 return scalar $time->_mktime(\@vals, $islocal); 601} 602 603sub day_list { 604 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method 605 my @old = @DAY_LIST; 606 if (@_) { 607 @DAY_LIST = @_; 608 &Time::Piece::_default_locale(); 609 } 610 return @old; 611} 612 613sub mon_list { 614 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method 615 my @old = @MON_LIST; 616 if (@_) { 617 @MON_LIST = @_; 618 &Time::Piece::_default_locale(); 619 } 620 return @old; 621} 622 623sub time_separator { 624 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); 625 my $old = $TIME_SEP; 626 if (@_) { 627 $TIME_SEP = $_[0]; 628 } 629 return $old; 630} 631 632sub date_separator { 633 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); 634 my $old = $DATE_SEP; 635 if (@_) { 636 $DATE_SEP = $_[0]; 637 } 638 return $old; 639} 640 641use overload '""' => \&cdate, 642 'cmp' => \&str_compare, 643 'fallback' => undef; 644 645sub cdate { 646 my $time = shift; 647 if ($time->[c_islocal]) { 648 return scalar(CORE::localtime($time->epoch)); 649 } 650 else { 651 return scalar(CORE::gmtime($time->epoch)); 652 } 653} 654 655sub str_compare { 656 my ($lhs, $rhs, $reverse) = @_; 657 658 if (blessed($rhs) && $rhs->isa('Time::Piece')) { 659 $rhs = "$rhs"; 660 } 661 return $reverse ? $rhs cmp $lhs->cdate : $lhs->cdate cmp $rhs; 662} 663 664use overload 665 '-' => \&subtract, 666 '+' => \&add; 667 668sub subtract { 669 my $time = shift; 670 my $rhs = shift; 671 672 if (shift) 673 { 674 # SWAPED is set (so someone tried an expression like NOTDATE - DATE). 675 # Imitate Perl's standard behavior and return the result as if the 676 # string $time resolves to was subtracted from NOTDATE. This way, 677 # classes which override this one and which have a stringify function 678 # that resolves to something that looks more like a number don't need 679 # to override this function. 680 return $rhs - "$time"; 681 } 682 683 if (blessed($rhs) && $rhs->isa('Time::Piece')) { 684 return Time::Seconds->new($time->epoch - $rhs->epoch); 685 } 686 else { 687 # rhs is seconds. 688 return $time->_mktime(($time->epoch - $rhs), $time->[c_islocal]); 689 } 690} 691 692sub add { 693 my $time = shift; 694 my $rhs = shift; 695 696 return $time->_mktime(($time->epoch + $rhs), $time->[c_islocal]); 697} 698 699use overload 700 '<=>' => \&compare; 701 702sub get_epochs { 703 my ($lhs, $rhs, $reverse) = @_; 704 unless (blessed($rhs) && $rhs->isa('Time::Piece')) { 705 $rhs = $lhs->new($rhs); 706 } 707 if ($reverse) { 708 return $rhs->epoch, $lhs->epoch; 709 } 710 return $lhs->epoch, $rhs->epoch; 711} 712 713sub compare { 714 my ($lhs, $rhs) = get_epochs(@_); 715 return $lhs <=> $rhs; 716} 717 718sub add_months { 719 my ($time, $num_months) = @_; 720 721 croak("add_months requires a number of months") unless defined($num_months); 722 723 my $final_month = $time->_mon + $num_months; 724 my $num_years = 0; 725 if ($final_month > 11 || $final_month < 0) { 726 # these two ops required because we have no POSIX::floor and don't 727 # want to load POSIX.pm 728 if ($final_month < 0 && $final_month % 12 == 0) { 729 $num_years = int($final_month / 12) + 1; 730 } 731 else { 732 $num_years = int($final_month / 12); 733 } 734 $num_years-- if ($final_month < 0); 735 736 $final_month = $final_month % 12; 737 } 738 739 my @vals = _mini_mktime($time->sec, $time->min, $time->hour, 740 $time->mday, $final_month, $time->year - 1900 + $num_years); 741 # warn(sprintf("got %d vals: %d-%d-%d %d:%d:%d [%d]\n", scalar(@vals), reverse(@vals), $time->[c_islocal])); 742 return scalar $time->_mktime(\@vals, $time->[c_islocal]); 743} 744 745sub add_years { 746 my ($time, $years) = @_; 747 $time->add_months($years * 12); 748} 749 750sub truncate { 751 my ($time, %params) = @_; 752 return $time unless exists $params{to}; 753 #if ($params{to} eq 'week') { return $time->_truncate_week; } 754 my %units = ( 755 second => 0, 756 minute => 1, 757 hour => 2, 758 day => 3, 759 month => 4, 760 quarter => 5, 761 year => 5 762 ); 763 my $to = $units{$params{to}}; 764 croak "Invalid value of 'to' parameter: $params{to}" unless defined $to; 765 my $start_month = 0; 766 if ($params{to} eq 'quarter') { 767 $start_month = int( $time->_mon / 3 ) * 3; 768 } 769 my @down_to = (0, 0, 0, 1, $start_month, $time->year); 770 return $time->_mktime([@down_to[0..$to-1], @$time[$to..c_isdst]], 771 $time->[c_islocal]); 772} 773 774#Given a format and a translate map, replace format flags in 775#accordance with the logic from the translation map subroutines 776sub _translate_format { 777 my ( $format, $trans_map, $time ) = @_; 778 779 $format =~ s/%%/\e\e/g; #escape the escape 780 my $lexer = _build_format_lexer($format); 781 782 while(my $flag = $lexer->() ){ 783 next unless exists $trans_map->{$flag}; 784 $format = $trans_map->{$flag}($format, $time); 785 } 786 787 $format =~ s/\e\e/%%/g; 788 return $format; 789} 790 791sub _build_format_lexer { 792 my $format = shift(); 793 794 #Higher Order Perl p.359 (or thereabouts) 795 return sub { 796 LABEL: { 797 return $1 if $format =~ m/\G%([a-zA-Z])/gc; #return single char flags 798 799 redo LABEL if $format =~ m/\G(.)/gc; 800 return; #return at empty string 801 } 802 }; 803} 804 805sub use_locale { 806 #get locale month/day names from posix strftime (from Piece.xs) 807 my $locales = _get_localization(); 808 809 #If AM and PM are the same, set both to '' 810 if ( !$locales->{PM} 811 || !$locales->{AM} 812 || ( $locales->{PM} eq $locales->{AM} ) ) 813 { 814 $locales->{PM} = ''; 815 $locales->{AM} = ''; 816 } 817 818 $locales->{pm} = lc $locales->{PM}; 819 $locales->{am} = lc $locales->{AM}; 820 #should probably figure out how to get a 821 #region specific format for %c someday 822 $locales->{c_fmt} = ''; 823 824 #Set globals. If anything is 825 #weird just use original 826 if( @{$locales->{weekday}} < 7 ){ 827 @{$locales->{weekday}} = @FULLDAY_LIST; 828 } 829 else { 830 @FULLDAY_LIST = @{$locales->{weekday}}; 831 } 832 833 if( @{$locales->{wday}} < 7 ){ 834 @{$locales->{wday}} = @DAY_LIST; 835 } 836 else { 837 @DAY_LIST = @{$locales->{wday}}; 838 } 839 840 if( @{$locales->{month}} < 12 ){ 841 @{$locales->{month}} = @FULLMON_LIST; 842 }else { 843 @FULLMON_LIST = @{$locales->{month}}; 844 } 845 846 if( @{$locales->{mon}} < 12 ){ 847 @{$locales->{mon}} = @MON_LIST; 848 } 849 else{ 850 @MON_LIST= @{$locales->{mon}}; 851 } 852 853 $LOCALE = $locales; 854} 855 856#$Time::Piece::LOCALE is used by strptime and thus needs to be 857#in sync with what ever users change to via day_list() and mon_list(). 858#Should probably deprecate this use of gloabl state, but oh well... 859sub _default_locale { 860 my $locales = {}; 861 862 @{ $locales->{weekday} } = @FULLDAY_LIST; 863 @{ $locales->{wday} } = @DAY_LIST; 864 @{ $locales->{month} } = @FULLMON_LIST; 865 @{ $locales->{mon} } = @MON_LIST; 866 $locales->{alt_month} = $locales->{month}; 867 868 $locales->{PM} = 'PM'; 869 $locales->{AM} = 'AM'; 870 $locales->{pm} = 'pm'; 871 $locales->{am} = 'am'; 872 $locales->{c_fmt} = ''; 873 874 $LOCALE = $locales; 875} 876 877sub _locale { 878 return $LOCALE; 879} 880 881 8821; 883__END__ 884 885=head1 NAME 886 887Time::Piece - Object Oriented time objects 888 889=head1 SYNOPSIS 890 891 use Time::Piece; 892 893 my $t = localtime; 894 print "Time is $t\n"; 895 print "Year is ", $t->year, "\n"; 896 897=head1 DESCRIPTION 898 899This module replaces the standard C<localtime> and C<gmtime> functions with 900implementations that return objects. It does so in a backwards 901compatible manner, so that using localtime/gmtime in the way documented 902in perlfunc will still return what you expect. 903 904The module actually implements most of an interface described by 905Larry Wall on the perl5-porters mailing list here: 906L<https://www.nntp.perl.org/group/perl.perl5.porters/2000/01/msg5283.html> 907 908=head1 USAGE 909 910After importing this module, when you use localtime or gmtime in a scalar 911context, rather than getting an ordinary scalar string representing the 912date and time, you get a Time::Piece object, whose stringification happens 913to produce the same effect as the localtime and gmtime functions. There is 914also a new() constructor provided, which is the same as localtime(), except 915when passed a Time::Piece object, in which case it's a copy constructor. The 916following methods are available on the object: 917 918 $t->sec # also available as $t->second 919 $t->min # also available as $t->minute 920 $t->hour # 24 hour 921 $t->mday # also available as $t->day_of_month 922 $t->mon # 1 = January 923 $t->_mon # 0 = January 924 $t->monname # Feb 925 $t->month # same as $t->monname 926 $t->fullmonth # February 927 $t->year # based at 0 (year 0 AD is, of course 1 BC) 928 $t->_year # year minus 1900 929 $t->yy # 2 digit year 930 $t->wday # 1 = Sunday 931 $t->_wday # 0 = Sunday 932 $t->day_of_week # 0 = Sunday 933 $t->wdayname # Tue 934 $t->day # same as wdayname 935 $t->fullday # Tuesday 936 $t->yday # also available as $t->day_of_year, 0 = Jan 01 937 $t->isdst # also available as $t->daylight_savings 938 939 $t->hms # 12:34:56 940 $t->hms(".") # 12.34.56 941 $t->time # same as $t->hms 942 943 $t->ymd # 2000-02-29 944 $t->date # same as $t->ymd 945 $t->mdy # 02-29-2000 946 $t->mdy("/") # 02/29/2000 947 $t->dmy # 29-02-2000 948 $t->dmy(".") # 29.02.2000 949 $t->datetime # 2000-02-29T12:34:56 (ISO 8601) 950 $t->cdate # Tue Feb 29 12:34:56 2000 951 "$t" # same as $t->cdate 952 953 $t->epoch # seconds since the epoch 954 $t->tzoffset # timezone offset in a Time::Seconds object 955 956 $t->julian_day # number of days since Julian period began 957 $t->mjd # modified Julian date (JD-2400000.5 days) 958 959 $t->week # week number (ISO 8601) 960 961 $t->is_leap_year # true if it's a leap year 962 $t->month_last_day # 28-31 963 964 $t->time_separator($s) # set the default separator (default ":") 965 $t->date_separator($s) # set the default separator (default "-") 966 $t->day_list(@days) # set the default weekdays 967 $t->mon_list(@days) # set the default months 968 969 $t->strftime(FORMAT) # same as POSIX::strftime (without the overhead 970 # of the full POSIX extension) 971 $t->strftime() # "Tue, 29 Feb 2000 12:34:56 GMT" 972 973 Time::Piece->strptime(STRING, FORMAT) 974 # see strptime man page. Creates a new 975 # Time::Piece object 976 977Note that C<localtime> and C<gmtime> are not listed above. If called as 978methods on a Time::Piece object, they act as constructors, returning a new 979Time::Piece object for the current time. In other words: they're not useful as 980methods. 981 982=head2 Local Locales 983 984Both wdayname (day) and monname (month) allow passing in a list to use 985to index the name of the days against. This can be useful if you need 986to implement some form of localisation without actually installing or 987using locales. Note that this is a global override and will affect 988all Time::Piece instances. 989 990 my @days = qw( Dimanche Lundi Merdi Mercredi Jeudi Vendredi Samedi ); 991 992 my $french_day = localtime->day(@days); 993 994These settings can be overridden globally too: 995 996 Time::Piece::day_list(@days); 997 998Or for months: 999 1000 Time::Piece::mon_list(@months); 1001 1002And locally for months: 1003 1004 print localtime->month(@months); 1005 1006Or to populate with your current system locale call: 1007 Time::Piece->use_locale(); 1008 1009=head2 Date Calculations 1010 1011It's possible to use simple addition and subtraction of objects: 1012 1013 use Time::Seconds; 1014 1015 my $seconds = $t1 - $t2; 1016 $t1 += ONE_DAY; # add 1 day (constant from Time::Seconds) 1017 1018The following are valid ($t1 and $t2 are Time::Piece objects): 1019 1020 $t1 - $t2; # returns Time::Seconds object 1021 $t1 - 42; # returns Time::Piece object 1022 $t1 + 533; # returns Time::Piece object 1023 1024However adding a Time::Piece object to another Time::Piece object 1025will cause a runtime error. 1026 1027Note that the first of the above returns a Time::Seconds object, so 1028while examining the object will print the number of seconds (because 1029of the overloading), you can also get the number of minutes, hours, 1030days, weeks and years in that delta, using the Time::Seconds API. 1031 1032In addition to adding seconds, there are two APIs for adding months and 1033years: 1034 1035 $t = $t->add_months(6); 1036 $t = $t->add_years(5); 1037 1038The months and years can be negative for subtractions. Note that there 1039is some "strange" behaviour when adding and subtracting months at the 1040ends of months. Generally when the resulting month is shorter than the 1041starting month then the number of overlap days is added. For example 1042subtracting a month from 2008-03-31 will not result in 2008-02-31 as this 1043is an impossible date. Instead you will get 2008-03-02. This appears to 1044be consistent with other date manipulation tools. 1045 1046=head2 Truncation 1047 1048Calling the C<truncate> method returns a copy of the object but with the 1049time truncated to the start of the supplied unit. 1050 1051 $t = $t->truncate(to => 'day'); 1052 1053This example will set the time to midnight on the same date which C<$t> 1054had previously. Allowed values for the "to" parameter are: "year", 1055"quarter", "month", "day", "hour", "minute" and "second". 1056 1057=head2 Date Comparisons 1058 1059Date comparisons are also possible, using the full suite of "<", ">", 1060"<=", ">=", "<=>", "==" and "!=". 1061 1062=head2 Date Parsing 1063 1064Time::Piece has a built-in strptime() function (from FreeBSD), allowing 1065you incredibly flexible date parsing routines. For example: 1066 1067 my $t = Time::Piece->strptime("Sunday 3rd Nov, 1943", 1068 "%A %drd %b, %Y"); 1069 1070 print $t->strftime("%a, %d %b %Y"); 1071 1072Outputs: 1073 1074 Wed, 03 Nov 1943 1075 1076(see, it's even smart enough to fix my obvious date bug) 1077 1078For more information see "man strptime", which should be on all unix 1079systems. 1080 1081Alternatively look here: L<http://www.unix.com/man-page/FreeBSD/3/strftime/> 1082 1083=head3 CAVEAT %A, %a, %B, %b, and friends 1084 1085Time::Piece::strptime by default can only parse American English date names. 1086Meanwhile, Time::Piece->strftime() will return date names that use the current 1087configured system locale. This means dates returned by strftime might not be 1088able to be parsed by strptime. This is the default behavior and can be 1089overridden by calling Time::Piece->use_locale(). This builds a list of the 1090current locale's day and month names which strptime will use to parse with. 1091Note this is a global override and will affect all Time::Piece instances. 1092 1093For instance with a German locale: 1094 1095 localtime->day_list(); 1096 1097Returns 1098 1099 ( 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ) 1100 1101While: 1102 1103 Time::Piece->use_locale(); 1104 localtime->day_list(); 1105 1106Returns 1107 1108 ( 'So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa' ) 1109 1110=head2 YYYY-MM-DDThh:mm:ss 1111 1112The ISO 8601 standard defines the date format to be YYYY-MM-DD, and 1113the time format to be hh:mm:ss (24 hour clock), and if combined, they 1114should be concatenated with date first and with a capital 'T' in front 1115of the time. 1116 1117=head2 Week Number 1118 1119The I<week number> may be an unknown concept to some readers. The ISO 11208601 standard defines that weeks begin on a Monday and week 1 of the 1121year is the week that includes both January 4th and the first Thursday 1122of the year. In other words, if the first Monday of January is the 11232nd, 3rd, or 4th, the preceding days of the January are part of the 1124last week of the preceding year. Week numbers range from 1 to 53. 1125 1126=head2 Global Overriding 1127 1128Finally, it's possible to override localtime and gmtime everywhere, by 1129including the ':override' tag in the import list: 1130 1131 use Time::Piece ':override'; 1132 1133=head1 CAVEATS 1134 1135=head2 Setting $ENV{TZ} in Threads on Win32 1136 1137Note that when using perl in the default build configuration on Win32 1138(specifically, when perl is built with PERL_IMPLICIT_SYS), each perl 1139interpreter maintains its own copy of the environment and only the main 1140interpreter will update the process environment seen by strftime. 1141 1142Therefore, if you make changes to $ENV{TZ} from inside a thread other than 1143the main thread then those changes will not be seen by strftime if you 1144subsequently call that with the %Z formatting code. You must change $ENV{TZ} 1145in the main thread to have the desired effect in this case (and you must 1146also call _tzset() in the main thread to register the environment change). 1147 1148Furthermore, remember that this caveat also applies to fork(), which is 1149emulated by threads on Win32. 1150 1151=head2 Use of epoch seconds 1152 1153This module internally uses the epoch seconds system that is provided via 1154the perl C<time()> function and supported by C<gmtime()> and C<localtime()>. 1155 1156If your perl does not support times larger than C<2^31> seconds then this 1157module is likely to fail at processing dates beyond the year 2038. There are 1158moves afoot to fix that in perl. Alternatively use 64 bit perl. Or if none 1159of those are options, use the L<DateTime> module which has support for years 1160well into the future and past. 1161 1162Also, the internal representation of Time::Piece->strftime deviates from the 1163standard POSIX implementation in that is uses the epoch (instead of separate 1164year, month, day parts). This change was added in version 1.30. If you must 1165have a more traditional strftime (which will normally never calculate day 1166light saving times correctly), you can pass the date parts from Time::Piece 1167into the strftime function provided by the POSIX module 1168(see strftime in L<POSIX> ). 1169 1170=head1 AUTHOR 1171 1172Matt Sergeant, matt@sergeant.org 1173Jarkko Hietaniemi, jhi@iki.fi (while creating Time::Piece for core perl) 1174 1175=head1 COPYRIGHT AND LICENSE 1176 1177Copyright 2001, Larry Wall. 1178 1179This module is free software, you may distribute it under the same terms 1180as Perl. 1181 1182=head1 SEE ALSO 1183 1184The excellent Calendar FAQ at L<http://www.tondering.dk/claus/calendar.html> 1185 1186=head1 BUGS 1187 1188The test harness leaves much to be desired. Patches welcome. 1189 1190=cut 1191