File Coverage

blib/lib/DateTime/Format/Human/Duration.pm
Criterion Covered Total %
statement 59 66 89.3
branch 42 50 84.0
condition n/a
subroutine 6 6 100.0
pod 3 3 100.0
total 110 125 88.0


line stmt bran cond sub pod time code
1             package DateTime::Format::Human::Duration;
2              
3 3     3   87361 use warnings;
  3         6  
  3         90  
4 3     3   15 use strict;
  3         7  
  3         171  
5             require DateTime::Format::Human::Duration::Locale;
6              
7             our $VERSION = '0.61';
8              
9 3     3   15 use Carp qw/croak/;
  3         9  
  3         2968  
10              
11             sub new {
12 2     2 1 531810 bless { 'locale_cache' => {} }, 'DateTime::Format::Human::Duration';
13             }
14              
15             sub format_duration_between {
16 9     9 1 198136 my ($span, $dt, $dtb, %args) = @_;
17 9         44 my $dur = $dt - $dtb;
18              
19 9 50       2470 if (!exists $args{'locale'}) {
20 9         30 $args{'locale'} = $dt->{'locale'}{'id'};
21             }
22            
23 9         33 return $span->format_duration($dur, %args);
24             }
25              
26             sub format_duration {
27 30     30 1 1066 my ($span, $duration, %args) = @_;
28            
29 30         79 my @default_units = qw(years months weeks days hours minutes seconds nanoseconds);
30              
31 30 100       96 my @units = $args{'units'} ? @{ $args{'units'} } : @default_units;
  3         9  
32 30 50       80 if ($args{'precision'}) {
33             # Reduce time resolution to requested precision
34 0         0 for (my $i = 0; $i < scalar(@units); $i++) {
35 0 0       0 next unless ($units[$i] eq $args{'precision'});
36 0         0 splice(@units, $i + 1);
37             }
38 0 0       0 croak('Useless precision') unless (@units);
39             }
40              
41 30         106 my @duration_vals = $duration->in_units( @units );
42 30         1235 my $i = 0;
43 30         54 my %duration_vals = map { ($_ => $duration_vals[$i++]) } @units;
  221         453  
44 30         106 my %positive_duration_vals = map { ($_ => abs $duration_vals{$_}) } keys %duration_vals;
  221         400  
45              
46 30         71 my $say = '';
47            
48             # $dta - $dtb:
49             # if dta < dtb means past -> future (Duration units will have negatives)
50             # else its either this absolute instant (no_time) or the past
51 30 100       44 if ( grep { $_ < 0 } @duration_vals ) {
  221         353  
52 23 100       78 if ( exists $args{'future'} ) {
53 4         9 $say = $args{'future'}
54             }
55             }
56             else {
57 7 100       23 if ( exists $args{'past'} ) {
58 2         5 $say = $args{'past'}
59             }
60             }
61            
62             ####
63             ## this is essentially the hashref that is returned from DateTime::Format::Human::Duration::en::get_human_span_hashref() : #
64             ####
65 30         339 my $setup = {
66             'no_oxford_comma' => 0,
67             'no_time' => 'no time', # The wait will be $formatted_duration
68             'and' => 'and',
69             'year' => 'year',
70             'years' => 'years',
71             'month' => 'month',
72             'months' => 'months',
73             'week' => 'week',
74             'weeks' => 'weeks',
75             'day' => 'day',
76             'days' => 'days',
77             'hour' => 'hour',
78             'hours' => 'hours',
79             'minute' => 'minute',
80             'minutes' => 'minutes',
81             'second' => 'second',
82             'seconds' => 'seconds',
83             'nanosecond' => 'nanosecond',
84             'nanoseconds' => 'nanoseconds',
85             };
86              
87 30         117 my $locale = DateTime::Format::Human::Duration::Locale::calc_locale($span, $args{'locale'});
88            
89 30 100       73 if($locale) {
90 7 100       49 if ( ref $locale eq 'HASH' ) {
    50          
    50          
91 5         159 %{ $setup } = (
  5         20  
92 5         19 %{ $setup },
93 5         6 %{ $locale },
94             );
95             }
96             # get_human_span_from_units_array is deprecated, but we will still
97             # support it.
98             elsif ( my $get1 = $locale->can('get_human_span_from_units_array') ) {
99 0         0 my @n = map { $positive_duration_vals{$_} } @default_units;
  0         0  
100 0         0 return $get1->( @n, \%args );
101             }
102             elsif ( my $get2 = $locale->can('get_human_span_from_units') ) {
103 2         9 return $get2->( \%duration_vals, \%args );
104             }
105             }
106              
107 28         55 my @parts;
108 28         43 for my $unit (@units) {
109 199         242 my $val = $positive_duration_vals{$unit};
110 199 100       447 next unless $val;
111              
112 46         52 my $setup_key = $unit;
113 46 100       89 if ($val == 1) {
114 21         84 $setup_key =~ s/s$//;
115             }
116              
117 46         100 push(@parts, $val . ' ' . $setup->{$setup_key});
118 46 100       114 if (exists $args{'significant_units'}) {
119 13 100       38 last if scalar(@parts) == $args{'significant_units'};
120             }
121             }
122            
123 28 100       73 my $no_time = exists $args{'no_time'} ? $args{'no_time'} : $setup->{'no_time'};
124 28 100       83 return $no_time if !@parts;
125              
126 25 100       59 my $last = @parts > 1 ? pop(@parts): '';
127              
128             ## We want to use the so-called Oxford comma to avoid ambiguity.
129             ## For that reason we make locale's specifically tell us they do not want it.
130 25 100       134 my $string = $setup->{'no_oxford_comma'}
    100          
    100          
    100          
131             ? join(', ', @parts) . ($last ? " $setup->{'and'} $last" : '')
132             : join(', ', @parts) . (@parts > 1 ? ',' : '') . ($last ? " $setup->{'and'} $last" : '')
133             ;
134              
135 25 100       51 if ( $say ) {
136 4 100       18 $string = $say =~ m{%s} ? sprintf($say, $string): "$say $string";
137             }
138              
139 25         278 return $string;
140             }
141              
142             1;
143              
144             __END__