Commit | Line | Data |
---|---|---|
16433e2b SP |
1 | package Time::Piece; |
2 | ||
3 | use strict; | |
4 | ||
5 | require Exporter; | |
6 | require DynaLoader; | |
7 | use Time::Seconds; | |
8 | use Carp; | |
9 | use Time::Local; | |
16433e2b SP |
10 | |
11 | our @ISA = qw(Exporter DynaLoader); | |
12 | ||
13 | our @EXPORT = qw( | |
14 | localtime | |
15 | gmtime | |
16 | ); | |
17 | ||
18 | our %EXPORT_TAGS = ( | |
19 | ':override' => 'internal', | |
20 | ); | |
21 | ||
ded2eedc | 22 | our $VERSION = '1.20_01'; |
16433e2b SP |
23 | |
24 | bootstrap Time::Piece $VERSION; | |
25 | ||
26 | my $DATE_SEP = '-'; | |
27 | my $TIME_SEP = ':'; | |
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); | |
33 | ||
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; | |
45 | ||
46 | sub localtime { | |
47 | unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') }; | |
48 | my $class = shift; | |
49 | my $time = shift; | |
50 | $time = time if (!defined $time); | |
51 | $class->_mktime($time, 1); | |
52 | } | |
53 | ||
54 | sub gmtime { | |
55 | unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') }; | |
56 | my $class = shift; | |
57 | my $time = shift; | |
58 | $time = time if (!defined $time); | |
59 | $class->_mktime($time, 0); | |
60 | } | |
61 | ||
62 | sub new { | |
63 | my $class = shift; | |
64 | my ($time) = @_; | |
65 | ||
66 | my $self; | |
67 | ||
68 | if (defined($time)) { | |
69 | $self = $class->localtime($time); | |
70 | } | |
71 | elsif (ref($class) && $class->isa(__PACKAGE__)) { | |
72 | $self = $class->_mktime($class->epoch, $class->[c_islocal]); | |
73 | } | |
74 | else { | |
75 | $self = $class->localtime(); | |
76 | } | |
77 | ||
90d55c29 | 78 | return bless $self, ref($class) || $class; |
16433e2b SP |
79 | } |
80 | ||
81 | sub parse { | |
82 | my $proto = shift; | |
83 | my $class = ref($proto) || $proto; | |
84 | my @components; | |
85 | if (@_ > 1) { | |
86 | @components = @_; | |
87 | } | |
88 | else { | |
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]); | |
91 | } | |
92 | return $class->new(_strftime("%s", @components)); | |
93 | } | |
94 | ||
95 | sub _mktime { | |
96 | my ($class, $time, $islocal) = @_; | |
97 | $class = eval { (ref $class) && (ref $class)->isa('Time::Piece') } | |
98 | ? ref $class | |
99 | : $class; | |
100 | if (ref($time)) { | |
101 | $time->[c_epoch] = undef; | |
90d55c29 | 102 | return wantarray ? @$time : bless [@$time[0..9], $islocal], $class; |
16433e2b SP |
103 | } |
104 | _tzset(); | |
105 | my @time = $islocal ? | |
106 | CORE::localtime($time) | |
107 | : | |
108 | CORE::gmtime($time); | |
109 | wantarray ? @time : bless [@time, $time, $islocal], $class; | |
110 | } | |
111 | ||
112 | my %_special_exports = ( | |
113 | localtime => sub { my $c = $_[0]; sub { $c->localtime(@_) } }, | |
114 | gmtime => sub { my $c = $_[0]; sub { $c->gmtime(@_) } }, | |
115 | ); | |
116 | ||
117 | sub export { | |
118 | my ($class, $to, @methods) = @_; | |
119 | for my $method (@methods) { | |
120 | if (exists $_special_exports{$method}) { | |
121 | no strict 'refs'; | |
122 | no warnings 'redefine'; | |
123 | *{$to . "::$method"} = $_special_exports{$method}->($class); | |
124 | } else { | |
125 | $class->SUPER::export($to, $method); | |
126 | } | |
127 | } | |
128 | } | |
129 | ||
130 | sub import { | |
131 | # replace CORE::GLOBAL localtime and gmtime if required | |
132 | my $class = shift; | |
133 | my %params; | |
134 | map($params{$_}++,@_,@EXPORT); | |
135 | if (delete $params{':override'}) { | |
136 | $class->export('CORE::GLOBAL', keys %params); | |
137 | } | |
138 | else { | |
139 | $class->export((caller)[0], keys %params); | |
140 | } | |
141 | } | |
142 | ||
143 | ## Methods ## | |
144 | ||
145 | sub sec { | |
146 | my $time = shift; | |
147 | $time->[c_sec]; | |
148 | } | |
149 | ||
150 | *second = \&sec; | |
151 | ||
152 | sub min { | |
153 | my $time = shift; | |
154 | $time->[c_min]; | |
155 | } | |
156 | ||
157 | *minute = \&min; | |
158 | ||
159 | sub hour { | |
160 | my $time = shift; | |
161 | $time->[c_hour]; | |
162 | } | |
163 | ||
164 | sub mday { | |
165 | my $time = shift; | |
166 | $time->[c_mday]; | |
167 | } | |
168 | ||
169 | *day_of_month = \&mday; | |
170 | ||
171 | sub mon { | |
172 | my $time = shift; | |
173 | $time->[c_mon] + 1; | |
174 | } | |
175 | ||
176 | sub _mon { | |
177 | my $time = shift; | |
178 | $time->[c_mon]; | |
179 | } | |
180 | ||
181 | sub month { | |
182 | my $time = shift; | |
183 | if (@_) { | |
184 | return $_[$time->[c_mon]]; | |
185 | } | |
186 | elsif (@MON_LIST) { | |
187 | return $MON_LIST[$time->[c_mon]]; | |
188 | } | |
189 | else { | |
190 | return $time->strftime('%b'); | |
191 | } | |
192 | } | |
193 | ||
194 | *monname = \&month; | |
195 | ||
196 | sub fullmonth { | |
197 | my $time = shift; | |
198 | if (@_) { | |
199 | return $_[$time->[c_mon]]; | |
200 | } | |
201 | elsif (@FULLMON_LIST) { | |
202 | return $FULLMON_LIST[$time->[c_mon]]; | |
203 | } | |
204 | else { | |
205 | return $time->strftime('%B'); | |
206 | } | |
207 | } | |
208 | ||
209 | sub year { | |
210 | my $time = shift; | |
211 | $time->[c_year] + 1900; | |
212 | } | |
213 | ||
214 | sub _year { | |
215 | my $time = shift; | |
216 | $time->[c_year]; | |
217 | } | |
218 | ||
219 | sub yy { | |
220 | my $time = shift; | |
221 | my $res = $time->[c_year] % 100; | |
222 | return $res > 9 ? $res : "0$res"; | |
223 | } | |
224 | ||
225 | sub wday { | |
226 | my $time = shift; | |
227 | $time->[c_wday] + 1; | |
228 | } | |
229 | ||
230 | sub _wday { | |
231 | my $time = shift; | |
232 | $time->[c_wday]; | |
233 | } | |
234 | ||
235 | *day_of_week = \&_wday; | |
236 | ||
237 | sub wdayname { | |
238 | my $time = shift; | |
239 | if (@_) { | |
240 | return $_[$time->[c_wday]]; | |
241 | } | |
242 | elsif (@DAY_LIST) { | |
243 | return $DAY_LIST[$time->[c_wday]]; | |
244 | } | |
245 | else { | |
246 | return $time->strftime('%a'); | |
247 | } | |
248 | } | |
249 | ||
250 | *day = \&wdayname; | |
251 | ||
252 | sub fullday { | |
253 | my $time = shift; | |
254 | if (@_) { | |
255 | return $_[$time->[c_wday]]; | |
256 | } | |
257 | elsif (@FULLDAY_LIST) { | |
258 | return $FULLDAY_LIST[$time->[c_wday]]; | |
259 | } | |
260 | else { | |
261 | return $time->strftime('%A'); | |
262 | } | |
263 | } | |
264 | ||
265 | sub yday { | |
266 | my $time = shift; | |
267 | $time->[c_yday]; | |
268 | } | |
269 | ||
270 | *day_of_year = \&yday; | |
271 | ||
272 | sub isdst { | |
273 | my $time = shift; | |
274 | $time->[c_isdst]; | |
275 | } | |
276 | ||
277 | *daylight_savings = \&isdst; | |
278 | ||
279 | # Thanks to Tony Olekshy <olekshy@cs.ualberta.ca> for this algorithm | |
280 | sub tzoffset { | |
281 | my $time = shift; | |
282 | ||
283 | return Time::Seconds->new(0) unless $time->[c_islocal]; | |
284 | ||
285 | my $epoch = $time->epoch; | |
286 | ||
287 | my $j = sub { | |
288 | ||
289 | my ($s,$n,$h,$d,$m,$y) = @_; $m += 1; $y += 1900; | |
290 | ||
291 | $time->_jd($y, $m, $d, $h, $n, $s); | |
292 | ||
293 | }; | |
294 | ||
295 | # Compute floating offset in hours. | |
296 | # | |
90d55c29 CBW |
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))); | |
16433e2b SP |
300 | |
301 | # Return value in seconds rounded to nearest minute. | |
302 | return Time::Seconds->new( int($delta * 60 + ($delta >= 0 ? 0.5 : -0.5)) * 60 ); | |
303 | } | |
304 | ||
305 | sub epoch { | |
306 | my $time = shift; | |
307 | if (defined($time->[c_epoch])) { | |
308 | return $time->[c_epoch]; | |
309 | } | |
310 | else { | |
311 | my $epoch = $time->[c_islocal] ? | |
312 | timelocal(@{$time}[c_sec .. c_mon], $time->[c_year]+1900) | |
313 | : | |
314 | timegm(@{$time}[c_sec .. c_mon], $time->[c_year]+1900); | |
315 | $time->[c_epoch] = $epoch; | |
316 | return $epoch; | |
317 | } | |
318 | } | |
319 | ||
320 | sub hms { | |
321 | my $time = shift; | |
322 | my $sep = @_ ? shift(@_) : $TIME_SEP; | |
323 | sprintf("%02d$sep%02d$sep%02d", $time->[c_hour], $time->[c_min], $time->[c_sec]); | |
324 | } | |
325 | ||
326 | *time = \&hms; | |
327 | ||
328 | sub ymd { | |
329 | my $time = shift; | |
330 | my $sep = @_ ? shift(@_) : $DATE_SEP; | |
331 | sprintf("%d$sep%02d$sep%02d", $time->year, $time->mon, $time->[c_mday]); | |
332 | } | |
333 | ||
334 | *date = \&ymd; | |
335 | ||
336 | sub mdy { | |
337 | my $time = shift; | |
338 | my $sep = @_ ? shift(@_) : $DATE_SEP; | |
339 | sprintf("%02d$sep%02d$sep%d", $time->mon, $time->[c_mday], $time->year); | |
340 | } | |
341 | ||
342 | sub dmy { | |
343 | my $time = shift; | |
344 | my $sep = @_ ? shift(@_) : $DATE_SEP; | |
345 | sprintf("%02d$sep%02d$sep%d", $time->[c_mday], $time->mon, $time->year); | |
346 | } | |
347 | ||
348 | sub datetime { | |
349 | my $time = shift; | |
350 | my %seps = (date => $DATE_SEP, T => 'T', time => $TIME_SEP, @_); | |
351 | return join($seps{T}, $time->date($seps{date}), $time->time($seps{time})); | |
352 | } | |
353 | ||
354 | ||
355 | ||
356 | # Julian Day is always calculated for UT regardless | |
357 | # of local time | |
358 | sub julian_day { | |
359 | my $time = shift; | |
360 | # Correct for localtime | |
361 | $time = $time->gmtime( $time->epoch ) if $time->[c_islocal]; | |
362 | ||
363 | # Calculate the Julian day itself | |
364 | my $jd = $time->_jd( $time->year, $time->mon, $time->mday, | |
365 | $time->hour, $time->min, $time->sec); | |
366 | ||
367 | return $jd; | |
368 | } | |
369 | ||
370 | # MJD is defined as JD - 2400000.5 days | |
371 | sub mjd { | |
372 | return shift->julian_day - 2_400_000.5; | |
373 | } | |
374 | ||
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 | |
380 | # for more details | |
381 | ||
382 | sub _jd { | |
383 | my $self = shift; | |
384 | my ($y, $m, $d, $h, $n, $s) = @_; | |
385 | ||
386 | # Adjust input parameters according to the month | |
387 | $y = ( $m > 2 ? $y : $y - 1); | |
388 | $m = ( $m > 2 ? $m - 3 : $m + 9); | |
389 | ||
390 | # Calculate the Julian Date (assuming Julian calendar) | |
391 | my $J = int( 365.25 *( $y + 4712) ) | |
392 | + int( (30.6 * $m) + 0.5) | |
393 | + 59 | |
394 | + $d | |
395 | - 0.5; | |
396 | ||
397 | # Calculate the Gregorian Correction (since we have Gregorian dates) | |
398 | my $G = 38 - int( 0.75 * int(49+($y/100))); | |
399 | ||
400 | # Calculate the actual Julian Date | |
401 | my $JD = $J + $G; | |
402 | ||
403 | # Modify to include hours/mins/secs in floating portion. | |
404 | return $JD + ($h + ($n + $s / 60) / 60) / 24; | |
405 | } | |
406 | ||
407 | sub week { | |
408 | my $self = shift; | |
409 | ||
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]; | |
415 | ||
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). | |
420 | $J = int($J+0.5); | |
421 | ||
422 | use integer; | |
423 | my $d4 = ((($J + 31741 - ($J % 7)) % 146097) % 36524) % 1461; | |
424 | my $L = $d4 / 1460; | |
425 | my $d1 = (($d4 - $L) % 365) + $L; | |
426 | return $d1 / 7 + 1; | |
427 | } | |
428 | ||
429 | sub _is_leap_year { | |
430 | my $year = shift; | |
431 | return (($year %4 == 0) && !($year % 100 == 0)) || ($year % 400 == 0) | |
432 | ? 1 : 0; | |
433 | } | |
434 | ||
435 | sub is_leap_year { | |
436 | my $time = shift; | |
437 | my $year = $time->year; | |
438 | return _is_leap_year($year); | |
439 | } | |
440 | ||
441 | my @MON_LAST = qw(31 28 31 30 31 30 31 31 30 31 30 31); | |
442 | ||
443 | sub month_last_day { | |
444 | my $time = shift; | |
445 | my $year = $time->year; | |
446 | my $_mon = $time->_mon; | |
447 | return $MON_LAST[$_mon] + ($_mon == 1 ? _is_leap_year($year) : 0); | |
448 | } | |
449 | ||
450 | sub strftime { | |
451 | my $time = shift; | |
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)); | |
457 | } | |
458 | else { | |
459 | return _strftime($format, CORE::gmtime($time->epoch)); | |
460 | } | |
461 | } | |
462 | return _strftime($format, (@$time)[c_sec..c_isdst]); | |
463 | } | |
464 | ||
465 | sub strptime { | |
466 | my $time = shift; | |
467 | my $string = shift; | |
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)); | |
472 | } | |
473 | ||
474 | sub day_list { | |
475 | shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method | |
476 | my @old = @DAY_LIST; | |
477 | if (@_) { | |
478 | @DAY_LIST = @_; | |
479 | } | |
480 | return @old; | |
481 | } | |
482 | ||
483 | sub mon_list { | |
484 | shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method | |
485 | my @old = @MON_LIST; | |
486 | if (@_) { | |
487 | @MON_LIST = @_; | |
488 | } | |
489 | return @old; | |
490 | } | |
491 | ||
492 | sub time_separator { | |
493 | shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); | |
494 | my $old = $TIME_SEP; | |
495 | if (@_) { | |
496 | $TIME_SEP = $_[0]; | |
497 | } | |
498 | return $old; | |
499 | } | |
500 | ||
501 | sub date_separator { | |
502 | shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); | |
503 | my $old = $DATE_SEP; | |
504 | if (@_) { | |
505 | $DATE_SEP = $_[0]; | |
506 | } | |
507 | return $old; | |
508 | } | |
509 | ||
510 | use overload '""' => \&cdate, | |
511 | 'cmp' => \&str_compare, | |
512 | 'fallback' => undef; | |
513 | ||
514 | sub cdate { | |
515 | my $time = shift; | |
516 | if ($time->[c_islocal]) { | |
517 | return scalar(CORE::localtime($time->epoch)); | |
518 | } | |
519 | else { | |
520 | return scalar(CORE::gmtime($time->epoch)); | |
521 | } | |
522 | } | |
523 | ||
524 | sub str_compare { | |
525 | my ($lhs, $rhs, $reverse) = @_; | |
526 | if (UNIVERSAL::isa($rhs, 'Time::Piece')) { | |
527 | $rhs = "$rhs"; | |
528 | } | |
529 | return $reverse ? $rhs cmp $lhs->cdate : $lhs->cdate cmp $rhs; | |
530 | } | |
531 | ||
532 | use overload | |
533 | '-' => \&subtract, | |
534 | '+' => \&add; | |
535 | ||
536 | sub subtract { | |
537 | my $time = shift; | |
538 | my $rhs = shift; | |
539 | if (UNIVERSAL::isa($rhs, 'Time::Seconds')) { | |
540 | $rhs = $rhs->seconds; | |
541 | } | |
e3db0d81 RGS |
542 | |
543 | if (shift) | |
544 | { | |
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"; | |
552 | } | |
16433e2b SP |
553 | |
554 | if (UNIVERSAL::isa($rhs, 'Time::Piece')) { | |
555 | return Time::Seconds->new($time->epoch - $rhs->epoch); | |
556 | } | |
557 | else { | |
558 | # rhs is seconds. | |
559 | return $time->_mktime(($time->epoch - $rhs), $time->[c_islocal]); | |
560 | } | |
561 | } | |
562 | ||
563 | sub add { | |
564 | my $time = shift; | |
565 | my $rhs = shift; | |
566 | if (UNIVERSAL::isa($rhs, 'Time::Seconds')) { | |
567 | $rhs = $rhs->seconds; | |
568 | } | |
569 | croak "Invalid rhs of addition: $rhs" if ref($rhs); | |
570 | ||
571 | return $time->_mktime(($time->epoch + $rhs), $time->[c_islocal]); | |
572 | } | |
573 | ||
574 | use overload | |
575 | '<=>' => \&compare; | |
576 | ||
577 | sub get_epochs { | |
578 | my ($lhs, $rhs, $reverse) = @_; | |
579 | if (!UNIVERSAL::isa($rhs, 'Time::Piece')) { | |
580 | $rhs = $lhs->new($rhs); | |
581 | } | |
582 | if ($reverse) { | |
583 | return $rhs->epoch, $lhs->epoch; | |
584 | } | |
585 | return $lhs->epoch, $rhs->epoch; | |
586 | } | |
587 | ||
588 | sub compare { | |
589 | my ($lhs, $rhs) = get_epochs(@_); | |
590 | return $lhs <=> $rhs; | |
591 | } | |
592 | ||
124e6c84 RGS |
593 | sub add_months { |
594 | my ($time, $num_months) = @_; | |
595 | ||
596 | croak("add_months requires a number of months") unless defined($num_months); | |
597 | ||
598 | my $final_month = $time->_mon + $num_months; | |
599 | my $num_years = 0; | |
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 | |
90d55c29 CBW |
603 | if ($final_month < 0 && $final_month % 12 == 0) { |
604 | $num_years = int($final_month / 12) + 1; | |
605 | } | |
606 | else { | |
607 | $num_years = int($final_month / 12); | |
608 | } | |
124e6c84 RGS |
609 | $num_years-- if ($final_month < 0); |
610 | ||
611 | $final_month = $final_month % 12; | |
612 | } | |
613 | ||
3df1a9e2 GA |
614 | my @vals = _mini_mktime($time->sec, $time->min, $time->hour, |
615 | $time->mday, $final_month, $time->year - 1900 + $num_years); | |
90d55c29 | 616 | # warn(sprintf("got %d vals: %d-%d-%d %d:%d:%d [%d]\n", scalar(@vals), reverse(@vals), $time->[c_islocal])); |
124e6c84 RGS |
617 | return scalar $time->_mktime(\@vals, $time->[c_islocal]); |
618 | } | |
619 | ||
620 | sub add_years { | |
621 | my ($time, $years) = @_; | |
622 | $time->add_months($years * 12); | |
623 | } | |
624 | ||
16433e2b SP |
625 | 1; |
626 | __END__ | |
627 | ||
628 | =head1 NAME | |
629 | ||
630 | Time::Piece - Object Oriented time objects | |
631 | ||
632 | =head1 SYNOPSIS | |
633 | ||
634 | use Time::Piece; | |
635 | ||
636 | my $t = localtime; | |
637 | print "Time is $t\n"; | |
638 | print "Year is ", $t->year, "\n"; | |
639 | ||
640 | =head1 DESCRIPTION | |
641 | ||
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. | |
646 | ||
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 | |
650 | ||
651 | =head1 USAGE | |
652 | ||
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: | |
660 | ||
661 | $t->sec # also available as $t->second | |
662 | $t->min # also available as $t->minute | |
663 | $t->hour # 24 hour | |
664 | $t->mday # also available as $t->day_of_month | |
665 | $t->mon # 1 = January | |
666 | $t->_mon # 0 = January | |
667 | $t->monname # Feb | |
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 | |
676 | $t->wdayname # Tue | |
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 | |
681 | ||
682 | $t->hms # 12:34:56 | |
683 | $t->hms(".") # 12.34.56 | |
684 | $t->time # same as $t->hms | |
685 | ||
686 | $t->ymd # 2000-02-29 | |
687 | $t->date # same as $t->ymd | |
688 | $t->mdy # 02-29-2000 | |
689 | $t->mdy("/") # 02/29/2000 | |
690 | $t->dmy # 29-02-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 | |
695 | ||
696 | $t->epoch # seconds since the epoch | |
697 | $t->tzoffset # timezone offset in a Time::Seconds object | |
698 | ||
699 | $t->julian_day # number of days since Julian period began | |
700 | $t->mjd # modified Julian date (JD-2400000.5 days) | |
701 | ||
702 | $t->week # week number (ISO 8601) | |
703 | ||
704 | $t->is_leap_year # true if it its | |
705 | $t->month_last_day # 28-31 | |
706 | ||
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 | |
711 | ||
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" | |
715 | ||
716 | Time::Piece->strptime(STRING, FORMAT) | |
717 | # see strptime man page. Creates a new | |
718 | # Time::Piece object | |
719 | ||
720 | =head2 Local Locales | |
721 | ||
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 | |
725 | using locales. | |
726 | ||
727 | my @days = qw( Dimanche Lundi Merdi Mercredi Jeudi Vendredi Samedi ); | |
728 | ||
729 | my $french_day = localtime->day(@days); | |
730 | ||
731 | These settings can be overriden globally too: | |
732 | ||
733 | Time::Piece::day_list(@days); | |
734 | ||
735 | Or for months: | |
736 | ||
737 | Time::Piece::mon_list(@months); | |
738 | ||
739 | And locally for months: | |
740 | ||
741 | print localtime->month(@months); | |
742 | ||
743 | =head2 Date Calculations | |
744 | ||
745 | It's possible to use simple addition and subtraction of objects: | |
746 | ||
747 | use Time::Seconds; | |
748 | ||
749 | my $seconds = $t1 - $t2; | |
750 | $t1 += ONE_DAY; # add 1 day (constant from Time::Seconds) | |
751 | ||
752 | The following are valid ($t1 and $t2 are Time::Piece objects): | |
753 | ||
754 | $t1 - $t2; # returns Time::Seconds object | |
755 | $t1 - 42; # returns Time::Piece object | |
756 | $t1 + 533; # returns Time::Piece object | |
757 | ||
758 | However adding a Time::Piece object to another Time::Piece object | |
759 | will cause a runtime error. | |
760 | ||
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. | |
765 | ||
124e6c84 RGS |
766 | In addition to adding seconds, there are two APIs for adding months and |
767 | years: | |
768 | ||
769 | $t->add_months(6); | |
770 | $t->add_years(5); | |
771 | ||
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. | |
779 | ||
16433e2b SP |
780 | =head2 Date Comparisons |
781 | ||
782 | Date comparisons are also possible, using the full suite of "<", ">", | |
783 | "<=", ">=", "<=>", "==" and "!=". | |
784 | ||
785 | =head2 Date Parsing | |
786 | ||
90d55c29 | 787 | Time::Piece has a built-in strptime() function (from FreeBSD), allowing |
16433e2b SP |
788 | you incredibly flexible date parsing routines. For example: |
789 | ||
90d55c29 | 790 | my $t = Time::Piece->strptime("Sunday 3rd Nov, 1943", |
16433e2b SP |
791 | "%A %drd %b, %Y"); |
792 | ||
793 | print $t->strftime("%a, %d %b %Y"); | |
794 | ||
795 | Outputs: | |
796 | ||
797 | Wed, 03 Nov 1943 | |
798 | ||
799 | (see, it's even smart enough to fix my obvious date bug) | |
800 | ||
801 | For more information see "man strptime", which should be on all unix | |
802 | systems. | |
803 | ||
90d55c29 CBW |
804 | Alternatively look here: http://www.unix.com/man-page/FreeBSD/3/strftime/ |
805 | ||
16433e2b SP |
806 | =head2 YYYY-MM-DDThh:mm:ss |
807 | ||
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 | |
811 | of the time. | |
812 | ||
813 | =head2 Week Number | |
814 | ||
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. | |
821 | ||
822 | =head2 Global Overriding | |
823 | ||
824 | Finally, it's possible to override localtime and gmtime everywhere, by | |
825 | including the ':override' tag in the import list: | |
826 | ||
827 | use Time::Piece ':override'; | |
828 | ||
12016aad SH |
829 | =head1 CAVEATS |
830 | ||
831 | =head2 Setting $ENV{TZ} in Threads on Win32 | |
832 | ||
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. | |
837 | ||
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). | |
843 | ||
8177d4d9 SH |
844 | Furthermore, remember that this caveat also applies to fork(), which is |
845 | emulated by threads on Win32. | |
846 | ||
90d55c29 CBW |
847 | =head2 Use of epoch seconds |
848 | ||
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()>. | |
851 | ||
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. | |
857 | ||
16433e2b SP |
858 | =head1 AUTHOR |
859 | ||
860 | Matt Sergeant, matt@sergeant.org | |
861 | Jarkko Hietaniemi, jhi@iki.fi (while creating Time::Piece for core perl) | |
862 | ||
863 | =head1 License | |
864 | ||
865 | This module is free software, you may distribute it under the same terms | |
866 | as Perl. | |
867 | ||
868 | =head1 SEE ALSO | |
869 | ||
870 | The excellent Calendar FAQ at http://www.tondering.dk/claus/calendar.html | |
871 | ||
872 | =head1 BUGS | |
873 | ||
874 | The test harness leaves much to be desired. Patches welcome. | |
875 | ||
876 | =cut |