File Coverage

blib/lib/Data/FormValidator/Constraints/Dates.pm
Criterion Covered Total %
statement 48 48 100.0
branch 21 26 80.7
condition 7 14 50.0
subroutine 8 8 100.0
pod 1 2 50.0
total 85 98 86.7


line stmt bran cond sub pod time code
1             package Data::FormValidator::Constraints::Dates;
2 2     2   5389 use Exporter 'import';
  2         3  
  2         54  
3 2     2   35 use 5.005;
  2         4  
4 2     2   6 use strict;
  2         2  
  2         1011  
5              
6             our %EXPORT_TAGS = ( 'all' => [ qw() ] );
7              
8             our @EXPORT_OK = (
9             'date_and_time',
10             @{ $EXPORT_TAGS{'all'} }
11             );
12              
13             our @EXPORT = qw(
14             match_date_and_time
15             );
16              
17             our $VERSION = 4.85;
18              
19             sub date_and_time {
20 5     5 1 3071 my $fmt = shift;
21             return sub {
22 4     4   3 my $self = shift;
23 4         8 $self->set_current_constraint_name('date_and_time');
24 4         6 return match_date_and_time($self,\$fmt);
25             }
26 5         24 }
27              
28             sub match_date_and_time {
29 6     6 0 5 my $self = shift;
30 6   50     10 my $fmt_ref = shift || die q!date_and_time: need format parameter. Be sure to pass it by reference, like this: \'MM/DD/YYYY'!;
31 6         8 my $fmt = $$fmt_ref;
32              
33 6         14 require Date::Calc;
34 6         170 import Date::Calc (qw/check_date check_time/);
35              
36 6         8 my $format = _prepare_date_format($fmt);
37 6         16 my ($date,$Y,$M,$D,$h,$m,$s) = _parse_date_format($format,$self->get_current_constraint_value);
38 6 100       17 return if not defined $date;
39              
40              
41             # We need to check the date if we find any in the format string, otherwise, it succeeds
42 4         5 my $date_test = 1;
43 4 50       30 $date_test = check_date($Y,$M,$D) if ($fmt =~ /[YMD]/) ;
44              
45             # If we find a time, check that
46 4         5 my $time_test = 1;
47 4 100       17 $time_test = check_time($h,$m,$s) if ($fmt =~ /[hms]/) ;
48              
49             # If either the time or date fails, it all fails
50 4 100 66     30 return ($date_test && $time_test) ? $date : undef;
51             }
52              
53             sub _prepare_date_format {
54 11     11   9782 my $format = shift;
55              
56             # Originally by Jan Krynicky
57              
58             # TODO: check that only valid characters appear in the format
59             # The logic should be: for any character A-Z in the format string,
60             # die if it's not one of: Y M D h m s p
61              
62 11         18 my ($i, @order) = 0;
63 11         49 $format =~ s{(Y+|M+|D+|h+|m+|s+|pp)(\?)?}{
64 61         73 my ($chr,$q) = ($1,$2);
65 61 50       81 $chr = '' if not defined $chr;
66 61 50       67 $q = '' if not defined $chr;
67              
68 61         74 $order[$i++] = substr($chr,0,1);
69 61 100       63 if ($chr eq 'pp') {
70 6         11 "(AM|PM|am|pm)"
71             } else {
72 55 100       170 '(' . ('\d' x length($chr)) . ($q ? $q : "") . ")"
73             }
74             }ge;
75              
76              
77 11         232 $format = qr/^((?:$format))$/;
78 11         35 return [$format, \@order];
79             }
80              
81             sub _parse_date_format {
82             # Originally by Jan Krynicky
83              
84 11     11   31 my ($format, $date) = @_;
85 11 100       77 my ($untainted_date,@data) = ($date =~ $format->[0])
86             or return;
87 9         12 my %result;
88 9         17 for(my $i = 0; $i <= $#data; $i++) {
89 49   66     166 $result{$format->[1]->[$i]} ||= $data[$i];
90             }
91              
92 9 100       17 if (exists $result{p}) {
93 4 50 33     20 $result{h} += 12 if ($result{p} eq 'PM' and $result{h} != 12);
94 4 50 33     18 $result{h} = 0 if ($result{p} eq 'AM' and $result{h} == 12);
95             }
96              
97              
98 9 100       11 return $untainted_date, map {defined $result{$_} ? $result{$_} : 0} qw(Y M D h m s);
  54         105  
99             }
100              
101             1;
102             __END__