File Coverage

blib/lib/Date/Parse.pm
Criterion Covered Total %
statement 142 181 78.4
branch 121 202 59.9
condition 41 78 52.5
subroutine 9 11 81.8
pod 1 2 50.0
total 314 474 66.2


line stmt bran cond sub pod time code
1             # Copyright (c) 1995-2009 Graham Barr. This program is free
2             # software; you can redistribute it and/or modify it under the same terms
3             # as Perl itself.
4              
5             package Date::Parse;
6              
7             require 5.000;
8 5     5   292914 use strict;
  5         9  
  5         177  
9 5     5   1563 use Time::Local;
  5         8415  
  5         311  
10 5     5   27 use Carp;
  5         16  
  5         278  
11 5     5   1496 use Time::Zone;
  5         12  
  5         299  
12 5     5   24 use Exporter;
  5         16  
  5         4021  
13              
14             our @ISA = qw(Exporter);
15             our @EXPORT = qw(&strtotime &str2time &strptime);
16              
17             our $VERSION = '2.34'; # VERSION: generated
18             # ABSTRACT: Parse date strings into time values
19              
20             my %month = (
21             january => 0,
22             february => 1,
23             march => 2,
24             april => 3,
25             may => 4,
26             june => 5,
27             july => 6,
28             august => 7,
29             september => 8,
30             sept => 8,
31             october => 9,
32             november => 10,
33             december => 11,
34             );
35              
36             my %day = (
37             sunday => 0,
38             monday => 1,
39             tuesday => 2,
40             tues => 2,
41             wednesday => 3,
42             wednes => 3,
43             thursday => 4,
44             thur => 4,
45             thurs => 4,
46             friday => 5,
47             saturday => 6,
48             );
49              
50             my @suf = (qw(th st nd rd th th th th th th)) x 3;
51             @suf[11,12,13] = qw(th th th);
52              
53             #Abbreviations
54              
55             map { $month{substr($_,0,3)} = $month{$_} } keys %month;
56             map { $day{substr($_,0,3)} = $day{$_} } keys %day;
57              
58             my $strptime = <<'ESQ';
59             my %month = map { lc $_ } %$mon_ref;
60             my $daypat = join("|", map { lc $_ } reverse sort keys %$day_ref);
61             my $monpat = join("|", reverse sort keys %month);
62             my $sufpat = join("|", reverse sort map { lc $_ } @$suf_ref);
63              
64             my %ampm = (
65             'a' => 0, # AM
66             'p' => 12, # PM
67             );
68              
69             my($AM, $PM) = (0,12);
70              
71             sub {
72              
73             my $dtstr = lc shift;
74             my $merid = 24;
75              
76             my($century,$year,$month,$day,$hh,$mm,$ss,$zone,$dst,$frac);
77              
78             $zone = tz_offset(shift) if @_;
79              
80             1 while $dtstr =~ s#\([^\(\)]*\)# #o;
81              
82             $dtstr =~ s#(\A|\n|\Z)# #sog;
83              
84             # ignore day names
85             $dtstr =~ s#([\d\w\s])[\.\,]\s#$1 #sog;
86             $dtstr =~ s/,/ /g;
87             $dtstr =~ s#($daypat)\s*(den\s)?\b# #o;
88             # Time: 12:00 or 12:00:00 with optional am/pm
89              
90             return unless $dtstr =~ /\S/;
91              
92             if ($dtstr =~ s/\s(\d{4})([-:]?)(\d\d?)\2(\d\d?)(?:[-Tt ](\d\d?)(?:([-:]?)(\d\d?)(?:\6(\d\d?)(?:[.,](\d+))?)?)?)?(?=\D)/ /) {
93             ($year,$month,$day,$hh,$mm,$ss,$frac) = ($1,$3-1,$4,$5,$7,$8,$9);
94             }
95              
96             # default C++ boost timestamp is effectively %Y-%b-%d %H:%M:%S.%f
97             # details: https://svn.boost.org/trac/boost/ticket/8839
98             if ($dtstr =~ s/\s(\d{4})([-:]?)(\w{3,})\2(\d\d?)(?:[-Tt ](\d\d?)(?:([-:]?)(\d\d?)(?:\6(\d\d?)(?:[.,](\d+))?)?)?)?(?=\D)/ /) {
99             ($year,$month,$day,$hh,$mm,$ss,$frac) = ($1,$month{$3},$4,$5,$7,$8,$9);
100             }
101              
102             unless (defined $hh) {
103             if ($dtstr =~ s#[:\s](\d\d?):(\d\d?)(:(\d\d?)(?:\.\d+)?)?(z)?\s*(?:([ap])\.?m?\.?)?\s# #o) {
104             ($hh,$mm,$ss) = ($1,$2,$4);
105             $zone = 0 if $5;
106             $merid = $ampm{$6} if $6;
107             }
108              
109             # Time: 12 am
110              
111             elsif ($dtstr =~ s#\s(\d\d?)\s*([ap])\.?m?\.?\s# #o) {
112             ($hh,$mm,$ss) = ($1,0,0);
113             $merid = $ampm{$2};
114             }
115             }
116              
117             if (defined $hh and $hh <= 12 and $dtstr =~ s# ([ap])\.?m?\.?\s# #o) {
118             $merid = $ampm{$1};
119             }
120              
121              
122             unless (defined $year) {
123             # Date: 12-June-96 (using - . or /)
124              
125             if ($dtstr =~ s#\s(\d\d?)([\-\./])($monpat)(\2(\d\d+))?\s# #o) {
126             ($month,$day) = ($month{$3},$1);
127             $year = $5 if $5;
128             }
129              
130             # Date: 12-12-96 (using '-', '.' or '/' )
131              
132             elsif ($dtstr =~ s#\s(\d+)([\-\./])(\d\d?)(\2(\d+))?\s# #o) {
133             ($month,$day) = ($1 - 1,$3);
134              
135             if ($5) {
136             $year = $5;
137             # Possible match for 1995-01-24 (short mainframe date format);
138             ($year,$month,$day) = ($1, $3 - 1, $5) if $month > 12;
139             return if length($year) > 2 and $year < 1901;
140             }
141             }
142             elsif ($dtstr =~ s#\s(\d+)\s*($sufpat)?\s*($monpat)# #o) {
143             ($month,$day) = ($month{$3},$1);
144             }
145             elsif ($dtstr =~ s#($monpat)\s*(\d+)\s*($sufpat)?\s# #o) {
146             ($month,$day) = ($month{$1},$2);
147             }
148             elsif ($dtstr =~ s#($monpat)([\/-])(\d+)[\/-]# #o) {
149             ($month,$day) = ($month{$1},$3);
150             }
151              
152             # Date: 961212
153              
154             elsif ($dtstr =~ s#\s(\d\d)(\d\d)(\d\d)\s# #o) {
155             ($year,$month,$day) = ($1,$2-1,$3);
156             }
157              
158             $year = $1 if !defined($year) and $dtstr =~ s#\s(\d{2}(\d{2})?)[\s\.,]# #o;
159              
160             }
161              
162             # Zone
163              
164             $dst = 1 if $dtstr =~ s#\bdst\b##o;
165              
166             if ($dtstr =~ s#\s"?([a-z]{3,4})(dst|\d+[a-z]*|_[a-z]+)?"?\s# #o) {
167             $dst = 1 if $2 and $2 eq 'dst';
168             $zone = tz_offset($1);
169             return unless defined $zone;
170             }
171             elsif ($dtstr =~ s#\s([a-z]{3,4})?([\-\+]?)-?(\d\d?):?(\d\d)?(00)?\s# #o) {
172             my $m = defined($4) ? "$2$4" : 0;
173             my $h = "$2$3";
174             $zone = defined($1) ? tz_offset($1) : 0;
175             return unless defined $zone;
176             $zone += 60 * ($m + (60 * $h));
177             }
178              
179             if ($dtstr =~ /\S/) {
180             # now for some dumb dates
181             if ($dtstr =~ s/^\s*(ut?|z)\s*$//) {
182             $zone = 0;
183             }
184             elsif ($dtstr =~ s#\s([a-z]{3,4})?([\-\+]?)-?(\d\d?)(\d\d)?(00)?\s# #o) {
185             my $m = defined($4) ? "$2$4" : 0;
186             my $h = "$2$3";
187             $zone = defined($1) ? tz_offset($1) : 0;
188             return unless defined $zone;
189             $zone += 60 * ($m + (60 * $h));
190             }
191              
192             return if $dtstr =~ /\S/o;
193             }
194              
195             if (defined $hh) {
196             if ($hh == 12) {
197             $hh = 0 if $merid == $AM;
198             }
199             elsif ($merid == $PM) {
200             $hh += 12;
201             }
202             }
203              
204             if (defined $year && $year > 1900) {
205             $century = int($year / 100);
206             $year -= 1900;
207             }
208              
209             $zone += 3600 if defined $zone && $dst;
210             $ss += "0.$frac" if $frac;
211              
212             return ($ss,$mm,$hh,$day,$month,$year,$zone,$century);
213             }
214             ESQ
215              
216             our ($day_ref, $mon_ref, $suf_ref, $obj);
217              
218             sub gen_parser
219             {
220 24     24 0 63 local($day_ref,$mon_ref,$suf_ref,$obj) = @_;
221              
222 24 100       87 if($obj)
223             {
224 19         34 my $obj_strptime = $strptime;
225 19         188 substr($obj_strptime,index($strptime,"sub")+6,0) = <<'ESQ';
226             shift; # package
227             ESQ
228 19 50 66 8   40526 my $sub = eval "$obj_strptime" or die $@;
  8 50 33     46  
  8 50 0     21  
  8 50 33     15  
  8 50 0     18  
  8 50 33     26  
  8 50 33     70  
  8 100       81  
  8 50       43  
  8 50       16  
  8 50       392  
  8 0       40  
  8 0       36  
  0 0       0  
  8 0       27  
  0 50       0  
  8 50       21  
  8 100       53  
  1 50       4  
  1 0       3  
  1 0       2  
  0 50       0  
  0 50       0  
  8 50       30  
  0 0       0  
  8 0       21  
  8 0       891  
  0 0       0  
  0 0       0  
  0 50       0  
  0 50       0  
  0 0       0  
  0 0       0  
  0 0       0  
  7 0       41  
  1 0       6  
  0 0       0  
  0 50       0  
  8 0       82  
  8 50       25  
  8 50       30  
  0 100       0  
  0 50       0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  0         0  
  0         0  
  8         21  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  8         18  
  1         3  
  0         0  
  0         0  
  8         51  
  8         21  
  8         16  
  8         26  
  8         17  
  8         40  
229 19         79 return $sub;
230             }
231              
232 5 50 100 479   11896 eval "$strptime" or die $@;
  480 50 100     4161  
  480 100 66     883  
  480 100 100     1103  
  480 100 33     1580  
  480 100 100     1700  
  480 100 66     6301  
  480 100       4931  
  480 50       998  
  480 100       3709  
  480 100       1967  
  477 100       2830  
  52 50       470  
  476 50       5431  
  4 50       30  
  476 100       1294  
  430 100       3933  
  419 100       2078  
  419 100       1213  
  419 100       1134  
  1 50       2  
  0 100       0  
  476 100       3948  
  3 50       39  
  476 50       1334  
  423 100       8872  
  8 50       276  
  7 50       52  
  6 50       33  
  6 100       23  
  6 100       13  
  6 0       34  
  6 0       54  
  226 0       1121  
  166 100       789  
  7 50       31  
  0 100       0  
  422 100       3629  
  477 100       1580  
  477 100       3764  
  291 100       908  
  290 100       962  
  290 100       1105  
  136 50       617  
  136 100       420  
  136         348  
  136         311  
  136         465  
  475         1583  
  16         89  
  14         39  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  15         44  
  474         1105  
  466         1564  
  24         70  
  10         21  
  474         2880  
  310         763  
  310         550  
  475         1735  
  475         1230  
  475         2869  
233              
234             }
235              
236             *strptime = gen_parser(\%day,\%month,\@suf);
237              
238             sub str2time
239             {
240 478     477 1 1590437 my @t = strptime(@_);
241              
242             return undef
243 478 100       1281 unless @t;
244              
245 473         1571 my($ss,$mm,$hh,$day,$month,$year,$zone, $century) = @t;
246 473         10623 my @lt = localtime(time);
247              
248 473   66     1467 $hh ||= 0;
249 473   66     1024 $mm ||= 0;
250 473   66     1011 $ss ||= 0;
251              
252 473         1055 my $frac = $ss - int($ss);
253 473         715 $ss = int $ss;
254              
255 473 100       969 $month = $lt[4]
256             unless(defined $month);
257              
258 473 100       1027 $day = $lt[3]
259             unless(defined $day);
260              
261 473 100       921 $year = ($month > $lt[4]) ? ($lt[5] - 1) : $lt[5]
    100          
262             unless(defined $year);
263              
264             # we were given a 4 digit year, so let's keep using those
265 473 100       1043 $year += 1900 if defined $century;
266              
267             return undef
268 472 100 33     4150 unless($month <= 11 && $day >= 1 && $day <= 31
      33        
      33        
      66        
      66        
269             && $hh <= 23 && $mm <= 59 && $ss <= 59);
270              
271 473         796 my $result;
272              
273 472 100       1028 if (defined $zone) {
274 440         817 $result = eval {
275 440     0   4437 local $SIG{__DIE__} = sub {}; # Ick!
276 440         2050 timegm($ss,$mm,$hh,$day,$month,$year);
277             };
278             return undef
279 440 50 33     22901 if !defined $result
      33        
280             or $result == -1
281             && join("",$ss,$mm,$hh,$day,$month,$year)
282             ne "595923311169";
283 440         804 $result -= $zone;
284             }
285             else {
286 33         64 $result = eval {
287 33     0   275 local $SIG{__DIE__} = sub {}; # Ick!
288 34         148 timelocal($ss,$mm,$hh,$day,$month,$year);
289             };
290             return undef
291 33 100 66     2532 if !defined $result
      33        
292             or $result == -1
293             && join("",$ss,$mm,$hh,$day,$month,$year)
294             ne join("",(localtime(-1))[0..5]);
295             }
296              
297 473         2093 return $result + $frac;
298             }
299              
300             1;
301              
302             __END__