File Coverage

blib/lib/Time/Duration/Parse/AsHash.pm
Criterion Covered Total %
statement 31 31 100.0
branch 12 12 100.0
condition n/a
subroutine 4 4 100.0
pod 1 1 100.0
total 48 48 100.0


line stmt bran cond sub pod time code
1             package Time::Duration::Parse::AsHash;
2              
3             our $DATE = '2016-05-17'; # DATE
4             our $VERSION = '0.10.3'; # VERSION
5              
6             #IFUNBUILT
7 1     1   13146 use strict;
  1         1  
  1         52  
8 1     1   4 use warnings;
  1         1  
  1         23  
9             #IFUNBUILT
10              
11 1     1   3 use Exporter;
  1         1  
  1         444  
12             our @ISA = qw( Exporter );
13             our @EXPORT = qw( parse_duration );
14              
15             my %Units = ( map(($_, "nanoseconds" ), qw(ns nanosecond nanoseconds)),
16             map(($_, "milliseconds"), qw(ms millisecond milliseconds milisecond miliseconds)),
17             map(($_, "microseconds"), qw(microsecond microseconds)),
18             map(($_, "seconds"), qw(s second seconds sec secs)),
19             map(($_, "minutes"), qw(m minute minutes min mins)),
20             map(($_, "hours"), qw(h hr hour hours)),
21             map(($_, "days"), qw(d day days)),
22             map(($_, "weeks"), qw(w week weeks)),
23             map(($_, "months"), qw(M month months mon mons mo mos)),
24             map(($_, "years"), qw(y year years)),
25             map(($_, "decades"), qw(decade decades)),
26             );
27             my %Converts = (
28             nanoseconds => ["seconds" => 1e-9],
29             microseconds => ["seconds" => 1e-6],
30             milliseconds => ["seconds" => 1e-3],
31             decades => ["years" => 10],
32             );
33              
34             sub parse_duration {
35 47     47 1 61 my $timespec = shift;
36              
37             # You can have an optional leading '+', which has no effect
38 47         71 $timespec =~ s/^\s*\+\s*//;
39              
40             # Treat a plain number as a number of seconds (and parse it later)
41 47 100       196 if ($timespec =~ /^\s*(-?\d+(?:[.,]\d+)?)\s*$/) {
42 5         11 $timespec = "$1s";
43             }
44              
45             # Convert hh:mm(:ss)? to something we understand
46 47         68 $timespec =~ s/\b(\d+):(\d\d):(\d\d(?:\.\d+)?)\b/$1h $2m $3s/g;
47 47         52 $timespec =~ s/\b(\d+):(\d\d)\b/$1h $2m/g;
48              
49 47         43 my %res;
50 47         209 while ($timespec =~ s/^\s*(-?\d+(?:[.,]\d+)?)\s*([a-zA-Z]+)(?:\s*(?:,|and)\s*)*//i) {
51 73         124 my($amount, $unit) = ($1, $2);
52 73 100       121 $unit = lc($unit) unless length($unit) == 1;
53              
54 73 100       109 if (my $canon_unit = $Units{$unit}) {
55 71         64 $amount =~ s/,/./;
56 71 100       164 if (my $convert = $Converts{$canon_unit}) {
57 4         4 $canon_unit = $convert->[0];
58 4         8 $amount *= $convert->[1];
59             }
60 71         258 $res{$canon_unit} += $amount;
61             } else {
62 2         16 die "Unknown timespec: $1 $2";
63             }
64             }
65              
66 45 100       64 if ($timespec =~ /\S/) {
67 1         7 die "Unknown timespec: $timespec";
68             }
69              
70 44         106 for (keys %res) {
71 68 100       780 delete $res{$_} if $res{$_} == 0;
72             }
73              
74 44         115 \%res;
75             }
76              
77             1;
78             # ABSTRACT: Parse string that represents time duration
79              
80             __END__