File Coverage

blib/lib/DateTime/Format/PGN.pm
Criterion Covered Total %
statement 53 75 70.6
branch 47 84 55.9
condition 29 114 25.4
subroutine 9 9 100.0
pod 3 3 100.0
total 141 285 49.4


line stmt bran cond sub pod time code
1 5     5   421164 use strict;
  5         9  
  5         126  
2 5     5   18 use warnings;
  5         5  
  5         231  
3              
4             package DateTime::Format::PGN;
5             # ABSTRACT: a Perl module for parsing and formatting date fields in chess game databases in PGN format
6              
7             our $VERSION = '0.05';
8              
9 5     5   2546 use DateTime::Incomplete 0.08;
  5         553242  
  5         169  
10 5     5   33 use Params::Validate 1.23 qw( validate BOOLEAN );
  5         51  
  5         5445  
11              
12              
13             sub new {
14 6     6 1 3025 my( $class ) = shift;
15              
16             my %args = validate( @_,
17             {
18             fix_errors => {
19             type => BOOLEAN,
20             default => 0,
21             callbacks => {
22             'is 0, 1, or undef' =>
23 3 50 33 3   45 sub { ! defined( $_[0] ) || $_[0] == 0 || $_[0] == 1 },
24             },
25             },
26             use_incomplete => {
27             type => BOOLEAN,
28             default => 0,
29             callbacks => {
30             'is 0, 1, or undef' =>
31 4 50 33 4   67 sub { ! defined( $_[0] ) || $_[0] == 0 || $_[0] == 1 },
32             },
33             },
34             }
35 6         133 );
36              
37 6   33     60 $class = ref( $class ) || $class;
38              
39 6         9 my $self = bless( \%args, $class );
40              
41 6         16 return( $self );
42             }
43              
44              
45              
46             sub parse_datetime {
47 42     42 1 89 my ( $self, $date ) = @_;
48 42         61 my @matches = ( '????', '??', '??' );
49            
50 42 100       144 if ($date =~ m/^(\?{4}|[1-2]\d{3})\.(\?{2}|0[1-9]|1[0-2])\.(\?{2}|0[1-9]|[1-2]\d|3[0-1])$/) {
51            
52 17         57 @matches = ( $1,$2,$3 );
53             }
54             else {
55            
56             # We can try to fix frequently occuring faults.
57 25 100       58 if ($self->{ fix_errors }) {
58            
59             # if we find a year, we can try to parse the wrong date.
60 24 50 33     162 if ($date =~ /(\A|\D)([1-2]\d{3})(\D|\Z)/ && $2 > 0) {
61            
62 24         33 $matches[0] = $2;
63            
64             # Try to find month and day.
65 24 100       134 if ($date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|3[0-1])\D+(0?[1-9]|[1-2][0-9]|3[0-1])(\D|\Z)/) {
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
66 20 100 100     111 if (($2 < 13 && $3 > 12) || ($2 == $3 && $2 < 13)) {
    100 33        
      66        
      66        
67 16         18 $matches[1] = $2;
68 16         20 $matches[2] = $3;
69             }
70             elsif ($3 < 13 && $2 > 12) {
71 2         2 $matches[1] = $3;
72 2         3 $matches[2] = $2;
73             }
74             }
75             elsif (index($date,'Jan') > -1) {
76 0         0 $matches[1] = 1;
77 0 0 0     0 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|3[0-1])(\D|\Z)/ && $2 < 32 && $2 > 0;
      0        
78             }
79             elsif (index($date,'Feb') > -1) {
80 0         0 $matches[1] = 2;
81 0 0 0     0 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9])(\D|\Z)/ && $2 < 32 && $2 > 0;
      0        
82             }
83             elsif (index($date,'Mar') > -1) {
84 0         0 $matches[1] = 3;
85 0 0 0     0 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|3[0-1])(\D|\Z)/ && $2 < 32 && $2 > 0;
      0        
86             }
87             elsif (index($date,'Apr') > -1) {
88 0         0 $matches[1] = 4;
89 0 0 0     0 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|30)(\D|\Z)/ && $2 < 32 && $2 > 0;
      0        
90             }
91             elsif (index($date,'May') > -1) {
92 0         0 $matches[1] = 5;
93 0 0 0     0 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|3[0-1])(\D|\Z)/ && $2 < 32 && $2 > 0;
      0        
94             }
95             elsif (index($date,'Jun') > -1) {
96 1         1 $matches[1] = 6;
97 1 50 33     10 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|30)(\D|\Z)/ && $2 < 32 && $2 > 0;
      33        
98             }
99             elsif (index($date,'Jul') > -1) {
100 0         0 $matches[1] = 7;
101 0 0 0     0 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|3[0-1])(\D|\Z)/ && $2 < 32 && $2 > 0;
      0        
102             }
103             elsif (index($date,'Aug') > -1) {
104 0         0 $matches[1] = 8;
105 0 0 0     0 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|3[0-1])(\D|\Z)/ && $2 < 32 && $2 > 0;
      0        
106             }
107             elsif (index($date,'Sep') > -1) {
108 0         0 $matches[1] = 9;
109 0 0 0     0 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|30)(\D|\Z)/ && $2 < 32 && $2 > 0;
      0        
110             }
111             elsif (index($date,'Oct') > -1) {
112 0         0 $matches[1] = 10;
113 0 0 0     0 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|3[0-1])(\D|\Z)/ && $2 < 32 && $2 > 0;
      0        
114             }
115             elsif (index($date,'Nov') > -1) {
116 0         0 $matches[1] = 11;
117 0 0 0     0 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|30)(\D|\Z)/ && $2 < 32 && $2 > 0;
      0        
118             }
119             elsif (index($date,'Dec') > -1) {
120 0         0 $matches[1] = 12;
121 0 0 0     0 $matches[2] = $2 if $date =~ /(\A|\D)(0?[1-9]|[1-2][0-9]|3[0-1])(\D|\Z)/ && $2 < 32 && $2 > 0;
      0        
122             }
123            
124             # check month length
125 24 100 66     86 if (index($matches[1],'?') == -1 && index($matches[2],'?') == -1) {
126 19 100 100     123 if ($matches[2] == 31 && ($matches[1] == 4 || $matches[1] == 6 || $matches[1] == 9 || $matches[1] == 9 || $matches[1] == 11)) {
    100 66        
127 4         5 $matches[1] = '??';
128 4         5 $matches[2] = '??';
129             }
130             elsif ($matches[1] == 2) {
131 4 100 100     27 if (($matches[2] == 29 && $matches[0] % 4 == 0 && $matches[0] % 100 > 0) || $matches[2] < 29) {}
      100        
      66        
132             else {
133 3         45 $matches[1] = '??';
134 3         4 $matches[2] = '??';
135             }
136             }
137             }
138             }
139             }
140             }
141            
142             # If incomplete data should be preserved, we must create a DateTime::Incomplete object instead.
143 42 100       86 if ( $self->{ use_incomplete } ) {
144            
145 25 100       27 grep { $_ = undef if index($_,'?') > -1 } @matches;
  75         195  
146            
147 25         100 return DateTime::Incomplete->new(
148             year => $matches[0],
149             month => $matches[1],
150             day => $matches[2],
151             formatter => $self,
152             );
153             }
154             # Otherwise the usual DateTime object.
155             else {
156            
157 17 100       20 grep { $_ = 1 if index($_,'?') > -1 } @matches;
  51         133  
158            
159 17         68 return DateTime->new(
160             year => $matches[0],
161             month => $matches[1],
162             day => $matches[2],
163             formatter => $self,
164             );
165             }
166             }
167              
168              
169             sub format_datetime {
170 42     42 1 3668 my ( $self, $dt ) = @_;
171            
172 42 100       81 my $year = (defined $dt->year()) ? $dt->year() : '????';
173 42 100       318 my $month = (defined $dt->month()) ? $dt->month() : '??';
174 42 100       247 my $day = (defined $dt->day()) ? $dt->day() : '??';
175            
176 42         388 return sprintf '%04s.%02s.%02s', $year, $month, $day;
177             }
178              
179             1;
180              
181             __END__