File Coverage

blib/lib/DateTime/Format/Human/Duration.pm
Criterion Covered Total %
statement 10 69 14.4
branch 0 52 0.0
condition n/a
subroutine 4 6 66.6
pod 3 3 100.0
total 17 130 13.0


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