File Coverage

blib/lib/Time/Duration/Parse/More.pm
Criterion Covered Total %
statement 47 48 97.9
branch 17 20 85.0
condition 3 3 100.0
subroutine 6 7 85.7
pod 2 2 100.0
total 75 80 93.7


line stmt bran cond sub pod time code
1             package Time::Duration::Parse::More;
2              
3             # ABSTRACT: parse natural language time duration expressions
4             our $VERSION = '0.007'; # VERSION
5             our $AUTHORITY = 'cpan:MELO'; # AUTHORITY
6              
7 1     1   37147 use strict;
  1         2  
  1         51  
8 1     1   6 use warnings;
  1         2  
  1         34  
9 1     1   6 use Exporter;
  1         2  
  1         58  
10 1     1   55 use Carp;
  1         3  
  1         1095  
11              
12             our @ISA = qw( Exporter );
13             our @EXPORT = qw( parse_duration );
14              
15             # From Time::Duration::Parse
16             my %units = (
17             map(($_, 1), qw(s second seconds sec secs)),
18             map(($_, 60), qw(m minute minutes min mins)),
19             map(($_, 60 * 60), qw(h hr hour hours)),
20             map(($_, 60 * 60 * 24), qw(d day days)),
21             map(($_, 60 * 60 * 24 * 7), qw(w week weeks)),
22             map(($_, 60 * 60 * 24 * 30), qw(M month months)),
23             map(($_, 60 * 60 * 24 * 365), qw(y year years))
24             );
25              
26             my %cache;
27              
28             sub parse_duration {
29 70     70 1 2027475 my ($expression) = @_;
30 70 50       192 return unless defined $expression;
31              
32 70 50       157 return $cache{$expression} if exists $cache{$expression};
33              
34 70         121 my ($val, $cacheable) = _parse_duration($expression);
35 63 100       137 return $val unless $cacheable;
36 58         260 return $cache{$expression} = $val;
37             }
38              
39 0     0 1 0 sub parse_duration_nc { return (_parse_duration(@_))[0] }
40              
41             sub _parse_duration {
42 70     70   92 my ($expression) = @_;
43 70 50       137 return unless defined $expression;
44              
45             ## 'midnight' is uncacheable
46 70 100       135 if ($expression eq 'midnight') {
47 5         22 my ($sec, $min, $hour) = (localtime())[0 .. 2];
48 5         344 return (60 - $sec + (60 - $min - 1) * 60 + (24 - $hour - 1) * 60 * 60, 0);
49             }
50              
51 65         78 my $e = $expression;
52              
53             ### split up 1h2m3s...
54 65         205 my $n_re = qr{[-+]?\d+(?:[.,]\d+)?};
55 65         1763 $e =~ s/ ($n_re) ([hsm]) (?= $n_re [hsm]) /$1 $2 /gxi;
56 65         554 $e =~ s/ ($n_re) ([hsm]) \b / $1 $2 /gxi;
57              
58 65         189 $e =~ s/\band\b/ /gi;
59 65         364 $e =~ s/[\s\t]+/ /g;
60 65         316 $e =~ s/^\s+|\s+$//g;
61              
62 65         204 $e =~ s/^\s*([-+]?\d+(?:[.,]\d+)?)\s*$/$1s/;
63 65         178 $e =~ s/^\s*([-+]?[.,]\d+)\s*$/$1s/;
64 65         103 $e =~ s/\b(\d+):(\d+):(\d+)\b/$1h $2m $3s/g;
65 65         95 $e =~ s/\b(\d+):(\d+)\b/$1h $2m/g;
66              
67 65         70 my $duration = 0;
68 65         71 my $signal = 1;
69 65         127 while ($e) {
70 122 100 100     916 if ($e =~ s/^plus\b(\s*,?)*//) { $signal = 1 }
  4 100       10  
    100          
71 7         17 elsif ($e =~ s/^minus\b(\s*,?)*//) { $signal = -1 }
72             elsif ($e =~ s/^(([-+]?\d+(?:[,.]\d*)?)\s*(\w+))(\s*,?)*// or $e =~ s/^(([-+]?[,.]\d+)\s*(\w+))(\s*,?)*//) {
73 107         269 my ($m, $n, $u) = ($1, $2, $3);
74 107         145 $n =~ s/,/./;
75 107 100       221 $u = lc($u) unless length($u) == 1;
76 107 100       771 croak "Unit '$u' not recognized in '$m'" unless exists $units{$u};
77 104         372 $duration += $signal * $n * $units{$u};
78             }
79             else {
80 4         518 croak("Could not parse '$e'");
81             }
82             }
83              
84 58         287 return (sprintf('%.0f', $duration), 1);
85             }
86              
87              
88             1;
89              
90             __END__