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