File Coverage

blib/lib/Time/Duration/Parse/More.pm
Criterion Covered Total %
statement 48 49 97.9
branch 17 20 85.0
condition 3 3 100.0
subroutine 6 7 85.7
pod 2 2 100.0
total 76 81 93.8


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.008'; # VERSION
5             our $AUTHORITY = 'cpan:MELO'; # AUTHORITY
6              
7 1     1   12954 use strict;
  1         1  
  1         24  
8 1     1   3 use warnings;
  1         1  
  1         21  
9 1     1   3 use Exporter;
  1         1  
  1         43  
10 1     1   6 use Carp;
  1         0  
  1         690  
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 71     71 1 2019166 my ($expression) = @_;
30 71 50       128 return unless defined $expression;
31              
32 71 50       114 return $cache{$expression} if exists $cache{$expression};
33              
34 71         87 my ($val, $cacheable) = _parse_duration($expression);
35 64 100       94 return $val unless $cacheable;
36 58         150 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 71     71   64 my ($expression) = @_;
43 71 50       83 return unless defined $expression;
44              
45 71         66 my $e = $expression;
46              
47             ### split up 1h2m3s...
48 71         173 my $n_re = qr{[-+]?\d+(?:[.,]\d+)?};
49 71         552 $e =~ s/ ($n_re) ([hsm]) (?= $n_re [hsm]) /$1 $2 /gxi;
50 71         327 $e =~ s/ ($n_re) ([hsm]) \b / $1 $2 /gxi;
51              
52 71         143 $e =~ s/\band\b/ /gi;
53 71         198 $e =~ s/[\s\t]+/ /g;
54 71         203 $e =~ s/^\s+|\s+$//g;
55              
56 71         139 $e =~ s/^\s*([-+]?\d+(?:[.,]\d+)?)\s*$/$1s/;
57 71         91 $e =~ s/^\s*([-+]?[.,]\d+)\s*$/$1s/;
58 71         64 $e =~ s/\b(\d+):(\d+):(\d+)\b/$1h $2m $3s/g;
59 71         74 $e =~ s/\b(\d+):(\d+)\b/$1h $2m/g;
60              
61 71         49 my $duration = 0;
62 71         33 my $cacheable = 1;
63 71         49 my $signal = 1;
64 71         107 while ($e) {
65 130 100 100     627 if ($e =~ s/^plus\b(\s*,?)*//) { $signal = 1 }
  5 100       8  
    100          
    100          
66 7         15 elsif ($e =~ s/^minus\b(\s*,?)*//) { $signal = -1 }
67             elsif ($e =~ s/^(([-+]?\d+(?:[,.]\d*)?)\s*(\w+))(\s*,?)*// or $e =~ s/^(([-+]?[,.]\d+)\s*(\w+))(\s*,?)*//) {
68 108         169 my ($m, $n, $u) = ($1, $2, $3);
69 108         83 $n =~ s/,/./;
70 108 100       166 $u = lc($u) unless length($u) == 1;
71 108 100       608 croak "Unit '$u' not recognized in '$m'" unless exists $units{$u};
72 105         256 $duration += $signal * $n * $units{$u};
73             }
74             elsif ($e =~ s/^midnight\b(\s*,?)*//) {
75 6         20 my ($sec, $min, $hour) = (localtime())[0 .. 2];
76 6         252 $duration += $signal * (60 - $sec + (60 - $min - 1) * 60 + (24 - $hour - 1) * 60 * 60);
77              
78             ## 'midnight' is uncacheable
79 6         15 $cacheable = 0;
80             }
81             else {
82 4         379 croak("Could not parse '$e'");
83             }
84             }
85              
86 64         249 return (sprintf('%.0f', $duration), $cacheable);
87             }
88              
89              
90             1;
91              
92             __END__