File Coverage

blib/lib/EB/Utils.pm
Criterion Covered Total %
statement 106 131 80.9
branch 61 96 63.5
condition 23 51 45.1
subroutine 7 15 46.6
pod 0 6 0.0
total 197 299 65.8


line stmt bran cond sub pod time code
1             #! perl
2              
3             # Utils.pm --
4             # Author : Johan Vromans
5             # Created On : Wed Sep 21 13:09:01 2005
6             # Last Modified By: Johan Vromans
7             # Last Modified On: Tue May 14 20:21:30 2013
8             # Update Count : 127
9             # Status : Unknown, Use with caution!
10              
11             package EB::Utils;
12              
13 6     6   17 use strict;
  6         6  
  6         141  
14              
15 6     6   18 use base qw(Exporter);
  6         4  
  6         400  
16              
17             our @EXPORT;
18             our @EXPORT_OK;
19              
20 6     6   2467 use Time::Local;
  6         6454  
  6         8724  
21              
22             # We're imported by EB that exports _T. Kinda catch-22.
23             *_T = *EB::_T;
24              
25             # These are only used by the BTW Aangifte modules.
26             # Note these are translated using _T where appropriate.
27             our @months =
28             split(" ", "Jan Feb Mrt Apr Mei Jun Jul Aug Sep Okt Nov Dec");
29             our @month_names =
30             split(" ", "Januari Februari Maart April Mei Juni Juli Augustus September Oktober November December");
31             our @days =
32             split(" ", "Zon Maa Din Woe Don Vri Zat");
33             our @day_names =
34             split(" ", "Zondag Maandag Dinsdag Woensdag Donderdag Vrijdag Zaterdag");
35              
36             my $_i;
37              
38             my %rev_months;
39             $_i = 1;
40             foreach ( @months ) {
41             $rev_months{ lc $_ } = $_i;
42             $rev_months{ "m$_i" } = $_i;
43             $rev_months{ sprintf("m%02d", $_i) } = $_i;
44             $_i++;
45             }
46              
47             my %rev_month_names;
48             $_i = 1;
49             foreach ( @month_names ) {
50             $rev_month_names{ lc $_ } = $_i++;
51             }
52              
53             sub parse_date {
54 78     78 0 26607 my ($date, $default_year, $delta_d, $delta_m, $delta_y) = @_;
55              
56             # Parse a date and return it in ISO format (scalar) or
57             # (YYYY,MM,DD) list context.
58              
59 78         64 my ($d, $m, $y);
60 78 100       266 if ( $date =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/ ) {
    100          
    50          
    0          
61 74         159 ($y, $m, $d) = ($1, $2, $3);
62             }
63             elsif ( $date =~ /^(\d\d?)-(\d\d?)-(\d\d\d\d)$/ ) {
64 2         6 ($d, $m, $y) = ($1, $2, $3);
65             }
66             elsif ( $date =~ /^(\d\d?)-(\d\d?)$/ ) {
67 2 50       4 return unless $default_year;
68 2         6 ($d, $m, $y) = ($1, $2, $default_year);
69             }
70             elsif ( $date =~ /^(\d\d?) (\w+)$/ ) {
71 0 0       0 return unless $default_year;
72 0 0 0     0 return unless $m = $rev_month_names{$2} || $rev_months{$2};
73 0         0 ($d, $y) = ($1, $default_year);
74             }
75             else {
76 0         0 return; # invalid format
77             }
78              
79             # The date, as delivered, must be valid.
80 78         81 my $time = eval { timelocal(0, 0, 12, $d, $m-1, $y) };
  78         204  
81 78 50       2792 return unless $time; # invalid date
82              
83             # Handle deltas.
84 78 50       106 $y += $delta_y if $delta_y;
85 78 100       95 $m += $delta_m if $delta_m;
86 78         111 while ( $m > 12 ) { $m -= 12, $y++ }
  0         0  
87 78         97 while ( $m < 1 ) { $m += 12; $y-- }
  0         0  
  0         0  
88 78         80 $delta_d += $d - 1;
89              
90             # New date, as of 1st of the month.
91 78         68 $time = eval { timelocal(0, 0, 12, 1, $m-1, $y) };
  78         122  
92 78 50       1968 return unless $time; # invalid date
93              
94             # Apply delta.
95 78 100       126 $time += $delta_d * 24*60*60 if $delta_d;
96              
97             # Convert and return.
98 78         542 my @tm = localtime($time);
99 78         171 @tm = (1900 + $tm[5], 1 + $tm[4], $tm[3]);
100 78 100       297 wantarray ? @tm : sprintf("%04d-%02d-%02d", @tm);
101             }
102              
103             push( @EXPORT, qw(parse_date) );
104              
105             sub parse_date_range {
106 23     23 0 7789 my ($range, $default_year) = @_;
107              
108             # Parse a date and return it as an array ref of two ISO formatted
109             # dates.
110              
111 23         21 my ($d1, $m1, $y1, $d2, $m2, $y2);
112 0         0 my $datefix;
113              
114 23         32 $range = lc($range);
115              
116             # 2004-03-04 - 2004-05-06 -> [ "2004-03-04", "2004-05-06" ]
117 23 100 66     363 if ( $range =~ /^(\d\d\d\d)-(\d\d)-(\d\d)\s*[-\/]\s*(\d\d\d\d)-(\d\d)-(\d\d)$/ ) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
118 2         10 ($y1, $m1, $d1, $y2, $m2, $d2) = ($1, $2, $3, $4, $5, $6);
119             }
120             # 2004-03-04/05-06 -> [ "2004-03-04", "2004-05-06" ]
121             elsif ( $range =~ /^(\d\d\d\d)-(\d\d)-(\d\d)\s*\/\s*(\d\d)-(\d\d)$/ ) {
122 1         5 ($y1, $m1, $d1, $y2, $m2, $d2) = ($1, $2, $3, $1, $4, $5);
123             }
124             # 2004-03-04/06 -> [ "2004-03-04", "2004-03-06" ]
125             elsif ( $range =~ /^(\d\d\d\d)-(\d\d)-(\d\d)\s*\/\s*(\d\d)$/ ) {
126 1         6 ($y1, $m1, $d1, $y2, $m2, $d2) = ($1, $2, $3, $1, $2, $4);
127             }
128             # 03-04-2004 - 05-06-2004 -> [ "2004-04-03", "2004-06-05" ]
129             elsif ( $range =~ /^(\d\d)-(\d\d)-(\d\d\d\d)\s*-\s*(\d\d)-(\d\d)-(\d\d\d\d)$/ ) {
130 1         4 ($d1, $m1, $y1, $d2, $m2, $y2) = ($1, $2, $3, $4, $5, $6);
131             }
132             # 03-04 - 05-06 -> [ "2004-04-03", "2004-06-25" ]
133             elsif ( $range =~ /^(\d\d)-(\d\d)\s*-\s*(\d\d)-(\d\d)$/ ) {
134 1 50       4 return unless $default_year;
135 1         4 ($d1, $m1, $y1, $d2, $m2, $y2) = ($1, $2, $default_year, $3, $4, $default_year);
136             }
137             # 3 april - 5 juni -> [ "2004-04-03", "2004-06-25" ]
138             # 3 april - 5 juni 2004 -> [ "2004-04-03", "2004-06-25" ]
139             elsif ( $range =~ /^(\d+)\s+(\w+)\s*-\s*(\d+)\s+(\w+)(?:\s+(\d{4}))?$/ ) {
140 2 50       4 return unless $default_year;
141 2 50 33     9 return unless $m1 = $rev_month_names{$2} || $rev_months{$2};
142 2 50 33     10 return unless $m2 = $rev_month_names{$4} || $rev_months{$4};
143 2         3 $d1 = $1; $d2 = $3;
  2         2  
144 2   66     7 $y1 = $y2 = $5 || $default_year;
145             }
146             # 3 april 2004 - 5 juni 2004 -> [ "2004-04-03", "2004-06-25" ]
147             elsif ( $range =~ /^(\d+)\s+(\w+)\s+(\d{4})\s*-\s*(\d+)\s+(\w+)\s+(\d{4})$/ ) {
148 1 50 33     7 return unless $m1 = $rev_month_names{$2} || $rev_months{$2};
149 1 50 33     7 return unless $m2 = $rev_month_names{$5} || $rev_months{$5};
150 1         1 $d1 = $1; $d2 = $4;
  1         1  
151 1         2 $y1 = $3; $y2 = $6;
  1         1  
152             }
153             # april - juni -> [ "2004-04-01", "2004-06-30" ]
154             # april - juni 2004 -> [ "2004-04-01", "2004-06-30" ]
155             elsif ( $range =~ /^(\w+)\s*-\s*(\w+)(?:\s+(\d{4}))?$/ ) {
156 2 50       6 return unless $default_year;
157 2 50 33     9 return unless $m1 = $rev_month_names{$1} || $rev_months{$1};
158 2 50 33     10 return unless $m2 = $rev_month_names{$2} || $rev_months{$2};
159 2         2 $d1 = 1; $d2 = -1;
  2         3  
160 2   66     6 $y1 = $y2 = $3 || $default_year;
161             }
162             # 2004 -> [ "2004-01-01", "2004-12-31" ]
163             elsif ( $range =~ /^(\d{4})$/ ) {
164 1         2 $d1 = 1; $d2 = -1; $m1 = 1; $m2 = 12; $y1 = $y2 = $1;
  1         2  
  1         2  
  1         1  
  1         2  
165             }
166             # k2 -> [ "2004-04-01", "2004-06-30" ]
167             # k2 2004 -> [ "2004-04-01", "2004-06-30" ]
168             elsif ( $range =~ /^[kq](\d+)(?:\s+(\d{4}))?$/ ) {
169 2 50 66     10 return unless $2||$default_year;
170 2 50 33     10 return unless $1 >= 1 && $1 <= 4;
171 2         5 $m1 = 3 * $1 - 2;
172 2         2 $m2 = $m1 + 2;
173 2   66     2 $d1 = 1; $d2 = -1; $y1 = $y2 = $2 || $default_year;
  2         1  
  2         6  
174             }
175             # jaar -> [ "2004-01-01", "2004-12-31" ]
176             elsif ( $range eq lc(EB::_T("jaar")) || $range eq "jaar" ) {
177 2 50       4 return unless $default_year;
178 2         2 $d1 = 1; $d2 = -1; $m1 = 1; $m2 = 12; $y1 = $y2 = $default_year;
  2         1  
  2         2  
  2         2  
  2         2  
179             }
180             # apr | april -> [ "2004-04-01", "2004-04-30" ]
181             # apr 2004 -> [ "2004-04-01", "2004-04-30" ]
182             elsif ( $range =~ /^(\w+)(?:\s+(\d{4}))?$/ ) {
183 7 50 66     33 return unless $2||$default_year;
184 7 50 66     27 return unless $m1 = $m2 = $rev_month_names{$1} || $rev_months{$1};
185 7         6 $d1 = 1; $d2 = -1;
  7         6  
186 7   66     17 $y1 = $y2 = $2 || $default_year;
187             }
188             else {
189 0         0 return; # unrecognizable format
190             }
191              
192 23 100       47 if ( $d2 < 0 ) {
193 14         7 $datefix = 24 * 60 * 60;
194 14         10 $d2 = 1;
195 14 100       19 $m2 = 1, $y2++ if ++$m2 > 12;
196             }
197              
198 23         22 my $time1 = eval { timelocal(0, 0, 12, $d1, $m1-1, $y1) };
  23         50  
199 23 50       871 return unless $time1; # invalid date
200 23         20 my $time2 = eval { timelocal(0, 0, 12, $d2, $m2-1, $y2) };
  23         114  
201 23 50       662 return unless $time2; # invalid date
202 23 100       32 $time2 -= $datefix if $datefix;
203              
204 23         168 my @tm = localtime($time1);
205 23         42 my @tm1 = (1900 + $tm[5], 1 + $tm[4], $tm[3]);
206 23         149 @tm = localtime($time2);
207 23         43 my @tm2 = (1900 + $tm[5], 1 + $tm[4], $tm[3]);
208 23         125 [ sprintf("%04d-%02d-%02d", @tm1),
209             sprintf("%04d-%02d-%02d", @tm2) ]
210             }
211              
212             push( @EXPORT, qw(parse_date_range) );
213              
214             sub iso8601date {
215 0   0 0 0 0 my ($time) = shift || time;
216 0         0 my @tm = localtime($time);
217 0         0 sprintf("%04d-%02d-%02d", 1900+$tm[5], 1+$tm[4], $tm[3]);
218             }
219              
220             push( @EXPORT, qw(iso8601date) );
221              
222 0 0   0 0 0 sub min { $_[0] < $_[1] ? $_[0] : $_[1] }
223 0 0   0 0 0 sub max { $_[0] > $_[1] ? $_[0] : $_[1] }
224              
225             push( @EXPORT, qw(min max) );
226              
227             # Locale / Gettext.
228             # Variable expansion. See GNU gettext for details.
229             sub __expand($%) {
230 46     46   66 my ($t, %args) = @_;
231 46         68 my $re = join('|', map { quotemeta($_) } keys(%args));
  70         130  
232 46 50       410 $t =~ s/\{($re)\}/defined($args{$1}) ? $args{$1} : "{$1}"/ge;
  70         222  
233 46         144 $t;
234             }
235              
236             # Translation w/ variables.
237             sub __x($@) {
238 46     46   107 my ($t, %vars) = @_;
239 46         873 __expand(_T($t), %vars);
240             }
241              
242             # Translation w/ singular/plural handling.
243             sub __n($$$) {
244 0     0     my ($sing, $plur, $n) = @_;
245 0 0         _T($n == 1 ? $sing : $plur);
246             }
247              
248             # Translation w/ singular/plural handling and variables.
249             sub __nx($$$@) {
250 0     0     my ($sing, $plur, $n, %vars) = @_;
251 0           __expand(__n($sing, $plur, $n), %vars);
252             }
253              
254             # Make __xn a synonym for __nx.
255             *__xn = \&__nx;
256              
257             # And the dummy...
258 0     0 0   sub N__($) { $_[0] };
259              
260             # This is for context sensitive translations, where e.g., cmd:btw
261             # translates to cmd:vat and we deliver need the part after the colon.
262             sub __xt {
263 0     0     my $t = _T($_[0]);
264 0           $t =~ s/^.*://;
265 0           $t;
266             }
267              
268             # Same, without translating.
269             # Basically, __xt is __XN(_T($_[0])).
270             sub __XN {
271 0     0     my $t = $_[0];
272 0           $t =~ s/^.*://;
273 0           $t;
274             }
275              
276             push( @EXPORT, qw( __x __n __nx __xn N__ __xt __XN ) );
277              
278             # ... more to come ...
279              
280             @EXPORT_OK = @EXPORT;
281              
282             1;