11 our @ISA = qw(Exporter DynaLoader);
19 ':override' => 'internal',
22 our $VERSION = '1.20_01';
24 bootstrap Time::Piece $VERSION;
28 my @MON_LIST = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
29 my @FULLMON_LIST = qw(January February March April May June July
30 August September October November December);
31 my @DAY_LIST = qw(Sun Mon Tue Wed Thu Fri Sat);
32 my @FULLDAY_LIST = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday);
34 use constant 'c_sec' => 0;
35 use constant 'c_min' => 1;
36 use constant 'c_hour' => 2;
37 use constant 'c_mday' => 3;
38 use constant 'c_mon' => 4;
39 use constant 'c_year' => 5;
40 use constant 'c_wday' => 6;
41 use constant 'c_yday' => 7;
42 use constant 'c_isdst' => 8;
43 use constant 'c_epoch' => 9;
44 use constant 'c_islocal' => 10;
47 unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') };
50 $time = time if (!defined $time);
51 $class->_mktime($time, 1);
55 unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') };
58 $time = time if (!defined $time);
59 $class->_mktime($time, 0);
69 $self = $class->localtime($time);
71 elsif (ref($class) && $class->isa(__PACKAGE__)) {
72 $self = $class->_mktime($class->epoch, $class->[c_islocal]);
75 $self = $class->localtime();
78 return bless $self, ref($class) || $class;
83 my $class = ref($proto) || $proto;
89 @components = shift =~ /(\d+)$DATE_SEP(\d+)$DATE_SEP(\d+)(?:(?:T|\s+)(\d+)$TIME_SEP(\d+)(?:$TIME_SEP(\d+)))/;
90 @components = reverse(@components[0..5]);
92 return $class->new(_strftime("%s", @components));
96 my ($class, $time, $islocal) = @_;
97 $class = eval { (ref $class) && (ref $class)->isa('Time::Piece') }
101 $time->[c_epoch] = undef;
102 return wantarray ? @$time : bless [@$time[0..9], $islocal], $class;
105 my @time = $islocal ?
106 CORE::localtime($time)
109 wantarray ? @time : bless [@time, $time, $islocal], $class;
112 my %_special_exports = (
113 localtime => sub { my $c = $_[0]; sub { $c->localtime(@_) } },
114 gmtime => sub { my $c = $_[0]; sub { $c->gmtime(@_) } },
118 my ($class, $to, @methods) = @_;
119 for my $method (@methods) {
120 if (exists $_special_exports{$method}) {
122 no warnings 'redefine';
123 *{$to . "::$method"} = $_special_exports{$method}->($class);
125 $class->SUPER::export($to, $method);
131 # replace CORE::GLOBAL localtime and gmtime if required
134 map($params{$_}++,@_,@EXPORT);
135 if (delete $params{':override'}) {
136 $class->export('CORE::GLOBAL', keys %params);
139 $class->export((caller)[0], keys %params);
169 *day_of_month = \&mday;
184 return $_[$time->[c_mon]];
187 return $MON_LIST[$time->[c_mon]];
190 return $time->strftime('%b');
199 return $_[$time->[c_mon]];
201 elsif (@FULLMON_LIST) {
202 return $FULLMON_LIST[$time->[c_mon]];
205 return $time->strftime('%B');
211 $time->[c_year] + 1900;
221 my $res = $time->[c_year] % 100;
222 return $res > 9 ? $res : "0$res";
235 *day_of_week = \&_wday;
240 return $_[$time->[c_wday]];
243 return $DAY_LIST[$time->[c_wday]];
246 return $time->strftime('%a');
255 return $_[$time->[c_wday]];
257 elsif (@FULLDAY_LIST) {
258 return $FULLDAY_LIST[$time->[c_wday]];
261 return $time->strftime('%A');
270 *day_of_year = \&yday;
277 *daylight_savings = \&isdst;
279 # Thanks to Tony Olekshy <olekshy@cs.ualberta.ca> for this algorithm
283 return Time::Seconds->new(0) unless $time->[c_islocal];
285 my $epoch = $time->epoch;
289 my ($s,$n,$h,$d,$m,$y) = @_; $m += 1; $y += 1900;
291 $time->_jd($y, $m, $d, $h, $n, $s);
295 # Compute floating offset in hours.
297 # Note use of crt methods so the tz is properly set...
298 # See: http://perlmonks.org/?node_id=820347
299 my $delta = 24 * ($j->(_crt_localtime($epoch)) - $j->(_crt_gmtime($epoch)));
301 # Return value in seconds rounded to nearest minute.
302 return Time::Seconds->new( int($delta * 60 + ($delta >= 0 ? 0.5 : -0.5)) * 60 );
307 if (defined($time->[c_epoch])) {
308 return $time->[c_epoch];
311 my $epoch = $time->[c_islocal] ?
312 timelocal(@{$time}[c_sec .. c_mon], $time->[c_year]+1900)
314 timegm(@{$time}[c_sec .. c_mon], $time->[c_year]+1900);
315 $time->[c_epoch] = $epoch;
322 my $sep = @_ ? shift(@_) : $TIME_SEP;
323 sprintf("%02d$sep%02d$sep%02d", $time->[c_hour], $time->[c_min], $time->[c_sec]);
330 my $sep = @_ ? shift(@_) : $DATE_SEP;
331 sprintf("%d$sep%02d$sep%02d", $time->year, $time->mon, $time->[c_mday]);
338 my $sep = @_ ? shift(@_) : $DATE_SEP;
339 sprintf("%02d$sep%02d$sep%d", $time->mon, $time->[c_mday], $time->year);
344 my $sep = @_ ? shift(@_) : $DATE_SEP;
345 sprintf("%02d$sep%02d$sep%d", $time->[c_mday], $time->mon, $time->year);
350 my %seps = (date => $DATE_SEP, T => 'T', time => $TIME_SEP, @_);
351 return join($seps{T}, $time->date($seps{date}), $time->time($seps{time}));
356 # Julian Day is always calculated for UT regardless
360 # Correct for localtime
361 $time = $time->gmtime( $time->epoch ) if $time->[c_islocal];
363 # Calculate the Julian day itself
364 my $jd = $time->_jd( $time->year, $time->mon, $time->mday,
365 $time->hour, $time->min, $time->sec);
370 # MJD is defined as JD - 2400000.5 days
372 return shift->julian_day - 2_400_000.5;
375 # Internal calculation of Julian date. Needed here so that
376 # both tzoffset and mjd/jd methods can share the code
377 # Algorithm from Hatcher 1984 (QJRAS 25, 53-55), and
378 # Hughes et al, 1989, MNRAS, 238, 15
379 # See: http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode=1989MNRAS.238.1529H&db_key=AST
384 my ($y, $m, $d, $h, $n, $s) = @_;
386 # Adjust input parameters according to the month
387 $y = ( $m > 2 ? $y : $y - 1);
388 $m = ( $m > 2 ? $m - 3 : $m + 9);
390 # Calculate the Julian Date (assuming Julian calendar)
391 my $J = int( 365.25 *( $y + 4712) )
392 + int( (30.6 * $m) + 0.5)
397 # Calculate the Gregorian Correction (since we have Gregorian dates)
398 my $G = 38 - int( 0.75 * int(49+($y/100)));
400 # Calculate the actual Julian Date
403 # Modify to include hours/mins/secs in floating portion.
404 return $JD + ($h + ($n + $s / 60) / 60) / 24;
410 my $J = $self->julian_day;
411 # Julian day is independent of time zone so add on tzoffset
412 # if we are using local time here since we want the week day
413 # to reflect the local time rather than UTC
414 $J += ($self->tzoffset/(24*3600)) if $self->[c_islocal];
416 # Now that we have the Julian day including fractions
417 # convert it to an integer Julian Day Number using nearest
418 # int (since the day changes at midday we oconvert all Julian
419 # dates to following midnight).
423 my $d4 = ((($J + 31741 - ($J % 7)) % 146097) % 36524) % 1461;
425 my $d1 = (($d4 - $L) % 365) + $L;
431 return (($year %4 == 0) && !($year % 100 == 0)) || ($year % 400 == 0)
437 my $year = $time->year;
438 return _is_leap_year($year);
441 my @MON_LAST = qw(31 28 31 30 31 30 31 31 30 31 30 31);
445 my $year = $time->year;
446 my $_mon = $time->_mon;
447 return $MON_LAST[$_mon] + ($_mon == 1 ? _is_leap_year($year) : 0);
452 my $tzname = $time->[c_islocal] ? '%Z' : 'UTC';
453 my $format = @_ ? shift(@_) : "%a, %d %b %Y %H:%M:%S $tzname";
454 if (!defined $time->[c_wday]) {
455 if ($time->[c_islocal]) {
456 return _strftime($format, CORE::localtime($time->epoch));
459 return _strftime($format, CORE::gmtime($time->epoch));
462 return _strftime($format, (@$time)[c_sec..c_isdst]);
468 my $format = @_ ? shift(@_) : "%a, %d %b %Y %H:%M:%S %Z";
469 my @vals = _strptime($string, $format);
470 # warn(sprintf("got vals: %d-%d-%d %d:%d:%d\n", reverse(@vals)));
471 return scalar $time->_mktime(\@vals, (ref($time) ? $time->[c_islocal] : 0));
475 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method
484 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method
493 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__);
502 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__);
510 use overload '""' => \&cdate,
511 'cmp' => \&str_compare,
516 if ($time->[c_islocal]) {
517 return scalar(CORE::localtime($time->epoch));
520 return scalar(CORE::gmtime($time->epoch));
525 my ($lhs, $rhs, $reverse) = @_;
526 if (UNIVERSAL::isa($rhs, 'Time::Piece')) {
529 return $reverse ? $rhs cmp $lhs->cdate : $lhs->cdate cmp $rhs;
539 if (UNIVERSAL::isa($rhs, 'Time::Seconds')) {
540 $rhs = $rhs->seconds;
545 # SWAPED is set (so someone tried an expression like NOTDATE - DATE).
546 # Imitate Perl's standard behavior and return the result as if the
547 # string $time resolves to was subtracted from NOTDATE. This way,
548 # classes which override this one and which have a stringify function
549 # that resolves to something that looks more like a number don't need
550 # to override this function.
551 return $rhs - "$time";
554 if (UNIVERSAL::isa($rhs, 'Time::Piece')) {
555 return Time::Seconds->new($time->epoch - $rhs->epoch);
559 return $time->_mktime(($time->epoch - $rhs), $time->[c_islocal]);
566 if (UNIVERSAL::isa($rhs, 'Time::Seconds')) {
567 $rhs = $rhs->seconds;
569 croak "Invalid rhs of addition: $rhs" if ref($rhs);
571 return $time->_mktime(($time->epoch + $rhs), $time->[c_islocal]);
578 my ($lhs, $rhs, $reverse) = @_;
579 if (!UNIVERSAL::isa($rhs, 'Time::Piece')) {
580 $rhs = $lhs->new($rhs);
583 return $rhs->epoch, $lhs->epoch;
585 return $lhs->epoch, $rhs->epoch;
589 my ($lhs, $rhs) = get_epochs(@_);
590 return $lhs <=> $rhs;
594 my ($time, $num_months) = @_;
596 croak("add_months requires a number of months") unless defined($num_months);
598 my $final_month = $time->_mon + $num_months;
600 if ($final_month > 11 || $final_month < 0) {
601 # these two ops required because we have no POSIX::floor and don't
602 # want to load POSIX.pm
603 if ($final_month < 0 && $final_month % 12 == 0) {
604 $num_years = int($final_month / 12) + 1;
607 $num_years = int($final_month / 12);
609 $num_years-- if ($final_month < 0);
611 $final_month = $final_month % 12;
614 my @vals = _mini_mktime($time->sec, $time->min, $time->hour,
615 $time->mday, $final_month, $time->year - 1900 + $num_years);
616 # warn(sprintf("got %d vals: %d-%d-%d %d:%d:%d [%d]\n", scalar(@vals), reverse(@vals), $time->[c_islocal]));
617 return scalar $time->_mktime(\@vals, $time->[c_islocal]);
621 my ($time, $years) = @_;
622 $time->add_months($years * 12);
630 Time::Piece - Object Oriented time objects
637 print "Time is $t\n";
638 print "Year is ", $t->year, "\n";
642 This module replaces the standard localtime and gmtime functions with
643 implementations that return objects. It does so in a backwards
644 compatible manner, so that using localtime/gmtime in the way documented
645 in perlfunc will still return what you expect.
647 The module actually implements most of an interface described by
648 Larry Wall on the perl5-porters mailing list here:
649 http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2000-01/msg00241.html
653 After importing this module, when you use localtime or gmtime in a scalar
654 context, rather than getting an ordinary scalar string representing the
655 date and time, you get a Time::Piece object, whose stringification happens
656 to produce the same effect as the localtime and gmtime functions. There is
657 also a new() constructor provided, which is the same as localtime(), except
658 when passed a Time::Piece object, in which case it's a copy constructor. The
659 following methods are available on the object:
661 $t->sec # also available as $t->second
662 $t->min # also available as $t->minute
664 $t->mday # also available as $t->day_of_month
665 $t->mon # 1 = January
666 $t->_mon # 0 = January
668 $t->month # same as $t->monname
669 $t->fullmonth # February
670 $t->year # based at 0 (year 0 AD is, of course 1 BC)
671 $t->_year # year minus 1900
672 $t->yy # 2 digit year
673 $t->wday # 1 = Sunday
674 $t->_wday # 0 = Sunday
675 $t->day_of_week # 0 = Sunday
677 $t->day # same as wdayname
678 $t->fullday # Tuesday
679 $t->yday # also available as $t->day_of_year, 0 = Jan 01
680 $t->isdst # also available as $t->daylight_savings
683 $t->hms(".") # 12.34.56
684 $t->time # same as $t->hms
687 $t->date # same as $t->ymd
689 $t->mdy("/") # 02/29/2000
691 $t->dmy(".") # 29.02.2000
692 $t->datetime # 2000-02-29T12:34:56 (ISO 8601)
693 $t->cdate # Tue Feb 29 12:34:56 2000
694 "$t" # same as $t->cdate
696 $t->epoch # seconds since the epoch
697 $t->tzoffset # timezone offset in a Time::Seconds object
699 $t->julian_day # number of days since Julian period began
700 $t->mjd # modified Julian date (JD-2400000.5 days)
702 $t->week # week number (ISO 8601)
704 $t->is_leap_year # true if it its
705 $t->month_last_day # 28-31
707 $t->time_separator($s) # set the default separator (default ":")
708 $t->date_separator($s) # set the default separator (default "-")
709 $t->day_list(@days) # set the default weekdays
710 $t->mon_list(@days) # set the default months
712 $t->strftime(FORMAT) # same as POSIX::strftime (without the overhead
713 # of the full POSIX extension)
714 $t->strftime() # "Tue, 29 Feb 2000 12:34:56 GMT"
716 Time::Piece->strptime(STRING, FORMAT)
717 # see strptime man page. Creates a new
722 Both wdayname (day) and monname (month) allow passing in a list to use
723 to index the name of the days against. This can be useful if you need
724 to implement some form of localisation without actually installing or
727 my @days = qw( Dimanche Lundi Merdi Mercredi Jeudi Vendredi Samedi );
729 my $french_day = localtime->day(@days);
731 These settings can be overriden globally too:
733 Time::Piece::day_list(@days);
737 Time::Piece::mon_list(@months);
739 And locally for months:
741 print localtime->month(@months);
743 =head2 Date Calculations
745 It's possible to use simple addition and subtraction of objects:
749 my $seconds = $t1 - $t2;
750 $t1 += ONE_DAY; # add 1 day (constant from Time::Seconds)
752 The following are valid ($t1 and $t2 are Time::Piece objects):
754 $t1 - $t2; # returns Time::Seconds object
755 $t1 - 42; # returns Time::Piece object
756 $t1 + 533; # returns Time::Piece object
758 However adding a Time::Piece object to another Time::Piece object
759 will cause a runtime error.
761 Note that the first of the above returns a Time::Seconds object, so
762 while examining the object will print the number of seconds (because
763 of the overloading), you can also get the number of minutes, hours,
764 days, weeks and years in that delta, using the Time::Seconds API.
766 In addition to adding seconds, there are two APIs for adding months and
772 The months and years can be negative for subtractions. Note that there
773 is some "strange" behaviour when adding and subtracting months at the
774 ends of months. Generally when the resulting month is shorter than the
775 starting month then the number of overlap days is added. For example
776 subtracting a month from 2008-03-31 will not result in 2008-02-31 as this
777 is an impossible date. Instead you will get 2008-03-02. This appears to
778 be consistent with other date manipulation tools.
780 =head2 Date Comparisons
782 Date comparisons are also possible, using the full suite of "<", ">",
783 "<=", ">=", "<=>", "==" and "!=".
787 Time::Piece has a built-in strptime() function (from FreeBSD), allowing
788 you incredibly flexible date parsing routines. For example:
790 my $t = Time::Piece->strptime("Sunday 3rd Nov, 1943",
793 print $t->strftime("%a, %d %b %Y");
799 (see, it's even smart enough to fix my obvious date bug)
801 For more information see "man strptime", which should be on all unix
804 Alternatively look here: http://www.unix.com/man-page/FreeBSD/3/strftime/
806 =head2 YYYY-MM-DDThh:mm:ss
808 The ISO 8601 standard defines the date format to be YYYY-MM-DD, and
809 the time format to be hh:mm:ss (24 hour clock), and if combined, they
810 should be concatenated with date first and with a capital 'T' in front
815 The I<week number> may be an unknown concept to some readers. The ISO
816 8601 standard defines that weeks begin on a Monday and week 1 of the
817 year is the week that includes both January 4th and the first Thursday
818 of the year. In other words, if the first Monday of January is the
819 2nd, 3rd, or 4th, the preceding days of the January are part of the
820 last week of the preceding year. Week numbers range from 1 to 53.
822 =head2 Global Overriding
824 Finally, it's possible to override localtime and gmtime everywhere, by
825 including the ':override' tag in the import list:
827 use Time::Piece ':override';
831 =head2 Setting $ENV{TZ} in Threads on Win32
833 Note that when using perl in the default build configuration on Win32
834 (specifically, when perl is built with PERL_IMPLICIT_SYS), each perl
835 interpreter maintains its own copy of the environment and only the main
836 interpreter will update the process environment seen by strftime.
838 Therefore, if you make changes to $ENV{TZ} from inside a thread other than
839 the main thread then those changes will not be seen by strftime if you
840 subsequently call that with the %Z formatting code. You must change $ENV{TZ}
841 in the main thread to have the desired effect in this case (and you must
842 also call _tzset() in the main thread to register the environment change).
844 Furthermore, remember that this caveat also applies to fork(), which is
845 emulated by threads on Win32.
847 =head2 Use of epoch seconds
849 This module internally uses the epoch seconds system that is provided via
850 the perl C<time()> function and supported by C<gmtime()> and C<localtime()>.
852 If your perl does not support times larger than C<2^31> seconds then this
853 module is likely to fail at processing dates beyond the year 2038. There are
854 moves afoot to fix that in perl. Alternatively use 64 bit perl. Or if none
855 of those are options, use the L<DateTime> module which has support for years
856 well into the future and past.
860 Matt Sergeant, matt@sergeant.org
861 Jarkko Hietaniemi, jhi@iki.fi (while creating Time::Piece for core perl)
865 This module is free software, you may distribute it under the same terms
870 The excellent Calendar FAQ at http://www.tondering.dk/claus/calendar.html
874 The test harness leaves much to be desired. Patches welcome.