File Coverage

blib/lib/Time/D.pm
Criterion Covered Total %
statement 205 235 87.2
branch 92 150 61.3
condition 48 60 80.0
subroutine 26 28 92.8
pod 13 13 100.0
total 384 486 79.0


line stmt bran cond sub pod time code
1 10     10   14190 use strict;
  10         16  
  10         255  
2 10     10   47 use warnings;
  10         19  
  10         686  
3             package Time::D;
4             $Time::D::VERSION = '0.024';
5             # ABSTRACT: Differentiate between two times.
6              
7             use overload (
8 4     4   4143 '""' => sub { shift->to_string(2); },
9 0     0   0 bool => sub { 1 },
10 10         86 fallback => 1,
11 10     10   958 );
  10         803  
12              
13 10     10   828 use Carp qw/ croak /;
  10         583  
  10         486  
14 10     10   623 use Function::Parameters qw/ :strict /;
  10         3171  
  10         54  
15 10     10   4753 use Time::C;
  10         21  
  10         236  
16 10     10   55 use Time::C::Sentinel;
  10         37  
  10         1465  
17              
18              
19              
20 9 50   9 1 4654 method new ($c: $base, $comp = $base) {
  9 50       28  
  9 100       19  
  9         39  
  9         18  
21 9         44 bless { base => $base, comp => $comp }, $c;
22             }
23              
24 195 50   195   447 method _setter ($d: $key, $new) {
  195 50       462  
  195         321  
  195         384  
  195         268  
25             return sub {
26 15     15   35 $d->{$key} = $_[0];
27 15 100       40 return $d if defined $new;
28 14         31 return $_[0];
29 195         729 };
30             }
31              
32 10 50   10   30 method _computed_setter ($d: $key, $new) {
  10 50       27  
  10         19  
  10         23  
  10         16  
33 10         18 my %diff;
34 10         26 @diff{qw/ sign year month week day hour minute second /} = $d->to_array();
35              
36 10         30 my $val = $diff{$key};
37              
38 10         33 my $ct = Time::C->gmtime($d->comp);
39             return $val, sub {
40 10 100   10   35 if ($diff{sign} eq '-') {
41 3         16 $ct->$key -= $_[0] - $val;
42             } else {
43 7         25 $ct->$key -= $val - $_[0];
44             }
45 10         52 $d->comp = $ct->epoch;
46              
47 10 50       57 return $d if defined $new;
48 10         41 return $_[0];
49 10         94 };
50             }
51              
52              
53              
54 79 50   79 1 228 method base ($d: $new_base = undef) :lvalue {
  79 50       199  
  79         128  
  79         159  
  79         118  
55 79         206 my $setter = $d->_setter('base', $new_base);
56              
57 79 50       223 return $setter->($new_base) if defined $new_base;
58              
59 79         319 sentinel value => $d->{base}, set => $setter;
60             }
61              
62              
63 116 50   116 1 768 method comp ($d: $new_comp = undef) :lvalue {
  116 50       278  
  116         197  
  116         217  
  116         159  
64 116         271 my $setter = $d->_setter('comp', $new_comp);
65              
66 116 100       309 return $setter->($new_comp) if defined $new_comp;
67              
68 115         387 sentinel value => $d->{comp}, set => $setter;
69             }
70              
71              
72 4 50   4 1 20 method sign ($d: $new_sign = undef) :lvalue {
  4 50       13  
  4         9  
  4         11  
  4         6  
73 4         8 my %diff;
74 4         15 @diff{qw/ sign year month week day hour minute second /} = $d->to_array();
75              
76 4         13 my $sign = $diff{sign};
77              
78 4         14 my $ct = Time::C->gmtime($d->comp);
79              
80             my $setter = sub {
81 4 50 66 4   24 if ($_[0] ne '+' and $_[0] ne '-') { croak "Can't set a sign other than '+' or '-'."; }
  0         0  
82              
83 4 50       12 if ($_[0] ne $sign) { $d->comp += 2*($d->base-$d->comp); }
  4         10  
84              
85 4 50       25 return $d if defined $new_sign;
86 4         14 return $_[0];
87 4         33 };
88              
89 4 50       15 return $setter->($new_sign) if defined $new_sign;
90              
91 4         15 sentinel value => $sign, set => $setter;
92             }
93              
94              
95 3 50   3 1 14 method years ($d: $new_years = undef) :lvalue {
  3 50       12  
  3         7  
  3         10  
  3         6  
96 3         21 my ($years, $setter) = $d->_computed_setter('year', $new_years);
97              
98 3 50       14 return $setter->($new_years) if defined $new_years;
99              
100 3         15 sentinel value => $years, set => $setter;
101             }
102              
103              
104 2 50   2 1 542 method months ($d: $new_months = undef) :lvalue {
  2 50       9  
  2         5  
  2         15  
  2         5  
105 2         8 my ($months, $setter) = $d->_computed_setter('month', $new_months);
106              
107 2 50       9 return $setter->($new_months) if defined $new_months;
108              
109 2         9 sentinel value => $months, set => $setter;
110             }
111              
112              
113 0 0   0 1 0 method weeks ($d: $new_weeks = undef) :lvalue {
  0 0       0  
  0         0  
  0         0  
  0         0  
114 0         0 my ($weeks, $setter) = $d->_computed_setter('week', $new_weeks);
115              
116 0 0       0 return $setter->($new_weeks) if defined $new_weeks;
117              
118 0         0 sentinel value => $weeks, set => $setter;
119             }
120              
121              
122 1 50   1 1 17 method days ($d: $new_days = undef) :lvalue {
  1 50       3  
  1         3  
  1         3  
  1         1  
123 1         4 my ($days, $setter) = $d->_computed_setter('day', $new_days);
124              
125 1 50       4 return $setter->($new_days) if defined $new_days;
126              
127 1         4 sentinel value => $days, set => $setter;
128             }
129              
130              
131 2 50   2 1 8 method hours ($d: $new_hours = undef) :lvalue {
  2 50       6  
  2         4  
  2         4  
  2         3  
132 2         7 my ($hours, $setter) = $d->_computed_setter('hour', $new_hours);
133              
134 2 50       7 return $setter->($new_hours) if defined $new_hours;
135              
136 2         8 sentinel value => $hours, set => $setter;
137             }
138              
139              
140 1 50   1 1 4 method minutes ($d: $new_minutes = undef) :lvalue {
  1 50       4  
  1         3  
  1         2  
  1         2  
141 1         4 my ($minutes, $setter) = $d->_computed_setter('minute', $new_minutes);
142              
143 1 50       5 return $setter->($new_minutes) if defined $new_minutes;
144              
145 1         5 sentinel value => $minutes, set => $setter;
146             }
147              
148              
149 1 50   1 1 6 method seconds ($d: $new_seconds = undef) :lvalue {
  1 50       4  
  1         2  
  1         3  
  1         2  
150 1         4 my ($seconds, $setter) = $d->_computed_setter('second', $new_seconds);
151              
152 1 50       4 return $setter->($new_seconds) if defined $new_seconds;
153              
154 1         5 sentinel value => $seconds, set => $setter;
155             }
156              
157              
158              
159 37 50   37 1 142 method to_array ($d:) {
  37 50       102  
  37         68  
  37         79  
160 37         116 my $bt = Time::C->gmtime($d->base);
161 37         273 my $ct = Time::C->gmtime($d->comp);
162              
163 37 100       230 my $sign = $d->base > $d->comp ? '-' : '+';
164              
165 37         247 my $years = $bt->tm->delta_years($ct->tm);
166 37         391 $ct->year -= $years;
167 37 50 66     325 if ($sign eq '+' and $bt->epoch > $ct->epoch) { $years--; $ct->year++; }
  0 50 66     0  
  0         0  
168 0         0 elsif ($sign eq '-' and $bt->epoch < $ct->epoch) { $years++; $ct->year--; }
  0         0  
169              
170 37         265 my $months = $bt->tm->delta_months($ct->tm);
171 37         338 $ct->month -= $months;
172 37 50 66     289 if ($sign eq '+' and $bt->epoch > $ct->epoch) { $months--; $ct->month++; }
  0 50 66     0  
  0         0  
173 0         0 elsif ($sign eq '-' and $bt->epoch < $ct->epoch) { $months++; $ct->month--; }
  0         0  
174              
175 37         222 my $weeks = $bt->tm->delta_weeks($ct->tm);
176 37         315 $ct->week -= $weeks;
177 37 50 66     336 if ($sign eq '+' and $bt->epoch > $ct->epoch) { $weeks--; $ct->week++; }
  0 50 66     0  
  0         0  
178 0         0 elsif ($sign eq '-' and $bt->epoch < $ct->epoch) { $weeks++; $ct->week--; }
  0         0  
179              
180 37         226 my $days = $bt->tm->delta_days($ct->tm);
181 37         303 $ct->day -= $days;
182 37 100 100     278 if ($sign eq '+' and $bt->epoch > $ct->epoch) { $days--; $ct->day++; }
  1 100 100     2  
  1         4  
183 5         11 elsif ($sign eq '-' and $bt->epoch < $ct->epoch) { $days++; $ct->day--; }
  5         14  
184              
185 37         227 my $hours = $bt->tm->delta_hours($ct->tm);
186 37         311 $ct->hour -= $hours;
187 37 50 66     301 if ($sign eq '+' and $bt->epoch > $ct->epoch) { $hours--; $ct->hour++; }
  0 50 66     0  
  0         0  
188 0         0 elsif ($sign eq '-' and $bt->epoch < $ct->epoch) { $hours++; $ct->hour--; }
  0         0  
189              
190 37         220 my $minutes = $bt->tm->delta_minutes($ct->tm);
191 37         320 $ct->minute -= $minutes;
192 37 50 66     289 if ($sign eq '+' and $bt->epoch > $ct->epoch) { $minutes--; $ct->minute++; }
  0 50 66     0  
  0         0  
193 0         0 elsif ($sign eq '-' and $bt->epoch < $ct->epoch) { $minutes++; $ct->minute--; }
  0         0  
194              
195 37         224 my $seconds = $bt->tm->delta_seconds($ct->tm);
196              
197 37 100       289 if ($sign eq '-') {
198 15         59 ($years, $months, $weeks, $days, $hours, $minutes, $seconds) =
199             (-$years, -$months, -$weeks, -$days, -$hours, -$minutes, -$seconds);
200             }
201              
202 37         383 return $sign, $years, $months, $weeks, $days, $hours, $minutes, $seconds;
203             }
204              
205 74 50   74   201 fun _plural ($num, $sing, $plur) { sprintf "%s %s", $num, $num == 1 ? $sing : $plur; }
  74 50       176  
  74 100       187  
  74         113  
  74         425  
206              
207              
208 22 50   22 1 150 method to_string ($d: $precision = 7) {
  22 50       69  
  22 100       57  
  22         91  
  22         37  
209 22         80 my ($sign, $years, $months, $weeks, $days, $hours, $minutes, $seconds) =
210             $d->to_array();
211              
212 22         54 my @out;
213              
214 22 100 66     132 if ($precision > 0 and $years) { $precision--; push @out, _plural($years, 'year', 'years'); }
  14         36  
  14         67  
215 22 100 100     133 if ($precision > 0 and $months) { $precision--; push @out, _plural($months, 'month', 'months'); }
  13         28  
  13         46  
216 22 100 100     126 if ($precision > 0 and $weeks) { $precision--; push @out, _plural($weeks, 'week', 'weeks'); }
  5         11  
  5         17  
217 22 100 100     115 if ($precision > 0 and $days) { $precision--; push @out, _plural($days, 'day', 'days'); }
  13         32  
  13         38  
218 22 100 100     113 if ($precision > 0 and $hours) { $precision--; push @out, _plural($hours, 'hour', 'hours'); }
  11         26  
  11         36  
219 22 100 100     113 if ($precision > 0 and $minutes) { $precision--; push @out, _plural($minutes, 'minute', 'minutes'); }
  12         29  
  12         37  
220 22 100 100     116 if ($precision > 0 and $seconds) { $precision--; push @out, _plural($seconds, 'second', 'seconds'); }
  6         13  
  6         22  
221              
222 22 100       92 return "now" unless @out;
223              
224 20 100       75 if (@out > 1) { $out[-1] = "and $out[-1]"; }
  18         55  
225              
226 20         91 my $pretty = join ", ", @out;
227              
228 20 100       255 return sprintf $sign eq '+' ? "in %s" : "%s ago", $pretty;
229             }
230              
231             1;
232              
233             __END__