4 use vars qw($VERSION @ISA @EXPORT %EXPORT_TAGS);
11 @ISA = qw(Exporter DynaLoader);
19 ':override' => 'internal',
24 bootstrap Time::Piece $VERSION;
28 my @MON_NAMES = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
29 my @WDAY_NAMES = qw(Sun Mon Tue Wed Thu Fri Sat);
30 my @MONTH_NAMES = qw(January February March April May June
31 July August September October Novemeber December);
32 my @WEEKDAY_NAMES = qw(Sunday Monday Tuesday Wednesday
33 Thursday Friday Saturday);
35 use constant 'c_sec' => 0;
36 use constant 'c_min' => 1;
37 use constant 'c_hour' => 2;
38 use constant 'c_mday' => 3;
39 use constant 'c_mon' => 4;
40 use constant 'c_year' => 5;
41 use constant 'c_wday' => 6;
42 use constant 'c_yday' => 7;
43 use constant 'c_isdst' => 8;
44 use constant 'c_epoch' => 9;
45 use constant 'c_islocal' => 10;
49 $time = time if (!defined $time);
55 $time = time if (!defined $time);
61 my $class = ref($proto) || $proto;
67 $self = &localtime($time);
69 elsif (ref($proto) && $proto->isa('Time::Piece')) {
70 $self = _mktime($proto->[c_epoch], $proto->[c_islocal]);
76 return bless $self, $class;
80 my ($time, $islocal) = @_;
82 CORE::localtime($time)
85 wantarray ? @time : bless [@time, $time, $islocal], 'Time::Piece';
89 # replace CORE::GLOBAL localtime and gmtime if required
92 map($params{$_}++,@_,@EXPORT);
93 if (delete $params{':override'}) {
94 $class->export('CORE::GLOBAL', keys %params);
97 $class->export((caller)[0], keys %params);
151 return $_[$time->[c_mon]];
153 elsif ($time->has_mon_names) {
154 return $time->mon_name($time->[c_mon]);
156 return $MON_NAMES[$time->[c_mon]];
159 sub has_month_names {
167 return $_[$time->[c_mon]];
169 elsif ($time->has_month_names) {
170 return $time->month_name($time->[c_mon]);
172 return $MONTH_NAMES[$time->[c_mon]];
175 *month = \&monthname;
179 $time->[c_year] + 1900;
199 *day_of_week = \&_wday;
209 return $_[$time->[c_wday]];
211 elsif ($time->has_wday_names) {
212 return $time->wday_name($time->[c_mon]);
214 return $WDAY_NAMES[$time->[c_wday]];
217 sub has_weekday_names {
225 return $_[$time->[c_wday]];
227 elsif ($time->has_weekday_names) {
228 return $time->weekday_name($time->[c_mon]);
230 return $WEEKDAY_NAMES[$time->[c_wday]];
233 *weekdayname = \&weekdayname;
234 *weekday = \&weekdayname;
241 *day_of_year = \&yday;
248 *daylight_savings = \&isdst;
250 # Thanks to Tony Olekshy <olekshy@cs.ualberta.ca> for this algorithm
254 my $epoch = $time->[c_epoch];
256 my $j = sub { # Tweaked Julian day number algorithm.
258 my ($s,$n,$h,$d,$m,$y) = @_; $m += 1; $y += 1900;
260 # Standard Julian day number algorithm without constant.
262 my $y1 = $m > 2 ? $y : $y - 1;
264 my $m1 = $m > 2 ? $m + 1 : $m + 13;
266 my $day = int(365.25 * $y1) + int(30.6001 * $m1) + $d;
268 # Modify to include hours/mins/secs in floating portion.
270 return $day + ($h + ($n + $s / 60) / 60) / 24;
273 # Compute floating offset in hours.
275 my $delta = 24 * (&$j(CORE::localtime $epoch) - &$j(CORE::gmtime $epoch));
277 # Return value in seconds rounded to nearest minute.
278 return Time::Seconds->new( int($delta * 60 + ($delta >= 0 ? 0.5 : -0.5)) * 60);
288 my $sep = @_ ? shift(@_) : $TIME_SEP;
289 sprintf("%02d$sep%02d$sep%02d", $time->[c_hour], $time->[c_min], $time->[c_sec]);
296 my $sep = @_ ? shift(@_) : $DATE_SEP;
297 sprintf("%d$sep%02d$sep%02d", $time->year, $time->mon, $time->[c_mday]);
304 my $sep = @_ ? shift(@_) : $DATE_SEP;
305 sprintf("%02d$sep%02d$sep%d", $time->mon, $time->[c_mday], $time->year);
310 my $sep = @_ ? shift(@_) : $DATE_SEP;
311 sprintf("%02d$sep%02d$sep%d", $time->[c_mday], $time->mon, $time->year);
316 my %seps = (date => $DATE_SEP, T => 'T', time => $TIME_SEP, @_);
317 return join($seps{T}, $time->date($seps{date}), $time->time($seps{time}));
320 # taken from Time::JulianDay
323 my ($year, $month, $day) = ($time->year, $time->mon, $time->mday);
327 + 1461 * ( $year + 4800 - ( 14 - $month ) / 12 )/4
328 + 367 * ( $month - 2 + ( ( 14 - $month ) / 12 ) * 12 ) / 12
329 - 3 * ( ( $year + 4900 - ( 14 - $month ) / 12 ) / 100 ) / 4
337 return shift->julian_day - 2_400_000.5;
341 # taken from the Calendar FAQ
343 my $J = shift->julian_day;
344 my $d4 = ((($J + 31741 - ($J % 7)) % 146097) % 36524) % 1461;
346 my $d1 = (($d4 - $L) % 365) + $L;
352 return (($year %4 == 0) && !($year % 100 == 0)) || ($year % 400 == 0)
358 my $year = $time->year;
359 return _is_leap_year($year);
362 my @MON_LAST = qw(31 28 31 30 31 30 31 31 30 31 30 31);
366 my $year = $time->year;
367 my $_mon = $time->_mon;
368 return $MON_LAST[$_mon] + ($_mon == 1 ? _is_leap_year($year) : 0);
371 use vars qw($_ftime);
379 my ($format, $time) = @_;
383 my ($format, $time) = @_;
384 $time->weekdayname();
387 my ($format, $time) = @_;
391 my ($format, $time) = @_;
395 my ($format, $time) = @_;
399 my ($format, $time) = @_;
400 sprintf("%02d", int($time->y() / 100));
403 my ($format, $time) = @_;
404 sprintf("%02d", $time->d());
407 my ($format, $time) = @_;
409 $_ftime->{'m'}->('m', $time),
410 $_ftime->{'d'}->('d', $time),
411 $_ftime->{'y'}->('y', $time));
414 my ($format, $time) = @_;
415 sprintf("%2d", $time->d());
418 my ($format, $time, @rest) = @_;
419 $time->monname(@rest);
422 my ($format, $time) = @_;
423 sprintf("%02d", $time->h());
426 my ($format, $time) = @_;
428 sprintf("%02d", $h == 0 ? 12 : ($h < 13 ? $h : $h % 12));
431 my ($format, $time) = @_;
432 sprintf("%03d", $time->yday());
435 my ($format, $time) = @_;
436 sprintf("%02d", $time->mon());
439 my ($format, $time) = @_;
440 sprintf("%02d", $time->min());
446 my ($format, $time) = @_;
448 $h == 0 ? 'pm' : ($h < 13 ? 'am' : 'pm');
451 my ($format, $time) = @_;
453 $_ftime->{'I'}->('I', $time),
454 $_ftime->{'M'}->('M', $time),
455 $_ftime->{'S'}->('S', $time)) .
456 " " . $_ftime->{'p'}->('p', $time);
459 my ($format, $time) = @_;
461 $_ftime->{'H'}->('H', $time),
462 $_ftime->{'M'}->('M', $time));
465 my ($format, $time) = @_;
466 sprintf("%02d", $time->s());
472 my ($format, $time) = @_;
474 $_ftime->{'H'}->('H', $time),
475 $_ftime->{'M'}->('M', $time),
476 $_ftime->{'S'}->('S', $time));
479 my ($format, $time) = @_;
480 ($time->wday() + 5) % 7 + 1;
482 # U taken care by libc
484 my ($format, $time) = @_;
485 sprintf("%02d", $time->week());
488 my ($format, $time) = @_;
491 # W taken care by libc
493 my ($format, $time) = @_;
495 $_ftime->{'m'}->('m', $time),
496 $_ftime->{'d'}->('d', $time),
497 $_ftime->{'y'}->('y', $time));
500 my ($format, $time) = @_;
501 sprintf("%02d", $time->y() % 100);
504 my ($format, $time) = @_;
505 sprintf("%4d", $time->y());
507 # Z taken care by libc
512 exists $_ftime->{$format};
520 delete $_ftime->{@_};
524 my ($format) = $_[0];
526 return $_ftime->{$format};
528 if (ref $_[0] eq 'CODE') {
529 $_ftime->{$format} = $_[1];
532 Carp::croak "ftime: second argument not a code ref";
536 Carp::croak "ftime: want one or two arguments";
541 my ($format, $time, @rest) = @_;
542 if (has_ftime($format)) {
543 # We are passing format to the anonsubs so that
544 # one can share the same sub among several formats.
545 return $_ftime->{$format}->($format, $time, @rest);
547 # If we don't know it, pass it down to the libc layer.
548 # (In other words, cheat.)
549 # This pays for for '%Z', though, and for all the
550 # locale-specific %Ex and %Oy formats.
551 return $time->_strftime("%$format");
556 my $format = @_ ? shift(@_) : "%a, %d %b %Y %H:%M:%S %Z";
557 $format =~ s/%(.)/_ftime($1, $time, @_)/ge;
563 my $format = @_ ? shift(@_) : "%a, %d %b %Y %H:%M:%S %Z";
564 return __strftime($format, (@$time)[c_sec..c_isdst]);
567 use vars qw($_ptime);
572 $_[1] =~ s/^%// && $1;
580 $_[1] =~ s/^(0[0-9])// && $1;
583 $_[1] =~ s/^(0[1-9]|2[0-9]|3[01])// && $1;
588 if (defined ($D = $_ptime->{'m'}->($_[0], $_[1]))) {
593 $_[1] =~ s:^/:: || return;
594 if (defined ($D = $_ptime->{'d'}->($_[0], $_[1]))) {
599 $_[1] =~ s:^/:: || return;
600 if (defined ($D = $_ptime->{'y'}->($_[0], $_[1]))) {
608 $_[1] =~ s/^( [1-9]|2[0-9]|3[01])// && $1;
612 $_[1] =~ s/^([0-1][0-9]|2[0-3])// && $1;
615 $_[1] =~ s/^(0[1-9]|1[012])// && $1;
618 $_[1] =~ s/^([0-9][0-9][0-9])// && $1 >= 1 && $1 <= 366 && $1;
621 $_[1] =~ s/^(0[1-9]|1[012])// && $1;
624 $_[1] =~ s/^([0-5][0-9])// && $1;
627 $_[1] =~ s/^\n// && $1;
630 $_[1] =~ s/^(am|pm)// && $1;
635 if (defined ($r = $_ptime->{'I'}->($_[0], $_[1]))) {
640 $_[1] =~ s/^:// || return;
641 if (defined ($r = $_ptime->{'M'}->($_[0], $_[1]))) {
646 $_[1] =~ s/^:// || return;
647 if (defined ($r = $_ptime->{'S'}->($_[0], $_[1]))) {
652 $_[1] =~ s/^ // || return;
653 if (defined ($r = $_ptime->{'p'}->($_[0], $_[1]))) {
663 if (defined ($R = $_ptime->{'H'}->($_[0], $_[1]))) {
668 $_[1] =~ s/^:// || return;
669 if (defined ($R = $_ptime->{'M'}->($_[0], $_[1]))) {
677 $_[1] =~ s/^([0-5][0-9])// && $1;
680 $_[1] =~ s/^\t// && $1;
685 if (defined ($T = $_ptime->{'H'}->($_[0], $_[1]))) {
690 $_[1] =~ s/^:// || return;
691 if (defined ($T = $_ptime->{'M'}->($_[0], $_[1]))) {
696 $_[1] =~ s/^:// || return;
697 if (defined ($T = $_ptime->{'S'}->($_[0], $_[1]))) {
711 if (defined ($x = $_ptime->{'m'}->($_[0], $_[1]))) {
716 $_[1] =~ s:^/:: || return;
717 if (defined ($x = $_ptime->{'d'}->($_[0], $_[1]))) {
722 $_[1] =~ s:^/:: || return;
723 if (defined ($x = $_ptime->{'y'}->($_[0], $_[1]))) {
731 $_[1] =~ s/^([0-9][0-9])// && $1;
734 $_[1] =~ s/^([1-9][0-9][0-9][0-9])// && $1;
741 exists $_ptime->{$format};
749 delete $_ptime->{@_};
753 my ($format) = $_[0];
755 return $_ptime->{$format};
757 if (ref $_[0] eq 'CODE') {
758 $_ptime->{$format} = $_[1];
761 Carp::croak "ptime: second argument not a code ref";
765 Carp::croak "ptime: want one or two arguments";
770 my ($format, $stime) = @_;
771 if (has_ptime($format)) {
772 # We are passing format to the anonsubs so that
773 # one can share the same sub among several formats.
774 return $_ptime->{$format}->($format, $_[1]);
776 die "strptime: unknown format %$format (time '$stime')\n";
782 my $stime = @_ ? shift : "$time";
785 while ($format ne '') {
786 if ($format =~ s/^([^%]+)//) {
788 last unless $stime =~ s/^\Q$skip//;
790 while ($format =~ s/^%(.)//) {
792 my $t = _ptime($f, $stime);
794 if (ref $t eq 'HASH') {
795 @ptime{keys %$t} = values %$t;
807 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method
808 my @old = @WDAY_NAMES;
816 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method
817 my @old = @WEEKDAY_NAMES;
825 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method
826 my @old = @MON_NAMES;
834 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method
835 my @old = @MONTH_NAMES;
843 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__);
852 shift if ref($_[0]) && $_[0]->isa(__PACKAGE__);
860 use overload '""' => \&cdate;
864 if ($time->[c_islocal]) {
865 return scalar(CORE::localtime($time->[c_epoch]));
868 return scalar(CORE::gmtime($time->[c_epoch]));
879 die "Can't subtract a date from something!" if shift;
881 if (ref($rhs) && $rhs->isa('Time::Piece')) {
882 return Time::Seconds->new($time->[c_epoch] - $rhs->epoch);
886 return _mktime(($time->[c_epoch] - $rhs), $time->[c_islocal]);
894 croak "Invalid rhs of addition: $rhs" if ref($rhs);
896 return _mktime(($time->[c_epoch] + $rhs), $time->[c_islocal]);
903 my ($time, $rhs, $reverse) = @_;
904 $time = $time->epoch;
905 if (UNIVERSAL::isa($rhs, 'Time::Piece')) {
915 my ($lhs, $rhs) = get_epochs(@_);
916 return $lhs <=> $rhs;
924 Time::Piece - Object Oriented time objects
931 print "Time is $t\n";
932 print "Year is ", $t->year, "\n";
936 This module replaces the standard localtime and gmtime functions with
937 implementations that return objects. It does so in a backwards
938 compatible manner, so that using localtime/gmtime in the way documented
939 in perlfunc will still return what you expect.
941 The module actually implements most of an interface described by
942 Larry Wall on the perl5-porters mailing list here:
943 http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2000-01/msg00241.html
947 After importing this module, when you use localtime or gmtime in a scalar
948 context, rather than getting an ordinary scalar string representing the
949 date and time, you get a Time::Piece object, whose stringification happens
950 to produce the same effect as the localtime and gmtime functions. There is
951 also a new() constructor provided, which is the same as localtime(), except
952 when passed a Time::Piece object, in which case it's a copy constructor. The
953 following methods are available on the object:
956 # and 61: leap second and double leap second
957 $t->sec # same as $t->s
958 $t->second # same as $t->s
961 $t->hour # same as $t->h
963 $t->mday # same as $t->d
964 $t->mon # 1 = January
965 $t->_mon # 0 = January
967 $t->monthname # February
968 $t->month # same as $t->monthname
969 $t->y # based at 0 (year 0 AD is, of course 1 BC)
970 $t->year # same as $t->y
971 $t->_year # year minus 1900
972 $t->wday # 1 = Sunday
973 $t->day_of_week # 0 = Sunday
974 $t->_wday # 0 = Sunday
976 $t->weekdayname # Tuesday
977 $t->weekday # same as weekdayname
978 $t->yday # also available as $t->day_of_year, 0 = Jan 01
979 $t->isdst # also available as $t->daylight_savings
980 $t->daylight_savings # same as $t->isdst
983 $t->hms(".") # 12.34.56
984 $t->time # same as $t->hms
987 $t->date # same as $t->ymd
989 $t->mdy("/") # 02/29/2000
991 $t->dmy(".") # 29.02.2000
992 $t->datetime # 2000-02-29T12:34:56 (ISO 8601)
993 $t->cdate # Tue Feb 29 12:34:56 2000
994 "$t" # same as $t->cdate
996 $t->epoch # seconds since the epoch
997 $t->tzoffset # timezone offset in a Time::Seconds object
999 $t->julian_day # number of days since Julian period began
1000 $t->mjd # modified Julian day
1002 $t->week # week number (ISO 8601)
1004 $t->is_leap_year # true if it its
1005 $t->month_last_day # 28-31
1007 $t->time_separator($s) # set the default separator (default ":")
1008 $t->date_separator($s) # set the default separator (default "-")
1009 $t->wday(@days) # set the default weekdays, abbreviated
1010 $t->weekday_names(@days) # set the default weekdays
1011 $t->mon_names(@days) # set the default months, abbreviated
1012 $t->month_names(@days) # set the default months
1014 $t->strftime($format) # data and time formatting
1015 $t->strftime() # "Tue, 29 Feb 2000 12:34:56 GMT"
1017 $t->_strftime($format) # same as POSIX::strftime (without the
1018 # overhead of the full POSIX extension),
1019 # calls the operating system libraries,
1020 # as opposed to $t->strftime()
1022 =head2 Local Locales
1024 Both wdayname (day) and monname (month) allow passing in a list to use
1025 to index the name of the days against. This can be useful if you need
1026 to implement some form of localisation without actually installing or
1029 my @days = qw( Dimanche Lundi Merdi Mercredi Jeudi Vendredi Samedi );
1031 my $french_day = localtime->day(@days);
1033 These settings can be overriden globally too:
1035 Time::Piece::weekday_names(@days);
1039 Time::Piece::month_names(@months);
1041 And locally for months:
1043 print localtime->month(@months);
1045 =head2 Date Calculations
1047 It's possible to use simple addition and subtraction of objects:
1051 my $seconds = $t1 - $t2;
1052 $t1 += ONE_DAY; # add 1 day (constant from Time::Seconds)
1054 The following are valid ($t1 and $t2 are Time::Piece objects):
1056 $t1 - $t2; # returns Time::Seconds object
1057 $t1 - 42; # returns Time::Piece object
1058 $t1 + 533; # returns Time::Piece object
1060 However adding a Time::Piece object to another Time::Piece object
1061 will cause a runtime error.
1063 Note that the first of the above returns a Time::Seconds object, so
1064 while examining the object will print the number of seconds (because
1065 of the overloading), you can also get the number of minutes, hours,
1066 days, weeks and years in that delta, using the Time::Seconds API.
1068 =head2 Date Comparisons
1070 Date comparisons are also possible, using the full suite of "<", ">",
1071 "<=", ">=", "<=>", "==" and "!=".
1073 =head2 YYYY-MM-DDThh:mm:ss
1075 The ISO 8601 standard defines the date format to be YYYY-MM-DD, and
1076 the time format to be hh:mm:ss (24 hour clock), and if combined, they
1077 should be concatenated with date first and with a capital 'T' in front
1082 The I<week number> may be an unknown concept to some readers. The ISO
1083 8601 standard defines that weeks begin on a Monday and week 1 of the
1084 year is the week that includes both January 4th and the first Thursday
1085 of the year. In other words, if the first Monday of January is the
1086 2nd, 3rd, or 4th, the preceding days of the January are part of the
1087 last week of the preceding year. Week numbers range from 1 to 53.
1089 =head2 Global Overriding
1091 Finally, it's possible to override localtime and gmtime everywhere, by
1092 including the ':override' tag in the import list:
1094 use Time::Piece ':override';
1098 The excellent Calendar FAQ at http://www.tondering.dk/claus/calendar.html
1102 Matt Sergeant, matt@sergeant.org
1104 This module is based on Time::Object, with changes suggested by Jarkko
1105 Hietaniemi before including in core perl.
1109 This module is free software, you may distribute it under the same terms
1114 The test harness leaves much to be desired. Patches welcome.