Commit | Line | Data |
16433e2b |
1 | # $Id: Piece.pm 70 2006-09-07 17:43:38Z matt $ |
2 | |
3 | package Time::Piece; |
4 | |
5 | use strict; |
6 | |
7 | require Exporter; |
8 | require DynaLoader; |
9 | use Time::Seconds; |
10 | use Carp; |
11 | use Time::Local; |
12 | use UNIVERSAL qw(isa); |
13 | |
14 | our @ISA = qw(Exporter DynaLoader); |
15 | |
16 | our @EXPORT = qw( |
17 | localtime |
18 | gmtime |
19 | ); |
20 | |
21 | our %EXPORT_TAGS = ( |
22 | ':override' => 'internal', |
23 | ); |
24 | |
be8a15fc |
25 | our $VERSION = '1.11_03'; |
16433e2b |
26 | |
27 | bootstrap Time::Piece $VERSION; |
28 | |
29 | my $DATE_SEP = '-'; |
30 | my $TIME_SEP = ':'; |
31 | my @MON_LIST = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); |
32 | my @FULLMON_LIST = qw(January February March April May June July |
33 | August September October November December); |
34 | my @DAY_LIST = qw(Sun Mon Tue Wed Thu Fri Sat); |
35 | my @FULLDAY_LIST = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday); |
36 | |
37 | use constant 'c_sec' => 0; |
38 | use constant 'c_min' => 1; |
39 | use constant 'c_hour' => 2; |
40 | use constant 'c_mday' => 3; |
41 | use constant 'c_mon' => 4; |
42 | use constant 'c_year' => 5; |
43 | use constant 'c_wday' => 6; |
44 | use constant 'c_yday' => 7; |
45 | use constant 'c_isdst' => 8; |
46 | use constant 'c_epoch' => 9; |
47 | use constant 'c_islocal' => 10; |
48 | |
49 | sub localtime { |
50 | unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') }; |
51 | my $class = shift; |
52 | my $time = shift; |
53 | $time = time if (!defined $time); |
54 | $class->_mktime($time, 1); |
55 | } |
56 | |
57 | sub gmtime { |
58 | unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') }; |
59 | my $class = shift; |
60 | my $time = shift; |
61 | $time = time if (!defined $time); |
62 | $class->_mktime($time, 0); |
63 | } |
64 | |
65 | sub new { |
66 | my $class = shift; |
67 | my ($time) = @_; |
68 | |
69 | my $self; |
70 | |
71 | if (defined($time)) { |
72 | $self = $class->localtime($time); |
73 | } |
74 | elsif (ref($class) && $class->isa(__PACKAGE__)) { |
75 | $self = $class->_mktime($class->epoch, $class->[c_islocal]); |
76 | } |
77 | else { |
78 | $self = $class->localtime(); |
79 | } |
80 | |
81 | return bless $self, $class; |
82 | } |
83 | |
84 | sub parse { |
85 | my $proto = shift; |
86 | my $class = ref($proto) || $proto; |
87 | my @components; |
88 | if (@_ > 1) { |
89 | @components = @_; |
90 | } |
91 | else { |
92 | @components = shift =~ /(\d+)$DATE_SEP(\d+)$DATE_SEP(\d+)(?:(?:T|\s+)(\d+)$TIME_SEP(\d+)(?:$TIME_SEP(\d+)))/; |
93 | @components = reverse(@components[0..5]); |
94 | } |
95 | return $class->new(_strftime("%s", @components)); |
96 | } |
97 | |
98 | sub _mktime { |
99 | my ($class, $time, $islocal) = @_; |
100 | $class = eval { (ref $class) && (ref $class)->isa('Time::Piece') } |
101 | ? ref $class |
102 | : $class; |
103 | if (ref($time)) { |
104 | $time->[c_epoch] = undef; |
105 | return wantarray ? @$time : bless [@$time, $islocal], $class; |
106 | } |
107 | _tzset(); |
108 | my @time = $islocal ? |
109 | CORE::localtime($time) |
110 | : |
111 | CORE::gmtime($time); |
112 | wantarray ? @time : bless [@time, $time, $islocal], $class; |
113 | } |
114 | |
115 | my %_special_exports = ( |
116 | localtime => sub { my $c = $_[0]; sub { $c->localtime(@_) } }, |
117 | gmtime => sub { my $c = $_[0]; sub { $c->gmtime(@_) } }, |
118 | ); |
119 | |
120 | sub export { |
121 | my ($class, $to, @methods) = @_; |
122 | for my $method (@methods) { |
123 | if (exists $_special_exports{$method}) { |
124 | no strict 'refs'; |
125 | no warnings 'redefine'; |
126 | *{$to . "::$method"} = $_special_exports{$method}->($class); |
127 | } else { |
128 | $class->SUPER::export($to, $method); |
129 | } |
130 | } |
131 | } |
132 | |
133 | sub import { |
134 | # replace CORE::GLOBAL localtime and gmtime if required |
135 | my $class = shift; |
136 | my %params; |
137 | map($params{$_}++,@_,@EXPORT); |
138 | if (delete $params{':override'}) { |
139 | $class->export('CORE::GLOBAL', keys %params); |
140 | } |
141 | else { |
142 | $class->export((caller)[0], keys %params); |
143 | } |
144 | } |
145 | |
146 | ## Methods ## |
147 | |
148 | sub sec { |
149 | my $time = shift; |
150 | $time->[c_sec]; |
151 | } |
152 | |
153 | *second = \&sec; |
154 | |
155 | sub min { |
156 | my $time = shift; |
157 | $time->[c_min]; |
158 | } |
159 | |
160 | *minute = \&min; |
161 | |
162 | sub hour { |
163 | my $time = shift; |
164 | $time->[c_hour]; |
165 | } |
166 | |
167 | sub mday { |
168 | my $time = shift; |
169 | $time->[c_mday]; |
170 | } |
171 | |
172 | *day_of_month = \&mday; |
173 | |
174 | sub mon { |
175 | my $time = shift; |
176 | $time->[c_mon] + 1; |
177 | } |
178 | |
179 | sub _mon { |
180 | my $time = shift; |
181 | $time->[c_mon]; |
182 | } |
183 | |
184 | sub month { |
185 | my $time = shift; |
186 | if (@_) { |
187 | return $_[$time->[c_mon]]; |
188 | } |
189 | elsif (@MON_LIST) { |
190 | return $MON_LIST[$time->[c_mon]]; |
191 | } |
192 | else { |
193 | return $time->strftime('%b'); |
194 | } |
195 | } |
196 | |
197 | *monname = \&month; |
198 | |
199 | sub fullmonth { |
200 | my $time = shift; |
201 | if (@_) { |
202 | return $_[$time->[c_mon]]; |
203 | } |
204 | elsif (@FULLMON_LIST) { |
205 | return $FULLMON_LIST[$time->[c_mon]]; |
206 | } |
207 | else { |
208 | return $time->strftime('%B'); |
209 | } |
210 | } |
211 | |
212 | sub year { |
213 | my $time = shift; |
214 | $time->[c_year] + 1900; |
215 | } |
216 | |
217 | sub _year { |
218 | my $time = shift; |
219 | $time->[c_year]; |
220 | } |
221 | |
222 | sub yy { |
223 | my $time = shift; |
224 | my $res = $time->[c_year] % 100; |
225 | return $res > 9 ? $res : "0$res"; |
226 | } |
227 | |
228 | sub wday { |
229 | my $time = shift; |
230 | $time->[c_wday] + 1; |
231 | } |
232 | |
233 | sub _wday { |
234 | my $time = shift; |
235 | $time->[c_wday]; |
236 | } |
237 | |
238 | *day_of_week = \&_wday; |
239 | |
240 | sub wdayname { |
241 | my $time = shift; |
242 | if (@_) { |
243 | return $_[$time->[c_wday]]; |
244 | } |
245 | elsif (@DAY_LIST) { |
246 | return $DAY_LIST[$time->[c_wday]]; |
247 | } |
248 | else { |
249 | return $time->strftime('%a'); |
250 | } |
251 | } |
252 | |
253 | *day = \&wdayname; |
254 | |
255 | sub fullday { |
256 | my $time = shift; |
257 | if (@_) { |
258 | return $_[$time->[c_wday]]; |
259 | } |
260 | elsif (@FULLDAY_LIST) { |
261 | return $FULLDAY_LIST[$time->[c_wday]]; |
262 | } |
263 | else { |
264 | return $time->strftime('%A'); |
265 | } |
266 | } |
267 | |
268 | sub yday { |
269 | my $time = shift; |
270 | $time->[c_yday]; |
271 | } |
272 | |
273 | *day_of_year = \&yday; |
274 | |
275 | sub isdst { |
276 | my $time = shift; |
277 | $time->[c_isdst]; |
278 | } |
279 | |
280 | *daylight_savings = \&isdst; |
281 | |
282 | # Thanks to Tony Olekshy <olekshy@cs.ualberta.ca> for this algorithm |
283 | sub tzoffset { |
284 | my $time = shift; |
285 | |
286 | return Time::Seconds->new(0) unless $time->[c_islocal]; |
287 | |
288 | my $epoch = $time->epoch; |
289 | |
290 | my $j = sub { |
291 | |
292 | my ($s,$n,$h,$d,$m,$y) = @_; $m += 1; $y += 1900; |
293 | |
294 | $time->_jd($y, $m, $d, $h, $n, $s); |
295 | |
296 | }; |
297 | |
298 | # Compute floating offset in hours. |
299 | # |
300 | my $delta = 24 * (&$j(CORE::localtime $epoch) - &$j(CORE::gmtime $epoch)); |
301 | |
302 | # Return value in seconds rounded to nearest minute. |
303 | return Time::Seconds->new( int($delta * 60 + ($delta >= 0 ? 0.5 : -0.5)) * 60 ); |
304 | } |
305 | |
306 | sub epoch { |
307 | my $time = shift; |
308 | if (defined($time->[c_epoch])) { |
309 | return $time->[c_epoch]; |
310 | } |
311 | else { |
312 | my $epoch = $time->[c_islocal] ? |
313 | timelocal(@{$time}[c_sec .. c_mon], $time->[c_year]+1900) |
314 | : |
315 | timegm(@{$time}[c_sec .. c_mon], $time->[c_year]+1900); |
316 | $time->[c_epoch] = $epoch; |
317 | return $epoch; |
318 | } |
319 | } |
320 | |
321 | sub hms { |
322 | my $time = shift; |
323 | my $sep = @_ ? shift(@_) : $TIME_SEP; |
324 | sprintf("%02d$sep%02d$sep%02d", $time->[c_hour], $time->[c_min], $time->[c_sec]); |
325 | } |
326 | |
327 | *time = \&hms; |
328 | |
329 | sub ymd { |
330 | my $time = shift; |
331 | my $sep = @_ ? shift(@_) : $DATE_SEP; |
332 | sprintf("%d$sep%02d$sep%02d", $time->year, $time->mon, $time->[c_mday]); |
333 | } |
334 | |
335 | *date = \&ymd; |
336 | |
337 | sub mdy { |
338 | my $time = shift; |
339 | my $sep = @_ ? shift(@_) : $DATE_SEP; |
340 | sprintf("%02d$sep%02d$sep%d", $time->mon, $time->[c_mday], $time->year); |
341 | } |
342 | |
343 | sub dmy { |
344 | my $time = shift; |
345 | my $sep = @_ ? shift(@_) : $DATE_SEP; |
346 | sprintf("%02d$sep%02d$sep%d", $time->[c_mday], $time->mon, $time->year); |
347 | } |
348 | |
349 | sub datetime { |
350 | my $time = shift; |
351 | my %seps = (date => $DATE_SEP, T => 'T', time => $TIME_SEP, @_); |
352 | return join($seps{T}, $time->date($seps{date}), $time->time($seps{time})); |
353 | } |
354 | |
355 | |
356 | |
357 | # Julian Day is always calculated for UT regardless |
358 | # of local time |
359 | sub julian_day { |
360 | my $time = shift; |
361 | # Correct for localtime |
362 | $time = $time->gmtime( $time->epoch ) if $time->[c_islocal]; |
363 | |
364 | # Calculate the Julian day itself |
365 | my $jd = $time->_jd( $time->year, $time->mon, $time->mday, |
366 | $time->hour, $time->min, $time->sec); |
367 | |
368 | return $jd; |
369 | } |
370 | |
371 | # MJD is defined as JD - 2400000.5 days |
372 | sub mjd { |
373 | return shift->julian_day - 2_400_000.5; |
374 | } |
375 | |
376 | # Internal calculation of Julian date. Needed here so that |
377 | # both tzoffset and mjd/jd methods can share the code |
378 | # Algorithm from Hatcher 1984 (QJRAS 25, 53-55), and |
379 | # Hughes et al, 1989, MNRAS, 238, 15 |
380 | # See: http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode=1989MNRAS.238.1529H&db_key=AST |
381 | # for more details |
382 | |
383 | sub _jd { |
384 | my $self = shift; |
385 | my ($y, $m, $d, $h, $n, $s) = @_; |
386 | |
387 | # Adjust input parameters according to the month |
388 | $y = ( $m > 2 ? $y : $y - 1); |
389 | $m = ( $m > 2 ? $m - 3 : $m + 9); |
390 | |
391 | # Calculate the Julian Date (assuming Julian calendar) |
392 | my $J = int( 365.25 *( $y + 4712) ) |
393 | + int( (30.6 * $m) + 0.5) |
394 | + 59 |
395 | + $d |
396 | - 0.5; |
397 | |
398 | # Calculate the Gregorian Correction (since we have Gregorian dates) |
399 | my $G = 38 - int( 0.75 * int(49+($y/100))); |
400 | |
401 | # Calculate the actual Julian Date |
402 | my $JD = $J + $G; |
403 | |
404 | # Modify to include hours/mins/secs in floating portion. |
405 | return $JD + ($h + ($n + $s / 60) / 60) / 24; |
406 | } |
407 | |
408 | sub week { |
409 | my $self = shift; |
410 | |
411 | my $J = $self->julian_day; |
412 | # Julian day is independent of time zone so add on tzoffset |
413 | # if we are using local time here since we want the week day |
414 | # to reflect the local time rather than UTC |
415 | $J += ($self->tzoffset/(24*3600)) if $self->[c_islocal]; |
416 | |
417 | # Now that we have the Julian day including fractions |
418 | # convert it to an integer Julian Day Number using nearest |
419 | # int (since the day changes at midday we oconvert all Julian |
420 | # dates to following midnight). |
421 | $J = int($J+0.5); |
422 | |
423 | use integer; |
424 | my $d4 = ((($J + 31741 - ($J % 7)) % 146097) % 36524) % 1461; |
425 | my $L = $d4 / 1460; |
426 | my $d1 = (($d4 - $L) % 365) + $L; |
427 | return $d1 / 7 + 1; |
428 | } |
429 | |
430 | sub _is_leap_year { |
431 | my $year = shift; |
432 | return (($year %4 == 0) && !($year % 100 == 0)) || ($year % 400 == 0) |
433 | ? 1 : 0; |
434 | } |
435 | |
436 | sub is_leap_year { |
437 | my $time = shift; |
438 | my $year = $time->year; |
439 | return _is_leap_year($year); |
440 | } |
441 | |
442 | my @MON_LAST = qw(31 28 31 30 31 30 31 31 30 31 30 31); |
443 | |
444 | sub month_last_day { |
445 | my $time = shift; |
446 | my $year = $time->year; |
447 | my $_mon = $time->_mon; |
448 | return $MON_LAST[$_mon] + ($_mon == 1 ? _is_leap_year($year) : 0); |
449 | } |
450 | |
451 | sub strftime { |
452 | my $time = shift; |
453 | my $tzname = $time->[c_islocal] ? '%Z' : 'UTC'; |
454 | my $format = @_ ? shift(@_) : "%a, %d %b %Y %H:%M:%S $tzname"; |
455 | if (!defined $time->[c_wday]) { |
456 | if ($time->[c_islocal]) { |
457 | return _strftime($format, CORE::localtime($time->epoch)); |
458 | } |
459 | else { |
460 | return _strftime($format, CORE::gmtime($time->epoch)); |
461 | } |
462 | } |
463 | return _strftime($format, (@$time)[c_sec..c_isdst]); |
464 | } |
465 | |
466 | sub strptime { |
467 | my $time = shift; |
468 | my $string = shift; |
469 | my $format = @_ ? shift(@_) : "%a, %d %b %Y %H:%M:%S %Z"; |
470 | my @vals = _strptime($string, $format); |
471 | # warn(sprintf("got vals: %d-%d-%d %d:%d:%d\n", reverse(@vals))); |
472 | return scalar $time->_mktime(\@vals, (ref($time) ? $time->[c_islocal] : 0)); |
473 | } |
474 | |
475 | sub day_list { |
476 | shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method |
477 | my @old = @DAY_LIST; |
478 | if (@_) { |
479 | @DAY_LIST = @_; |
480 | } |
481 | return @old; |
482 | } |
483 | |
484 | sub mon_list { |
485 | shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method |
486 | my @old = @MON_LIST; |
487 | if (@_) { |
488 | @MON_LIST = @_; |
489 | } |
490 | return @old; |
491 | } |
492 | |
493 | sub time_separator { |
494 | shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); |
495 | my $old = $TIME_SEP; |
496 | if (@_) { |
497 | $TIME_SEP = $_[0]; |
498 | } |
499 | return $old; |
500 | } |
501 | |
502 | sub date_separator { |
503 | shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); |
504 | my $old = $DATE_SEP; |
505 | if (@_) { |
506 | $DATE_SEP = $_[0]; |
507 | } |
508 | return $old; |
509 | } |
510 | |
511 | use overload '""' => \&cdate, |
512 | 'cmp' => \&str_compare, |
513 | 'fallback' => undef; |
514 | |
515 | sub cdate { |
516 | my $time = shift; |
517 | if ($time->[c_islocal]) { |
518 | return scalar(CORE::localtime($time->epoch)); |
519 | } |
520 | else { |
521 | return scalar(CORE::gmtime($time->epoch)); |
522 | } |
523 | } |
524 | |
525 | sub str_compare { |
526 | my ($lhs, $rhs, $reverse) = @_; |
527 | if (UNIVERSAL::isa($rhs, 'Time::Piece')) { |
528 | $rhs = "$rhs"; |
529 | } |
530 | return $reverse ? $rhs cmp $lhs->cdate : $lhs->cdate cmp $rhs; |
531 | } |
532 | |
533 | use overload |
534 | '-' => \&subtract, |
535 | '+' => \&add; |
536 | |
537 | sub subtract { |
538 | my $time = shift; |
539 | my $rhs = shift; |
540 | if (UNIVERSAL::isa($rhs, 'Time::Seconds')) { |
541 | $rhs = $rhs->seconds; |
542 | } |
e3db0d81 |
543 | |
544 | if (shift) |
545 | { |
546 | # SWAPED is set (so someone tried an expression like NOTDATE - DATE). |
547 | # Imitate Perl's standard behavior and return the result as if the |
548 | # string $time resolves to was subtracted from NOTDATE. This way, |
549 | # classes which override this one and which have a stringify function |
550 | # that resolves to something that looks more like a number don't need |
551 | # to override this function. |
552 | return $rhs - "$time"; |
553 | } |
16433e2b |
554 | |
555 | if (UNIVERSAL::isa($rhs, 'Time::Piece')) { |
556 | return Time::Seconds->new($time->epoch - $rhs->epoch); |
557 | } |
558 | else { |
559 | # rhs is seconds. |
560 | return $time->_mktime(($time->epoch - $rhs), $time->[c_islocal]); |
561 | } |
562 | } |
563 | |
564 | sub add { |
565 | my $time = shift; |
566 | my $rhs = shift; |
567 | if (UNIVERSAL::isa($rhs, 'Time::Seconds')) { |
568 | $rhs = $rhs->seconds; |
569 | } |
570 | croak "Invalid rhs of addition: $rhs" if ref($rhs); |
571 | |
572 | return $time->_mktime(($time->epoch + $rhs), $time->[c_islocal]); |
573 | } |
574 | |
575 | use overload |
576 | '<=>' => \&compare; |
577 | |
578 | sub get_epochs { |
579 | my ($lhs, $rhs, $reverse) = @_; |
580 | if (!UNIVERSAL::isa($rhs, 'Time::Piece')) { |
581 | $rhs = $lhs->new($rhs); |
582 | } |
583 | if ($reverse) { |
584 | return $rhs->epoch, $lhs->epoch; |
585 | } |
586 | return $lhs->epoch, $rhs->epoch; |
587 | } |
588 | |
589 | sub compare { |
590 | my ($lhs, $rhs) = get_epochs(@_); |
591 | return $lhs <=> $rhs; |
592 | } |
593 | |
594 | 1; |
595 | __END__ |
596 | |
597 | =head1 NAME |
598 | |
599 | Time::Piece - Object Oriented time objects |
600 | |
601 | =head1 SYNOPSIS |
602 | |
603 | use Time::Piece; |
604 | |
605 | my $t = localtime; |
606 | print "Time is $t\n"; |
607 | print "Year is ", $t->year, "\n"; |
608 | |
609 | =head1 DESCRIPTION |
610 | |
611 | This module replaces the standard localtime and gmtime functions with |
612 | implementations that return objects. It does so in a backwards |
613 | compatible manner, so that using localtime/gmtime in the way documented |
614 | in perlfunc will still return what you expect. |
615 | |
616 | The module actually implements most of an interface described by |
617 | Larry Wall on the perl5-porters mailing list here: |
618 | http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2000-01/msg00241.html |
619 | |
620 | =head1 USAGE |
621 | |
622 | After importing this module, when you use localtime or gmtime in a scalar |
623 | context, rather than getting an ordinary scalar string representing the |
624 | date and time, you get a Time::Piece object, whose stringification happens |
625 | to produce the same effect as the localtime and gmtime functions. There is |
626 | also a new() constructor provided, which is the same as localtime(), except |
627 | when passed a Time::Piece object, in which case it's a copy constructor. The |
628 | following methods are available on the object: |
629 | |
630 | $t->sec # also available as $t->second |
631 | $t->min # also available as $t->minute |
632 | $t->hour # 24 hour |
633 | $t->mday # also available as $t->day_of_month |
634 | $t->mon # 1 = January |
635 | $t->_mon # 0 = January |
636 | $t->monname # Feb |
637 | $t->month # same as $t->monname |
638 | $t->fullmonth # February |
639 | $t->year # based at 0 (year 0 AD is, of course 1 BC) |
640 | $t->_year # year minus 1900 |
641 | $t->yy # 2 digit year |
642 | $t->wday # 1 = Sunday |
643 | $t->_wday # 0 = Sunday |
644 | $t->day_of_week # 0 = Sunday |
645 | $t->wdayname # Tue |
646 | $t->day # same as wdayname |
647 | $t->fullday # Tuesday |
648 | $t->yday # also available as $t->day_of_year, 0 = Jan 01 |
649 | $t->isdst # also available as $t->daylight_savings |
650 | |
651 | $t->hms # 12:34:56 |
652 | $t->hms(".") # 12.34.56 |
653 | $t->time # same as $t->hms |
654 | |
655 | $t->ymd # 2000-02-29 |
656 | $t->date # same as $t->ymd |
657 | $t->mdy # 02-29-2000 |
658 | $t->mdy("/") # 02/29/2000 |
659 | $t->dmy # 29-02-2000 |
660 | $t->dmy(".") # 29.02.2000 |
661 | $t->datetime # 2000-02-29T12:34:56 (ISO 8601) |
662 | $t->cdate # Tue Feb 29 12:34:56 2000 |
663 | "$t" # same as $t->cdate |
664 | |
665 | $t->epoch # seconds since the epoch |
666 | $t->tzoffset # timezone offset in a Time::Seconds object |
667 | |
668 | $t->julian_day # number of days since Julian period began |
669 | $t->mjd # modified Julian date (JD-2400000.5 days) |
670 | |
671 | $t->week # week number (ISO 8601) |
672 | |
673 | $t->is_leap_year # true if it its |
674 | $t->month_last_day # 28-31 |
675 | |
676 | $t->time_separator($s) # set the default separator (default ":") |
677 | $t->date_separator($s) # set the default separator (default "-") |
678 | $t->day_list(@days) # set the default weekdays |
679 | $t->mon_list(@days) # set the default months |
680 | |
681 | $t->strftime(FORMAT) # same as POSIX::strftime (without the overhead |
682 | # of the full POSIX extension) |
683 | $t->strftime() # "Tue, 29 Feb 2000 12:34:56 GMT" |
684 | |
685 | Time::Piece->strptime(STRING, FORMAT) |
686 | # see strptime man page. Creates a new |
687 | # Time::Piece object |
688 | |
689 | =head2 Local Locales |
690 | |
691 | Both wdayname (day) and monname (month) allow passing in a list to use |
692 | to index the name of the days against. This can be useful if you need |
693 | to implement some form of localisation without actually installing or |
694 | using locales. |
695 | |
696 | my @days = qw( Dimanche Lundi Merdi Mercredi Jeudi Vendredi Samedi ); |
697 | |
698 | my $french_day = localtime->day(@days); |
699 | |
700 | These settings can be overriden globally too: |
701 | |
702 | Time::Piece::day_list(@days); |
703 | |
704 | Or for months: |
705 | |
706 | Time::Piece::mon_list(@months); |
707 | |
708 | And locally for months: |
709 | |
710 | print localtime->month(@months); |
711 | |
712 | =head2 Date Calculations |
713 | |
714 | It's possible to use simple addition and subtraction of objects: |
715 | |
716 | use Time::Seconds; |
717 | |
718 | my $seconds = $t1 - $t2; |
719 | $t1 += ONE_DAY; # add 1 day (constant from Time::Seconds) |
720 | |
721 | The following are valid ($t1 and $t2 are Time::Piece objects): |
722 | |
723 | $t1 - $t2; # returns Time::Seconds object |
724 | $t1 - 42; # returns Time::Piece object |
725 | $t1 + 533; # returns Time::Piece object |
726 | |
727 | However adding a Time::Piece object to another Time::Piece object |
728 | will cause a runtime error. |
729 | |
730 | Note that the first of the above returns a Time::Seconds object, so |
731 | while examining the object will print the number of seconds (because |
732 | of the overloading), you can also get the number of minutes, hours, |
733 | days, weeks and years in that delta, using the Time::Seconds API. |
734 | |
735 | =head2 Date Comparisons |
736 | |
737 | Date comparisons are also possible, using the full suite of "<", ">", |
738 | "<=", ">=", "<=>", "==" and "!=". |
739 | |
740 | =head2 Date Parsing |
741 | |
742 | Time::Piece links to your C library's strptime() function, allowing |
743 | you incredibly flexible date parsing routines. For example: |
744 | |
745 | my $t = Time::Piece->strptime("Sun 3rd Nov, 1943", |
746 | "%A %drd %b, %Y"); |
747 | |
748 | print $t->strftime("%a, %d %b %Y"); |
749 | |
750 | Outputs: |
751 | |
752 | Wed, 03 Nov 1943 |
753 | |
754 | (see, it's even smart enough to fix my obvious date bug) |
755 | |
756 | For more information see "man strptime", which should be on all unix |
757 | systems. |
758 | |
759 | =head2 YYYY-MM-DDThh:mm:ss |
760 | |
761 | The ISO 8601 standard defines the date format to be YYYY-MM-DD, and |
762 | the time format to be hh:mm:ss (24 hour clock), and if combined, they |
763 | should be concatenated with date first and with a capital 'T' in front |
764 | of the time. |
765 | |
766 | =head2 Week Number |
767 | |
768 | The I<week number> may be an unknown concept to some readers. The ISO |
769 | 8601 standard defines that weeks begin on a Monday and week 1 of the |
770 | year is the week that includes both January 4th and the first Thursday |
771 | of the year. In other words, if the first Monday of January is the |
772 | 2nd, 3rd, or 4th, the preceding days of the January are part of the |
773 | last week of the preceding year. Week numbers range from 1 to 53. |
774 | |
775 | =head2 Global Overriding |
776 | |
777 | Finally, it's possible to override localtime and gmtime everywhere, by |
778 | including the ':override' tag in the import list: |
779 | |
780 | use Time::Piece ':override'; |
781 | |
782 | =head1 AUTHOR |
783 | |
784 | Matt Sergeant, matt@sergeant.org |
785 | Jarkko Hietaniemi, jhi@iki.fi (while creating Time::Piece for core perl) |
786 | |
787 | =head1 License |
788 | |
789 | This module is free software, you may distribute it under the same terms |
790 | as Perl. |
791 | |
792 | =head1 SEE ALSO |
793 | |
794 | The excellent Calendar FAQ at http://www.tondering.dk/claus/calendar.html |
795 | |
796 | =head1 BUGS |
797 | |
798 | The test harness leaves much to be desired. Patches welcome. |
799 | |
800 | =cut |