File Coverage

blib/lib/Log/Parallel/Durations.pm
Criterion Covered Total %
statement 69 96 71.8
branch 29 52 55.7
condition 7 17 41.1
subroutine 7 7 100.0
pod 0 2 0.0
total 112 174 64.3


line stmt bran cond sub pod time code
1              
2             package Log::Parallel::Durations;
3              
4 1     1   19096 use strict;
  1         2  
  1         28  
5 1     1   5 use warnings;
  1         2  
  1         30  
6             require Exporter;
7 1     1   683 use List::EvenMoreUtils qw(keys_to_regex);
  1         1175  
  1         53  
8 1     1   1159 use Lingua::EN::Inflect qw(PL);
  1         19810  
  1         124  
9 1     1   843 use Time::JulianDay;
  1         3818  
  1         1182  
10              
11             our @ISA = qw(Exporter);
12             our @EXPORT = qw(frequency_and_span);
13              
14             my %span = (
15             # days months
16             day => [ 1, 0 ],
17             week => [ 7, 0 ],
18             month => [ 0, 1 ],
19             quarter => [ 0, 3 ],
20             year => [ 0, 12 ],
21             );
22              
23             my %translations = qw(
24             daily day
25             weekly week
26             monthly month
27             yearly year
28             quarterly quarter
29             );
30              
31             my %weekdays = qw(
32             sun 0 sunday 0
33             mon 1 monday 1
34             tue 2 tuesday 2
35             wed 3 wednesday 3
36             thu 4 thursday 4
37             fri 5 friday 5
38             sat 6 saturday 6
39             );
40              
41              
42             my %spans = map { PL($_) => $span{$_} } keys %span;
43             my %singular = map { PL($_) => $_ } keys %span;
44             my $re_trans = keys_to_regex(%translations);
45             my $re_span = keys_to_regex(%span);
46             my $re_spans = keys_to_regex(%spans);
47             my $re_wday = keys_to_regex(%weekdays);
48              
49             my %timely = map { $translations{$_} => $_ } keys %translations;
50              
51             my $re_nth = qr/(?:((?:[23]?1(?=st))|(?:2?2(?=nd))|(2?3(?=rd))|(?:(?:1\d|2?[04-9]|30)(?=th)))..)/;
52             my $re_small_nth = qr/(?:((?:1(?=st))|(?:2(?=nd))|(3(?=rd))|(?:4(?=th)))..)/;
53              
54             sub match_span
55             {
56 5     5 0 16 my ($jd, $from, $count, $type) = @_;
57 5         7 my ($sd, $sm) = @{$span{$type}};
  5         18  
58 5 50 33     35 die if $sd && $sm;
59 5 50       14 if ($sd) {
60 5 100       37 return 1 if ($jd - $from) % ($count * $sd) == 0;
61 2         13 return 0;
62             }
63 0         0 my ($y, $m, $d) = inverse_julian_day($jd);
64 0         0 my ($fy, $fm, $fd) = inverse_julian_day($from);
65 0 0       0 return 0 unless $d == $fd;
66 0         0 my $md = $m - $fm + $y*12 - $fy*12;
67 0 0       0 return 1 if $md % ($count * $sm) == 0;
68 0         0 return 0;
69             }
70              
71              
72             #use Tie::Function::Examples;
73             #tie my %yyyymmdd, 'Tie::Function::Examples',
74             # sub {
75             # my ($y, $m, $d) = inverse_julian_day($_[0]);
76             # return sprintf("%d-%02d-%02d", $y, $m, $d);
77             # };
78              
79             sub frequency_and_span
80             {
81 11     11 0 8091 my ($job, $jd, $jd_from_limit, $jd_to_limit) = @_;
82              
83             #print "F&S: $job->{name} $yyyymmdd{$jd} $yyyymmdd{$jd_from_limit} $yyyymmdd{$jd_to_limit} $job->{frequency}\n";
84              
85             #if $job->{frequency} && $job->{frequency} ne 'daily';
86              
87 11 50 33     77 return unless $jd >= $jd_from_limit && $jd <= $jd_to_limit;
88              
89 11   100     40 my $frequency = $job->{frequency} || 'daily';
90              
91 11         259 $frequency =~ s/\b($re_trans)\b/every $translations{$1}/g;
92              
93 11         43 my ($yyyy, $mm, $dd) = inverse_julian_day($jd);
94 11         199 my ($name, $count, $default_span);
95              
96 11 100       1236 if ($frequency =~ /^\s*(?:every\s+)?(\d+)\s+($re_spans)$/i) {
    100          
    50          
    100          
    50          
    100          
    50          
97 2         8 $count = $1;
98 2         6 $name = $singular{$2};
99 2         6 $default_span = "$count $name";
100 2 100       6 return unless match_span($jd, $jd_from_limit, $count, $name);
101             } elsif ($frequency =~ /^\s*every\s+($re_span)/i) {
102 3         7 $count = 1;
103 3         10 $name = $1;
104 3         8 $default_span = "$count $name";
105 3 100       12 return unless match_span($jd, $jd_from_limit, $count, $name);
106             } elsif ($frequency =~ /^\s*every\s+$re_nth\s+day\s+each\s+month\s*$/i) {
107 0         0 $name = "month";
108 0         0 $count = 1;
109 0 0       0 return unless $dd == $1;
110 0         0 $default_span = "1 month";
111             } elsif ($frequency =~ /^\s*(?:each\s+month,?\s+)?on\s+the\s+$re_nth(?:\s+(?:of\s+)?each\s+month)?\s*$/i) {
112 3         7 $name = "month";
113 3         5 $count = 1;
114 3 100       15 return unless $dd == $1;
115 2         3 $default_span = "1 month";
116             } elsif ($frequency =~ /^\s*every\s+($re_wday)\s*$/i) {
117 0         0 my $dow = $weekdays{lc($2)};
118 0 0       0 return unless $dow = day_of_week($jd);
119 0         0 $name = "week";
120 0         0 $count = 1;
121 0         0 $default_span = "1 week";
122             } elsif ($frequency =~ /^\s*(?:every|on\s+the)\s$re_small_nth\s+($re_wday)(?:\s+(?:of\s+)?each\s+month)?\s*$/i) {
123 2         7 $name = "month";
124 2         6 $count = 1;
125 2         6 $default_span = "1 month";
126 2         9 my $nth = $1;
127 2         12 my $dow = $weekdays{lc($2)};
128 2 100       14 return unless $dow = day_of_week($jd);
129 1         14 my $weeknum = int(($dd - 1)/ 7) + 1;
130 1 50       8 return unless $weeknum == $nth;
131             } elsif ($frequency =~ /^\s*range\s*$/) {
132 0 0       0 return unless $jd == $jd_to_limit;
133 0         0 my ($from_yyyy, $from_mm, $from_dd) = inverse_julian_day($jd_from_limit);
134 0         0 my ($yyyy, $mm, $dd) = inverse_julian_day($jd_to_limit);
135             return ({
136 0         0 YYYY => $yyyy,
137             FROM_YYYY => $from_yyyy,
138             MM => $mm,
139             FROM_MM => $from_mm,
140             DD => $dd,
141             FROM_DD => $from_dd,
142             DURATION => 'range',
143             FROM_JD => $jd_from_limit,
144             JD => $jd,
145             }, $jd_from_limit .. $jd_to_limit);
146             } else {
147 1         9 require Carp;
148 1         235 Carp::confess "could not parse frequency '$frequency'";
149             }
150              
151 6   33     37 my $timespan = $job->{timespan} || $default_span;
152              
153 6         11 my $duration;
154             my $spancount;
155 0         0 my $spanname;
156 6 50       190 if ($timespan =~ /^(\d+)\s+($re_spans)$/) {
    50          
    0          
157 0         0 $spancount = $singular{$1};
158 0         0 $spanname = $2;
159             } elsif ($timespan =~ /^(\d+)\s+($re_span)$/) {
160 6         19 $spancount = $1;
161 6         16 $spanname = $2;
162             } elsif ($timespan =~ /^\s*all ?time\s*$/) {
163 0 0       0 return unless $jd == $jd_to_limit;
164 0         0 $spancount = 0;
165             } else {
166 0         0 die "can't parse timespan '$timespan'";
167             }
168              
169 6         10 my ($spand, $spanm) = @{$span{$spanname}};
  6         19  
170 6         11 my $fy = $yyyy;
171 6         15 my $fm = $mm - $spanm * $spancount;
172 6         22 while ($fm < 1) {
173 0         0 $fy -= 1;
174 0         0 $fm += 12;
175             }
176 6         67 my $fromjd = julian_day($fy, $fm, $dd);
177 6         51 $fromjd -= $spand * $spancount;
178 6         12 $fromjd += 1; # don't overlap
179              
180 6 100       35 if ($count == 1) {
181 5   33     73 $duration ||= $timely{$name};
182             } else {
183 1   33     11 $duration ||= "$count$name";
184             }
185 6         24 my ($from_yyyy, $from_mm, $from_dd) = inverse_julian_day($fromjd);
186              
187             return ({
188 6         171 YYYY => $yyyy,
189             FROM_YYYY => $from_yyyy,
190             MM => $mm,
191             FROM_MM => $from_mm,
192             DD => $dd,
193             FROM_DD => $from_dd,
194             DURATION => $duration,
195             FROM_JD => $fromjd,
196             JD => julian_day($yyyy, $mm, $dd),
197             }, $fromjd .. $jd);
198             }
199              
200             1;
201              
202             __END__