File Coverage

blib/lib/Time/Duration/Parse/AsHash.pm
Criterion Covered Total %
statement 27 27 100.0
branch 14 14 100.0
condition 7 14 50.0
subroutine 2 2 100.0
pod 1 1 100.0
total 51 58 87.9


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.5'; # VERSION
5              
6             #IFUNBUILT
7             # # use strict;
8             # # use warnings;
9             #END IFUNBUILT
10              
11 1     1   12730 use Exporter;
  1         1  
  1         484  
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 48     48 1 61 my $timespec = shift;
36              
37             # You can have an optional leading '+', which has no effect
38 48         68 $timespec =~ s/^\s*\+\s*//;
39              
40             # Treat a plain number as a number of seconds (and parse it later)
41 48 100       181 if ($timespec =~ /^\s*(-?\d+(?:[.,]\d+)?)\s*$/) {
42 5         13 $timespec = "$1s";
43             }
44              
45             # Convert hh:mm(:ss)? to something we understand
46 48         63 $timespec =~ s/\b(\d+):(\d\d):(\d\d(?:\.\d+)?)\b/$1h $2m $3s/g;
47 48         54 $timespec =~ s/\b(\d+):(\d\d)\b/$1h $2m/g;
48              
49 48         40 my %res;
50 48         213 while ($timespec =~ s/^\s*(-?\d+(?:[.,]\d+)?)\s*([a-zA-Z]+)(?:\s*(?:,|and)\s*)*//i) {
51 75         111 my($amount, $unit) = ($1, $2);
52 75 100       123 $unit = lc($unit) unless length($unit) == 1;
53              
54 75 100       111 if (my $canon_unit = $Units{$unit}) {
55 73         64 $amount =~ s/,/./;
56 73 100       100 if (my $convert = $Converts{$canon_unit}) {
57 4         6 $canon_unit = $convert->[0];
58 4         12 $amount *= $convert->[1];
59             }
60 73         274 $res{$canon_unit} += $amount;
61             } else {
62 2         18 die "Unknown timespec: $1 $2";
63             }
64             }
65              
66 46 100       63 if ($timespec =~ /\S/) {
67 1         7 die "Unknown timespec: $timespec";
68             }
69              
70 45         108 for (keys %res) {
71 70 100       119 delete $res{$_} if $res{$_} == 0;
72             }
73              
74 45 100       59 if ($_[0]) {
75             return
76             ( $res{seconds} || 0) +
77             (($res{minutes} || 0) * 60) +
78             (($res{hours} || 0) * 3600) +
79             (($res{days} || 0) * 86400) +
80             (($res{weeks} || 0) * 7*86400) +
81             (($res{months} || 0) * 30*86400) +
82 1   50     24 (($res{years} || 0) * 365*86400);
      50        
      50        
      50        
      50        
      50        
      50        
83             }
84              
85 44         101 \%res;
86             }
87              
88             1;
89             # ABSTRACT: Parse string that represents time duration
90              
91             __END__