File Coverage

blib/lib/Date/Piece.pm
Criterion Covered Total %
statement 200 223 89.6
branch 47 70 67.1
condition 14 26 53.8
subroutine 55 61 90.1
pod 22 22 100.0
total 338 402 84.0


line stmt bran cond sub pod time code
1             package Date::Piece;
2             $VERSION = v0.0.3;
3              
4 3     3   48938 use warnings;
  3         8  
  3         123  
5 3     3   17 use strict;
  3         5  
  3         109  
6 3     3   28 use Carp;
  3         6  
  3         358  
7              
8 3     3   2987 use Time::Piece;
  3         54603  
  3         17  
9             {
10 3     3   265 no warnings 'redefine';
  3         7  
  3         364  
11             *Time::Piece::ymd = *Time::Piece::date = sub {
12 1     1   1184 my $t = shift;
13 1         7 return Date::Piece->new($t->year, $t->mon, $t->mday);
14             };
15             }
16              
17 3     3   20 use base 'Date::Simple';
  3         5  
  3         4477  
18              
19             =head1 NAME
20              
21             Date::Piece - efficient dates with Time::Piece interoperability
22              
23             =head1 SYNOPSIS
24              
25             use Date::Piece qw(date);
26              
27             my $date = date('2007-11-22');
28             my $time = $date->at('16:42:35');
29              
30             print $time, "\n"; # is a Time::Piece
31              
32             You can also start from a Time::Piece object.
33              
34             use Time::Piece;
35             use Date::Piece;
36              
37             my $time = localtime;
38             my $date = $time->date; # also ymd()
39              
40             $date+=7;
41             # seven days later
42             print $date, "\n";
43              
44             # seven days later at the original time
45             print $date->at($time), "\n";
46              
47             =head1 ABOUT
48              
49             This module allows you to do I math on dates. That is, rather
50             than worrying about time zones and DST while adding increments of
51             24*60**2 seconds to a date&time object, you simply discard the time
52             component and do math directly on the date. If you need a time-of-day
53             on the calculated date, the at() method returns a Time::Piece object,
54             thus allowing you to be specific about the endpoints of a nominal
55             interval.
56              
57             This is useful for constructs such as "tomorrow", "yesterday", "this
58             time tomorrow", "one week from today", "one month later", "my 31st
59             birthday", and various other not-necessarily-numeric intervals on the
60             arbitrary and edge-case-laden division of time known by most earthlings
61             as "the calendar." That is, adding days or months is analogous to
62             counting squares or turning pages on a calendar.
63              
64             This module extends Date::Simple and connects it to Time::Piece. See
65             Date::Simple for more details.
66              
67             =head1 Immutable
68              
69             A Date::Piece object never changes. This means that methods like add_months() always return a new object.
70              
71             This does not I to be true with constructs such as C<$date++> or
72             C<$date+=7>, but what is actually happening is that perl treats the
73             variable as an lvalue and assigns the new object to it. Thus, the
74             following is true:
75              
76             my $also_date = my $date = today;
77             $date++;
78             $date > $also_date;
79              
80             =head1 Validation
81              
82             Where Date::Simple returns false for invalid dates, I throw errors.
83              
84             =head1 Convenient Syntax
85              
86             You may import the functions 'date' and 'today' as well as the
87             unit-qualifiers 'years', 'months', and 'weeks'.
88              
89             When loaded as -MDate::Piece with perl -e (and/or -E in 5.10), these
90             extremely short versions are exported by default:
91              
92             years => 'Y',
93             months => 'M',
94             weeks => 'W',
95             date => 'D',
96             today => 'CD', # mnemonic: Current Date
97              
98             You may unimport any imported functions with the 'no Date::Piece'
99             directive.
100              
101             =cut
102              
103             =head1 Functions
104              
105             =head2 today
106              
107             This returns the current date. Don't be afraid to use it in arithmetic.
108              
109             my $today = today;
110             my $tomorrow = today + 1;
111              
112             =head2 date
113              
114             my $new_year_is_coming = date('2007-12-31');
115              
116             Equivalent to Date::Piece->new('2007-12-31');
117              
118             Also takes year, month, day arguments.
119              
120             my $d = date($year, $month, $day);
121              
122             =cut
123              
124 3     3 1 2183 sub today () { __PACKAGE__->_today }
125             sub date {
126 17     17 1 16349 my $d = __PACKAGE__->_new(@_);
127 17 100       1014 $d or croak("invalid date @_");
128 15         108 return($d);
129             }
130              
131             ########################################################################
132             # I-hate-exporter overhead
133             my @export_ok = qw(
134             today
135             date
136             );
137             my $gensub = sub {
138             my $part = shift;
139 3     3   888 my $sub = eval("sub () { Date::Piece::${part}_unit->new(1) }");
  2         89  
  1         533  
  2         1009  
  1         640  
140             $@ and die "gah $@";
141             return($sub);
142             };
143             my %export_as = (
144             map({("${_}s" => $gensub->($_))} qw(year month week day)),
145             centuries => $gensub->('century'),
146             );
147             my %exported;
148             my $do_export = sub {
149             my $package = shift;
150             my ($caller, $function, $as) = @_;
151             $as ||= $function;
152              
153             my $track = $exported{$package} ||= {};
154             $track = $track->{$caller} ||= {};
155              
156             $track->{$as} = $function;
157             my $sref = $export_as{$function} ||
158             $package->can($function) or croak("cannot $function");
159 3     3   32523 no strict 'refs';
  3         8  
  3         1014  
160             *{$caller . '::' . $as} = $sref;
161             };
162              
163             sub import {
164 3     3   31 my $package = shift;
165 3         29 my (@args) = @_;
166              
167 3         13 my ($caller, $file, $line) = caller;
168              
169 3 50 33     19 if(not $line and lc($file) eq '-e') {
170 0         0 $package->$do_export($caller, @$_) for(
171             [years => 'Y'],
172             [months => 'M'],
173             [weeks => 'W'],
174             [date => 'D'],
175             [today => 'CD'],
176             );
177             }
178              
179 3         13 my %ok = map({$_ => 1} @export_ok, keys(%export_as));
  21         49  
180 3         13 foreach my $arg (@args) {
181 8 50       24 $ok{$arg} or croak("$arg is not exported by the $package module");
182             }
183 3         23 $package->$do_export($caller, $_) for(@args);
184             }
185              
186             =head2 unimport
187              
188             Clean-out the imported methods from your namespace.
189              
190             no Date::Piece;
191              
192             =cut
193              
194             sub unimport {
195 0     0   0 my $package = shift;
196 0         0 my $caller = caller;
197              
198 0   0     0 my $track = $exported{$package} ||= {};
199 0   0     0 $track = $track->{$caller} ||= {};
200 0         0 foreach my $func (keys(%$track)) {
201 3     3   25 no strict 'refs';
  3         6  
  3         5168  
202 0         0 delete(${$caller . '::'}{$func});
  0         0  
203             }
204             }
205             # end another-thing-to-be-modularized
206             ########################################################################
207              
208             =head2 new
209              
210             Takes the same arguments as date().
211              
212             =cut
213              
214             sub new {
215 24     24 1 159 my $package = shift;
216 24 50       104 my $obj = $package->SUPER::new(@_) or croak("invalid date @_");
217 24         881 return($obj);
218             }
219              
220             =head1 Methods
221              
222             TODO paste most of the Date::Simple documentation here?
223              
224             =head2 Note: lack of complete API compatibility with Time::Piece
225              
226             Ideally, we should have the Time::Piece API, but Date::Simple doesn't do
227             that. I'm I to avoid a complete fork of Date::Simple, but will
228             likely need to do that just to make e.g. month() do the same thing that
229             it does in Time::Piece. Ultimately, a Date::Piece should act exactly
230             like a Time::Piece where the time is always midnight (which implies that
231             adding seconds upgrades the result to a Time::Piece and etc.)
232              
233              
234             =head2 Y
235              
236             $date->Y;
237              
238             =cut
239              
240             sub Y {
241 0     0 1 0 my $self = shift;
242 0         0 $self->year;
243             } # end subroutine Y definition
244             ########################################################################
245              
246             =head2 M
247              
248             $date->M;
249              
250             =cut
251              
252             sub M {
253 0     0 1 0 my $self = shift;
254 0         0 $self->month;
255             } # end subroutine M definition
256             ########################################################################
257              
258             =head2 mon
259              
260             $date->mon;
261              
262             =cut
263              
264             sub mon {
265 0     0 1 0 my $self = shift;
266 0         0 $self->at('16:00')->monname;
267             } # end subroutine mon definition
268             ########################################################################
269              
270             =head2 monthname
271              
272             $date->monthname;
273              
274             =cut
275              
276             sub monthname {
277 0     0 1 0 my $self = shift;
278 0         0 $self->at('16:00')->fullmonth;
279             } # end subroutine monthname definition
280             ########################################################################
281              
282             =head2 D
283              
284             $date->D;
285              
286             =cut
287              
288             sub D {
289 0     0 1 0 my $self = shift;
290 0         0 $self->day;
291             } # end subroutine D definition
292             ########################################################################
293              
294             =head2 iso_dow
295              
296             Returns the day of the week (0-6) with Monday = 0 (as per ISO 8601.)
297              
298             my $dow = $date->iso_dow;
299              
300             See day_of_week() if you want Sunday as the first day (as in localtime.)
301              
302             =cut
303              
304             sub iso_dow {
305 6     6 1 1915 my $self = shift;
306 6         19 my $dow = $self->day_of_week;
307 6         8 $dow--;
308 6 100       35 return($dow < 0 ? 6 : $dow);
309             } # end subroutine iso_dow definition
310             ########################################################################
311              
312             =head2 iso_wday
313              
314             Returns 1-7 where Monday is 1.
315              
316             my $wday = $date->iso_wday;
317              
318             =cut
319              
320             sub iso_wday {
321 3     3 1 7 my $self = shift;
322 3         8 return($self->iso_dow+1);
323             } # end subroutine iso_wday definition
324             ########################################################################
325              
326             =head1 Setting the Time on a Date
327              
328             =head2 at
329              
330             Returns a Time::Piece object at the given time on the date C<$date>.
331              
332             my $timepiece = $date->at($time);
333              
334             $time can be in 24-hour format (seconds optional) or have an 'am' or
335             'pm' (case insensitive) suffix.
336              
337             $time may also be of the form '1268s', which will be taken as a number
338             of seconds to be added to midnight on the given day (and may be
339             negative.)
340              
341             The time is constructed via Time::Local. For concerns about daylight
342             savings, see the caveats in Time::Local.
343              
344             If $time is a Time::Piece from a different time zone, we *should*
345             respect that, but currently do the wrong thing.
346              
347             =cut
348              
349             sub at {
350 4     4 1 1383 my $self = shift;
351 4         10 my ($h, $m, $s) = @_;
352              
353             # XXX just throw it at Date::Parse?
354 4         5 my $offset;
355 4 50       12 unless(defined($m)) { # parse-out $h
356 4 100       20 if(ref($h)) { # a time object
    100          
357 1         7 ($h,$m,$s) = split(/:/, $h->hms);
358             }
359             elsif($h =~ s/s$//) { # number-of-seconds
360 2         4 $offset = $h;
361 2         3 ($h, $m, $s) = (0,0,0);
362             }
363             else {
364 1         6 ($h, $m, $s) = $self->_parse_at($h);
365             }
366             }
367 4         47 require Time::Local;
368              
369             # XXX doesn't respect UTC on an incoming Time::Piece
370              
371 4         49 my $time = Time::Piece->new(
372             Time::Local::timelocal($s,$m,$h,
373             $self->day, $self->month - 1, $self->year - 1900
374             )
375             );
376 4 100       526 $time += $offset if($offset);
377 4         130 return($time);
378             } # end subroutine at definition
379             ########################################################################
380              
381             sub _parse_at {
382 1     1   3 my $self = shift;
383 1         2 my ($t) = @_;
384              
385 1         7 my @bits = split(/:/, $t);
386 1 50       6 (@bits > 3) and croak("invalid time $t");
387 1 50       18 (@bits >= 2) or croak("invalid time $t");
388              
389 1 50       6 if($bits[-1] =~ s/([ap])m$//i) {
390 0         0 my $d = lc($1);
391 0 0       0 if($bits[0] == 12) {
392 0 0       0 $bits[0] = 0 if($d eq 'a');
393             }
394             else {
395 0 0       0 $bits[0] += 12 if($d eq 'p');
396             }
397             }
398              
399 1   50     5 $bits[2] ||= 0;
400              
401 1         5 return(@bits);
402             } # end subroutine _parse_at definition
403             ########################################################################
404              
405             # TODO next("wednesday"), last("wednesday") (also prev("wed"))
406              
407             =head1 Endpoints
408              
409             These are all very simple, but convenient.
410              
411             =head2 start_of_year
412              
413             January 1st of the year containing $date.
414              
415             my $start = $date->start_of_year;
416              
417             =cut
418              
419             sub start_of_year {
420 1     1 1 114 my $self = shift;
421 1         7 return($self->new($self->year, 1, 1));
422             } # end subroutine start_of_year definition
423             ########################################################################
424              
425             =head2 end_of_year
426              
427             December 31st of the year containing $date.
428              
429             my $end = $date->end_of_year;
430              
431             =cut
432              
433             sub end_of_year {
434 1     1 1 9 my $self = shift;
435 1         7 return($self->new($self->year, 12, 31));
436             } # end subroutine end_of_year definition
437             ########################################################################
438              
439             =head2 start_of_month
440              
441             Returns the 1st of the month containing $date.
442              
443             my $start = $date->start_of_month;
444              
445             =cut
446              
447             sub start_of_month {
448 1     1 1 17 my $self = shift;
449 1         22 return $self->new(($self->as_ymd)[0,1], 1);
450             } # end subroutine start_of_month definition
451             ########################################################################
452              
453             =head2 end_of_month
454              
455             Returns the last day of the month containing $date.
456              
457             my $end = $date->end_of_month;
458              
459             =cut
460              
461             sub end_of_month {
462 3     3 1 570 my $self = shift;
463 3         15 return($self->new(($self->as_ymd)[0,1], $self->days_in_month));
464             } # end subroutine end_of_month definition
465             ########################################################################
466              
467             =head2 days_in_month
468              
469             Returns the number of days in the month containing $date.
470              
471             my $num = $date->days_in_month;
472              
473             See also C.
474              
475             =cut
476              
477             sub days_in_month {
478 3     3 1 4 my $self = shift;
479 3         17 return(Date::Simple::days_in_month(($self->as_ymd)[0,1]));
480             } # end subroutine days_in_month definition
481             ########################################################################
482              
483             =head2 leap_year
484              
485             Returns true if Date is in a leap year.
486              
487             my $bool = $date->leap_year;
488              
489             See also C.
490              
491             =cut
492              
493             sub leap_year {
494 1     1 1 10 my $self = shift;
495 1         10 return(Date::Simple::leap_year($self->year));
496             } # end subroutine leap_year definition
497             ########################################################################
498              
499             =head2 thru
500              
501             Returns a list ala $start..$end (because overloading doesn't work with
502             the '..' construct.) Will work forwards or backwards.
503              
504             my @list = $date->thru($other_date);
505              
506             =cut
507              
508             sub thru {
509 3     3 1 2370 my $self = shift;
510 3         14 my $i = $self->iterator(@_);
511              
512 3         10 my @ans;
513 3         8 while(my $d = $i->()) { push(@ans, $d); }
  21         241  
514 3         21 return(@ans);
515             } # end subroutine thru definition
516             ########################################################################
517              
518             =head2 iterator
519              
520             Returns a subref which iterates through the dates between $date and
521             $other_date (inclusive.)
522              
523             my $subref = $date->iterator($other_date);
524             while(my $day = $subref->()) {
525             # do something with $day
526             }
527              
528             =cut
529              
530             sub iterator {
531 3     3 1 5 my $self = shift;
532 3         6 my ($other) = @_;
533 3 100       16 ref($other) or $other = ref($self)->new($other);
534              
535 3         11 my $diff = $other - $self;
536 3         7 my $abs_d = abs($diff);
537 3 50       65 my $dir = $abs_d ? $diff/$abs_d : 1;
538 3         6 my $count = 0;
539             my $ref = sub {
540 24 100   24   68 ($count++ > $abs_d) and return;
541 21         26 my $now = $self; $self += $dir;
  21         41  
542 21         439 return($now);
543 3         23 };
544             } # end subroutine iterator definition
545             ########################################################################
546              
547             =head1 Fuzzy Math
548              
549             We can do math with months and years as long as you're flexible about
550             the day of the month. The theme here is to keep the answer within the
551             destination calendar month rather than adding e.g. 30 days.
552              
553             =head2 adjust_day_of_month
554              
555             Returns a valid date even if the given day is beyond the last day of the
556             month (returns the last day of that month.)
557              
558             $date = adjust_day_of_month($y, $m, $maybe_day);
559              
560             =cut
561              
562             sub adjust_day_of_month {
563 8     8 1 19 my (@ymd) = @_;
564              
565 8 50       25 (@ymd == 3) or croak(
566             "adjust_day_of_month() must have 3 arguments, not ", scalar(@ymd));
567              
568 8 100       22 if($ymd[2] > 28) { # optimize
569 5         16 my $dim = Date::Simple::days_in_month(@ymd[0,1]);
570 5 100       16 $ymd[2] = $dim if($ymd[2] > $dim);
571             }
572            
573 8         156 return(@ymd);
574             } # end subroutine adjust_day_of_month definition
575             ########################################################################
576              
577             =head2 add_months
578              
579             Adds $n I months to $date. This will just be a simple
580             increment of the months (rolling-over at 12) as long as the day part is
581             less than 28. If the destination month doesn't have as many days as the
582             origin month, the answer will be the last day of the destination month
583             (via adjust_day_of_month().)
584              
585             my $shifted = $date->add_months($n);
586              
587             Note that if $day > 28 this is not reversible. One should not rely on
588             it for incrementing except in trivial cases where $day <= 28 (because
589             calling $date = $date->add_months(1) twice is not necessarily the same
590             result as $date = $date->add_months(2).)
591              
592             =cut
593              
594             sub add_months {
595 8     8 1 1835 my $self = shift;
596 8         15 my ($months) = @_;
597              
598 8 100       31 return($self->add_years($months/12)) unless($months % 12);
599              
600 6         27 my @ymd = $self->as_ymd;
601              
602             # get raw month number, bound, and carry to years
603 6         13 my $nm = $ymd[1]+$months;
604 6   100     23 my $m = $nm % 12 || 12;
605 6         16 my $ya = ($nm - $m)/12;
606 6         12 $ymd[0] += $ya;
607 6         9 $ymd[1] = $m;
608 6         17 return($self->new(adjust_day_of_month(@ymd)));
609             } # end subroutine add_months definition
610             ########################################################################
611              
612             =head2 add_years
613              
614             Equivalent to adding $n*12 months.
615              
616             my $shifted = $date->add_years($n);
617              
618             =cut
619              
620             sub add_years {
621 10     10 1 730 my $self = shift;
622 10         15 my ($years) = @_;
623              
624 10         39 my (@ymd) = $self->as_ymd;
625              
626 10         18 $ymd[0]+= $years;
627              
628             # optimize: only check February
629 10 100       34 @ymd = adjust_day_of_month(@ymd) if($ymd[1] == 2);
630              
631 10         37 return($self->new(@ymd));
632             } # end subroutine add_years definition
633             ########################################################################
634              
635             =head1 Year, Month, and etc "units"
636              
637             The constants 'years', 'months', and 'weeks' may be multiplied by an
638             I and added to (or subtracted from) a date.
639              
640             use Date::Piece qw(today years);
641             my $distant_future = today + 10*years;
642              
643             perl -MDate::Piece -e 'print CD+10*Y, "\n";'
644              
645             The unit objects stringify as e.g. '10years'.
646              
647             You may also divide time units by a number as long as the result is an
648             integer. You may not use units as a divisor.
649              
650             Any math done on these units which yields other than an integer will
651             throw a run-time error.
652              
653             Also available are 'centuries' and 'days' (the latter is convenient as a
654             stricture to ensure that your days are integers.)
655              
656             Conversion between these units only makes sense for centuries => years
657             and weeks => days, but is currently not available.
658              
659             =cut
660              
661             BEGIN {
662             package Date::Piece::unit_base;
663              
664 3     3   25 use Carp;
  3         14  
  3         881  
665              
666             sub new {
667 34     34   56 my $package = shift;
668 34         41 my ($v) = @_;
669 34         148 my $int = int($v);
670 34 100       949 ($v == $int) or croak("can only work in integer ", $package->unit);
671 29         35 $v = $int;
672 29   66     92 my $class = ref($package) || $package;
673 29         596 bless(\$v, $class);
674             } # end subroutine new definition
675             use overload (
676 12     12   1040 '*' => sub {shift->_redispatch('multiply', @_)},
677 6     6   2047 '/' => '_divide',
678             '+' => sub {shift->_redispatch('add', @_)},
679 6     6   25 '-' => sub {shift->_redispatch('subtract', @_)},
680 15     15   31043 '""' => sub { my $self = shift; $$self . $self->unit },
  15         116  
681             #fallback => 1,
682 3     3   46 );
  3         6  
  3         41  
683             sub _redispatch {
684 29     29   60 my ($self, $op, $and, $r) = @_;
685              
686 29         45 my $sref = ref($self);
687 29         40 my $aref = ref($and);
688              
689 29         54 my $method = '_' . $op;
690              
691             # check sanity and maybe send elsewhere
692 29 100 66     108 if($aref and $aref->isa('Date::Simple')) {
693 4 50       23 $aref->can($method) or
694             croak("cannot $op ", $self->unit, " with a date");
695 4 50       18 return($and->$method($self, $r ? 0 : 1));
696             }
697 25 50 33     2291 if($sref and $aref) {
698 0 0       0 ($sref eq $aref) or croak("cannot $op dissimilar units");
699             }
700              
701 25         125 return($self->$method($and, $r));
702             }
703              
704             sub _add {
705 3     3   8 my ($self, $and, $r) = @_;
706 3         13 $self->new($$self + $and);
707             }
708             sub _subtract {
709 5     5   7 my ($self, $op, $r) = @_;
710 5 50       24 $self->new($r ? $op - $$self : $$self - $op);
711             }
712             sub _multiply {
713 17     17   29 my ($self, $and, $r) = @_;
714 17         66 $self->new($$self * $and);
715             }
716             sub _divide {
717 5     5   1634 my ($s, $v, $r) = @_;
718             # TODO 1week/7 => 1day
719 5 50       19 croak($s->unit, " cannot be in the denominator") if($r);
720 5         28 $s->_redispatch('multiply', 1/$v, $r);
721             }
722              
723             package Date::Piece::century_unit;
724 3     3   55 our @ISA = qw(Date::Piece::unit_base);
725 3     3   1804 use constant unit => 'centuries';
  3         5  
  3         375  
726             package Date::Piece::year_unit;
727 3         38 our @ISA = qw(Date::Piece::unit_base);
728 3     3   15 use constant unit => 'years';
  3         6  
  3         231  
729             package Date::Piece::month_unit;
730 3         37 our @ISA = qw(Date::Piece::unit_base);
731 3     3   16 use constant unit => 'months';
  3         12  
  3         223  
732             # Hmm, weeks are just 7 and days are just 1?
733             # but do we want to be able to add weeks together first?
734             package Date::Piece::week_unit;
735 3     3   16 use constant unit => 'weeks';
  3         7  
  3         273  
736 3         48 our @ISA = qw(Date::Piece::unit_base);
737             package Date::Piece::day_unit;
738 3     3   15 use constant unit => 'days';
  3         6  
  3         197  
739 3         1542 our @ISA = qw(Date::Piece::unit_base);
740             }
741             # now to redo the overloading here
742              
743             =head2 _add
744              
745             $date = $date->_add($thing);
746              
747             =cut
748              
749             sub _add {
750 67     67   10379 my $self = shift;
751 67         107 my ($and) = @_;
752 67 100 66     328 if(ref($and) and $and->can('unit')) {
753 13         37 my $m = '_add_' . $and->unit;
754 13 50       49 croak("cannot add ", $and->unit) unless($self->can($m));
755 13         34 return($self->$m($$and))
756             }
757              
758 54         364 return($self->SUPER::_add($and));
759             } # end subroutine _add definition
760             ########################################################################
761              
762 2     2   7 sub _add_days {shift(@_)+shift(@_);}
763 3     3   11 sub _add_weeks {shift(@_)+shift(@_)*7;}
764 3     3   11 sub _add_months {shift->add_months(@_);}
765 3     3   10 sub _add_years {shift->add_years(@_);}
766 2     2   7 sub _add_centuries {shift->add_years(shift(@_)*100);}
767              
768             =head2 _subtract
769              
770             $date = $date->_subtract($thing);
771              
772             =cut
773              
774             sub _subtract {
775 20     20   6508 my $self = shift;
776 20         41 my ($and, $r) = @_;
777 20 100       375 croak("cannot subtract a date from a non-date") if($r);
778 19 100 100     235 if(ref($and) and $and->isa(__PACKAGE__)) {
779 5         38 return($self->SUPER::_subtract($and, $r));
780             }
781 14         39 return($self->_add(-$and));
782             } # end subroutine _subtract definition
783             ########################################################################
784              
785             =head1 Examples
786              
787             These all assume imported syntactical sugar ala:
788              
789             use Date::Piece qw(date today years months weeks);
790             use Time::Piece;
791              
792             Turning 40 is pretty arbitrary, but alarming!
793              
794             my $bd = date('1970-12-02');
795             my $big40 = $bd+40*years;
796              
797             $SIG{ALRM} = sub { print "dude! You're 'old' now.\n"; exit; }
798             my $eggtimer = localtime - $big40->at('06:57');
799             alarm($eggtimer);
800              
801             while(1) {
802             my $countdown = $big40-today;
803             print "$countdown days till the top of the hill\n";
804             sleep(3600*24);
805             }
806              
807             Wake me when the ball drops (in my time zone.)
808              
809             my $date = today+1*years;
810             $date = $date->start_of_year;
811             $SIG{ALRM} = sub { print "Happy new year!\n"; exit; }
812             alarm(localtime - $date->at('0s'));
813              
814             =head1 Constructor
815              
816             =head1 AUTHOR
817              
818             Eric Wilhelm @
819              
820             http://scratchcomputing.com/
821              
822             =head1 BUGS
823              
824             If you found this module on CPAN, please report any bugs or feature
825             requests through the web interface at L. I will be
826             notified, and then you'll automatically be notified of progress on your
827             bug as I make changes.
828              
829             If you pulled this development version from my /svn/, please contact me
830             directly.
831              
832             =head1 COPYRIGHT
833              
834             Copyright (C) 2007 Eric L. Wilhelm, All Rights Reserved.
835              
836             =head1 NO WARRANTY
837              
838             Absolutely, positively NO WARRANTY, neither express or implied, is
839             offered with this software. You use this software at your own risk. In
840             case of loss, no person or entity owes you anything whatsoever. You
841             have been warned.
842              
843             =head1 LICENSE
844              
845             This program is free software; you can redistribute it and/or modify it
846             under the same terms as Perl itself.
847              
848             =cut
849              
850             # vi:ts=2:sw=2:et:sta
851             1;