File Coverage

lib/Pcore/Util/Date/Strptime.pm
Criterion Covered Total %
statement 3 53 5.6
branch 0 14 0.0
condition 0 11 0.0
subroutine 1 4 25.0
pod 0 2 0.0
total 4 84 4.7


line stmt bran cond sub pod time code
1             package Pcore::Util::Date::Strptime;
2              
3 1     1   1262 use Pcore -role, -const;
  1         2  
  1         6  
4              
5             # %a - the abbreviated weekday name ('Sun')
6             # %A - the full weekday name ('Sunday')
7             # %b - the abbreviated month name ('Jan')
8             # %B - the full month name ('January')
9             # %c - the preferred local date and time representation
10             # %d - day of the month (01..31)
11             # %e - day of the month without leading zeroes (1..31)
12             # %H - hour of the day, 24-hour clock (00..23)
13             # %I - hour of the day, 12-hour clock (01..12)
14             # %j - day of the year (001..366)
15             # %k - hour of the day, 24-hour clock w/o leading zeroes (0..23)
16             # %l - hour of the day, 12-hour clock w/o leading zeroes (1..12)
17             # %m - month of the year (01..12)
18             # %M - minute of the hour (00..59)
19             # %p - meridian indicator ('AM' or 'PM')
20             # %P - meridian indicator ('am' or 'pm')
21             # %S - second of the minute (00..60)
22             # %U - week number of the current year, starting with the first Sunday as the first day of the first week (00..53)
23             # %W - week number of the current year, starting with the first Monday as the first day of the first week (00..53)
24             # %w - day of the week (Sunday is 0, 0..6)
25             # %x - preferred representation for the date alone, no time
26             # %X - preferred representation for the time alone, no date
27             # %y - year without a century (00..99)
28             # %Y - year with century
29             # %Z - time zone name
30             # %z - +/- hhmm or hh:mm
31             # %% - literal '%' character
32              
33             const our $WEEKDAY => [qw[monday tuesday wednesday thursday friday saturday sunday]];
34              
35             const our $WEEKDAY_ABBR => [qw[mon tue wed thu fri sat sun]];
36              
37             const our $MONTH => [qw[january february march april may june july august september october november december]];
38              
39             const our $MONTH_ABBR => [qw[jan feb mar apr may jun jul aug sep oct nov dec]];
40              
41             const our $MONTH_NUM => { map { $_ => state $i++ + 1 } $MONTH->@* };
42              
43             const our $MONTH_ABBR_NUM => { map { $_ => state $i++ + 1 } $MONTH_ABBR->@* };
44              
45             const our $TIMEZONE => {
46             A => '+0100',
47             ACDT => '+1030',
48             ACST => '+0930',
49             ADT => undef,
50             AEDT => '+1100',
51             AES => '+1000',
52             AEST => '+1000',
53             AFT => '+0430',
54             AHDT => '-0900',
55             AHST => '-1000',
56             AKDT => '-0800',
57             AKST => '-0900',
58             AMST => '+0400',
59             AMT => '+0400',
60             ANAST => '+1300',
61             ANAT => '+1200',
62             ART => '-0300',
63             AST => undef,
64             AT => '-0100',
65             AWST => '+0800',
66             AZOST => '+0000',
67             AZOT => '-0100',
68             AZST => '+0500',
69             AZT => '+0400',
70             B => '+0200',
71             BADT => '+0400',
72             BAT => '+0600',
73             BDST => '+0200',
74             BDT => '+0600',
75             BET => '-1100',
76             BNT => '+0800',
77             BORT => '+0800',
78             BOT => '-0400',
79             BRA => '-0300',
80             BST => undef,
81             BT => undef,
82             BTT => '+0600',
83             C => '+0300',
84             CAST => '+0930',
85             CAT => undef,
86             CCT => undef,
87             CDT => undef,
88             CEST => '+0200',
89             CET => '+0100',
90             CETDST => '+0200',
91             CHADT => '+1345',
92             CHAST => '+1245',
93             CKT => '-1000',
94             CLST => '-0300',
95             CLT => '-0400',
96             COT => '-0500',
97             CST => undef,
98             CSUT => '+1030',
99             CUT => '+0000',
100             CVT => '-0100',
101             CXT => '+0700',
102             CHST => '+1000',
103             D => '+0400',
104             DAVT => '+0700',
105             DDUT => '+1000',
106             DNT => '+0100',
107             DST => '+0200',
108             E => '+0500',
109             EASST => '-0500',
110             EAST => undef,
111             EAT => '+0300',
112             ECT => undef,
113             EDT => undef,
114             EEST => '+0300',
115             EET => '+0200',
116             EETDST => '+0300',
117             EGST => '+0000',
118             EGT => '-0100',
119             EMT => '+0100',
120             EST => undef,
121             ESUT => '+1100',
122             F => '+0600',
123             FDT => undef,
124             FJST => '+1300',
125             FJT => '+1200',
126             FKST => '-0300',
127             FKT => '-0400',
128             FST => undef,
129             FWT => '+0100',
130             G => '+0700',
131             GALT => '-0600',
132             GAMT => '-0900',
133             GEST => '+0500',
134             GET => '+0400',
135             GFT => '-0300',
136             GILT => '+1200',
137             GMT => '+0000',
138             GST => undef,
139             GT => '+0000',
140             GYT => '-0400',
141             GZ => '+0000',
142             H => '+0800',
143             HAA => '-0300',
144             HAC => '-0500',
145             HAE => '-0400',
146             HAP => '-0700',
147             HAR => '-0600',
148             HAT => '-0230',
149             HAY => '-0800',
150             HDT => '-0930',
151             HFE => '+0200',
152             HFH => '+0100',
153             HG => '+0000',
154             HKT => '+0800',
155             HL => undef, # 'local',
156             HNA => '-0400',
157             HNC => '-0600',
158             HNE => '-0500',
159             HNP => '-0800',
160             HNR => '-0700',
161             HNT => '-0330',
162             HNY => '-0900',
163             HOE => '+0100',
164             HST => '-1000',
165             I => '+0900',
166             ICT => '+0700',
167             IDLE => '+1200',
168             IDLW => '-1200',
169             IDT => undef,
170             IOT => '+0500',
171             IRDT => '+0430',
172             IRKST => '+0900',
173             IRKT => '+0800',
174             IRST => '+0430',
175             IRT => '+0330',
176             IST => undef,
177             IT => '+0330',
178             ITA => '+0100',
179             JAVT => '+0700',
180             JAYT => '+0900',
181             JST => '+0900',
182             JT => '+0700',
183             K => '+1000',
184             KDT => '+1000',
185             KGST => '+0600',
186             KGT => '+0500',
187             KOST => '+1200',
188             KRAST => '+0800',
189             KRAT => '+0700',
190             KST => '+0900',
191             L => '+1100',
192             LHDT => '+1100',
193             LHST => '+1030',
194             LIGT => '+1000',
195             LINT => '+1400',
196             LKT => '+0600',
197             LST => undef, # 'local',
198             LT => undef, # 'local',
199             M => '+1200',
200             MAGST => '+1200',
201             MAGT => '+1100',
202             MAL => '+0800',
203             MART => '-0930',
204             MAT => '+0300',
205             MAWT => '+0600',
206             MDT => '-0600',
207             MED => '+0200',
208             MEDST => '+0200',
209             MEST => '+0200',
210             MESZ => '+0200',
211             MET => undef,
212             MEWT => '+0100',
213             MEX => '-0600',
214             MEZ => '+0100',
215             MHT => '+1200',
216             MMT => '+0630',
217             MPT => '+1000',
218             MSD => '+0400',
219             MSK => '+0300',
220             MSKS => '+0400',
221             MST => '-0700',
222             MT => '+0830',
223             MUT => '+0400',
224             MVT => '+0500',
225             MYT => '+0800',
226             N => '-0100',
227             NCT => '+1100',
228             NDT => '-0230',
229             NFT => undef,
230             NOR => '+0100',
231             NOVST => '+0700',
232             NOVT => '+0600',
233             NPT => '+0545',
234             NRT => '+1200',
235             NST => undef,
236             NSUT => '+0630',
237             NT => '-1100',
238             NUT => '-1100',
239             NZDT => '+1300',
240             NZST => '+1200',
241             NZT => '+1200',
242             O => '-0200',
243             OESZ => '+0300',
244             OEZ => '+0200',
245             OMSST => '+0700',
246             OMST => '+0600',
247             OZ => undef, # 'local',
248             P => '-0300',
249             PDT => '-0700',
250             PET => '-0500',
251             PETST => '+1300',
252             PETT => '+1200',
253             PGT => '+1000',
254             PHOT => '+1300',
255             PHT => '+0800',
256             PKT => '+0500',
257             PMDT => '-0200',
258             PMT => '-0300',
259             PNT => '-0830',
260             PONT => '+1100',
261             PST => undef,
262             PWT => '+0900',
263             PYST => '-0300',
264             PYT => '-0400',
265             Q => '-0400',
266             R => '-0500',
267             R1T => '+0200',
268             R2T => '+0300',
269             RET => '+0400',
270             ROK => '+0900',
271             S => '-0600',
272             SADT => '+1030',
273             SAST => undef,
274             SBT => '+1100',
275             SCT => '+0400',
276             SET => '+0100',
277             SGT => '+0800',
278             SRT => '-0300',
279             SST => undef,
280             SWT => '+0100',
281             T => '-0700',
282             TFT => '+0500',
283             THA => '+0700',
284             THAT => '-1000',
285             TJT => '+0500',
286             TKT => '-1000',
287             TMT => '+0500',
288             TOT => '+1300',
289             TRUT => '+1000',
290             TST => '+0300',
291             TUC => '+0000',
292             TVT => '+1200',
293             U => '-0800',
294             ULAST => '+0900',
295             ULAT => '+0800',
296             USZ1 => '+0200',
297             USZ1S => '+0300',
298             USZ3 => '+0400',
299             USZ3S => '+0500',
300             USZ4 => '+0500',
301             USZ4S => '+0600',
302             USZ5 => '+0600',
303             USZ5S => '+0700',
304             USZ6 => '+0700',
305             USZ6S => '+0800',
306             USZ7 => '+0800',
307             USZ7S => '+0900',
308             USZ8 => '+0900',
309             USZ8S => '+1000',
310             USZ9 => '+1000',
311             USZ9S => '+1100',
312             UTZ => '-0300',
313             UYT => '-0300',
314             UZ10 => '+1100',
315             UZ10S => '+1200',
316             UZ11 => '+1200',
317             UZ11S => '+1300',
318             UZ12 => '+1200',
319             UZ12S => '+1300',
320             UZT => '+0500',
321             V => '-0900',
322             VET => '-0400',
323             VLAST => '+1100',
324             VLAT => '+1000',
325             VTZ => '-0200',
326             VUT => '+1100',
327             W => '-1000',
328             WAKT => '+1200',
329             WAST => undef,
330             WAT => '+0100',
331             WEST => '+0100',
332             WESZ => '+0100',
333             WET => '+0000',
334             WETDST => '+0100',
335             WEZ => '+0000',
336             WFT => '+1200',
337             WGST => '-0200',
338             WGT => '-0300',
339             WIB => '+0700',
340             WIT => '+0900',
341             WITA => '+0800',
342             WST => undef,
343             WTZ => '-0100',
344             WUT => '+0100',
345             X => '-1100',
346             Y => '-1200',
347             YAKST => '+1000',
348             YAKT => '+0900',
349             YAPT => '+1000',
350             YDT => '-0800',
351             YEKST => '+0600',
352             YEKT => '+0500',
353             YST => '-0900',
354             Z => '+0000',
355             UTC => '+0000',
356             };
357              
358             const our $OFFSET => { map { $_ => abs $TIMEZONE->{$_} >= 100 ? ( int( abs $TIMEZONE->{$_} / 100 ) * 60 + abs( $TIMEZONE->{$_} ) % 100 ) / ( $TIMEZONE->{$_} < 0 ? -1 : 1 ) : $TIMEZONE->{$_} } grep { defined $TIMEZONE->{$_} } keys $TIMEZONE->%* };
359              
360             const our $STRPTIME_TOKEN => {
361             a => [ # the abbreviated weekday name ('Sun')
362             '(?i:' . join( q[|], $WEEKDAY_ABBR->@* ) . ')',
363             ],
364             A => [ # the full weekday name ('Sunday')
365             '(?i:' . join( q[|], sort $WEEKDAY->@* ) . ')',
366             ],
367             b => [ # the abbreviated month name ('Jan')
368             '((?i:' . join( q[|], sort $MONTH_ABBR->@* ) . '))',
369             '\$args{month} = \$MONTH_ABBR_NUM->{lc $1}',
370             ],
371             B => [ # the full month name ('January')
372             '((?i:' . join( q[|], sort $MONTH->@* ) . '))',
373             '\$args{month} = \$1',
374             ],
375             d => [ # day of the month (01..31)
376             '(\d\d)',
377             '\$args{day} = \$1',
378             ],
379             H => [ # hour of the day, 24-hour clock (00..23)
380             '(\d\d)',
381             '\$args{hour} = \$1',
382             ],
383             m => [ # month of the year (01..12)
384             '(\d\d)',
385             '\$args{month} = \$1',
386             ],
387             M => [ # minute of the hour (00..59)
388             '(\d\d)',
389             '\$args{minute} = \$1',
390             ],
391             S => [ # second of the minute (00..60)
392             '(\d\d)',
393             '\$args{second} = \$1',
394             ],
395             y => [ # year without a century (00..99)
396             '(\d\d)',
397             '\$args{year} = \( $1 + ( $1 >= 69 ? 1900 : 2000 ) )',
398             ],
399             Y => [ # year with century
400             '(\d\d\d\d)',
401             '\$args{year} = \$1',
402             ],
403             Z => [ # time zone name
404             '((?i:' . join( q[|], sort { length $b <=> length $a } grep { defined $OFFSET->{$_} } keys $OFFSET->%* ) . '))',
405             '\$args{offset} = \$OFFSET->{uc $1}',
406             ],
407             z => [ # +/-hhmm, +/-hh:mm
408             '([+-])(\d\d):?(\d\d)',
409             '\$args{offset} = \( ($2 * 60 + $3) / ($1 eq q[-] ? -1 : 1) )',
410             ],
411             };
412              
413             our $CACHE = {};
414              
415 0     0 0   sub from_strptime ( $self, $str, $pattern, $use_cache = 1 ) {
  0            
  0            
  0            
  0            
  0            
416 0 0 0       return $CACHE->{$pattern}->($str) if $use_cache and $CACHE->{$pattern};
417              
418 0           return $self->_strptime_compile_pattern( $pattern, $use_cache )->($str);
419             }
420              
421 0     0 0   sub expand_strptime_re ( $self, $re ) {
  0            
  0            
  0            
422 0           state $split_re = qr/%([@{[ join q[|], keys $STRPTIME_TOKEN->%* ]}])/sm;
  0            
423              
424 0           my $expanded_re;
425              
426 0           for my $token ( split $split_re, $re ) {
427 0 0         if ( !exists $STRPTIME_TOKEN->{$token} ) {
428 0           $expanded_re .= $token;
429             }
430             else {
431 0           state $cache = {};
432              
433 0   0       $cache->{$token} //= $STRPTIME_TOKEN->{$token}->[0] =~ s/[(](?![?])/(?:/smrg;
434              
435 0           $expanded_re .= $cache->{$token};
436             }
437             }
438              
439 0           return $expanded_re;
440             }
441              
442 0     0     sub _strptime_compile_pattern ( $self, $pattern, $use_cache = 1 ) {
  0            
  0            
  0            
  0            
443 0           state $split_re = qr/%([@{[ join q[|], keys $STRPTIME_TOKEN->%* ]}])/sm;
  0            
444              
445 0 0 0       return $CACHE->{$pattern} if $use_cache and $CACHE->{$pattern};
446              
447 0           my $re;
448              
449 0           my $match_id = 0;
450              
451 0           my $sub;
452              
453 0           for my $token ( split $split_re, $pattern ) {
454 0 0         if ( !exists $STRPTIME_TOKEN->{$token} ) {
455 0           $re .= $token;
456             }
457             else {
458 0           $re .= $STRPTIME_TOKEN->{$token}->[0];
459              
460 0 0         if ( $STRPTIME_TOKEN->{$token}->[1] ) {
461 0           my $code = $STRPTIME_TOKEN->{$token}->[1];
462              
463 0           my $id = 1;
464              
465 0 0         NEXT: if ( $code =~ /\$$id/sm ) {
466 0           $code =~ s/\$$id/\$match[$match_id]/smg;
467              
468 0           $id++;
469              
470 0           $match_id++;
471              
472 0           goto NEXT;
473             }
474              
475 0           $sub .= " $code;$LF";
476             }
477             }
478             }
479              
480 0           $sub = <<"PERL";
481             sub ( \$str ) {
482             if ( my \@match = \$str =~ m[$re]sm ) {
483             my \%args;
484              
485             $sub
486             return \$self->new( \%args );
487             }
488             else {
489             die q[Strftime pattern does not match];
490             }
491             };
492             PERL
493              
494 0   0       $sub = eval $sub || die; ## no critic qw[BuiltinFunctions::ProhibitStringyEval]
495              
496 0 0         $CACHE->{$pattern} = $sub if $use_cache;
497              
498 0           return $sub;
499             }
500              
501             1;
502             ## -----SOURCE FILTER LOG BEGIN-----
503             ##
504             ## PerlCritic profile "pcore-script" policy violations:
505             ## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
506             ## | Sev. | Lines | Policy |
507             ## |======+======================+================================================================================================================|
508             ## | 1 | 369, 373, 377, 381, | ValuesAndExpressions::RequireInterpolationOfMetachars - String *may* require interpolation |
509             ## | | 385, 389, 393, 397, | |
510             ## | | 401, 405, 409 | |
511             ## |------+----------------------+----------------------------------------------------------------------------------------------------------------|
512             ## | 1 | 404 | BuiltinFunctions::ProhibitReverseSortBlock - Forbid $b before $a in sort blocks |
513             ## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
514             ##
515             ## -----SOURCE FILTER LOG END-----
516             __END__
517             =pod
518              
519             =encoding utf8
520              
521             =head1 NAME
522              
523             Pcore::Util::Date::Strptime
524              
525             =head1 SYNOPSIS
526              
527             =head1 DESCRIPTION
528              
529             =head1 ATTRIBUTES
530              
531             =head1 METHODS
532              
533             =head1 SEE ALSO
534              
535             =cut