File Coverage

blib/lib/DateTime/Format/Strptime.pm
Criterion Covered Total %
statement 306 318 96.2
branch 154 174 88.5
condition 50 57 87.7
subroutine 35 38 92.1
pod 9 11 81.8
total 554 598 92.6


line stmt bran cond sub pod time code
1             package DateTime::Format::Strptime;
2              
3 12     12   1282622 use strict;
  12         141  
  12         356  
4 12     12   75 use warnings;
  12         26  
  12         652  
5              
6             our $VERSION = '1.77';
7              
8 12     12   87 use Carp qw( carp croak );
  12         24  
  12         758  
9 12     12   11232 use DateTime 1.00;
  12         6114609  
  12         685  
10 12     12   126 use DateTime::Locale 1.23;
  12         200  
  12         327  
11 12     12   6599 use DateTime::Format::Strptime::Types;
  12         43  
  12         122  
12 12     12   217065 use DateTime::TimeZone 2.09;
  12         408  
  12         322  
13 12     12   77 use Exporter ();
  12         31  
  12         320  
14 12     12   190 use Params::ValidationCompiler qw( validation_for );
  12         34  
  12         757  
15 12     12   115 use Try::Tiny;
  12         28  
  12         1254  
16              
17             our @EXPORT_OK = qw( strftime strptime );
18              
19             ## no critic (ValuesAndExpressions::ProhibitConstantPragma)
20 12     12   99 use constant PERL_58 => $] < 5.010;
  12         27  
  12         65838  
21              
22             # We previously used Package::DeprecationManager which allowed passing of
23             # "-api_version => X" on import. We don't want any such imports to blow up but
24             # we no longer have anything to deprecate.
25             sub import {
26 14     14   2646 my $class = shift;
27 14         31 my @args;
28             ## no critic (ControlStructures::ProhibitCStyleForLoops)
29 14         79 for ( my $i = 0; $i < @_; $i++ ) {
30 3 100       10 if ( $_[$i] eq '-api_version' ) {
31 1         3 $i++;
32             }
33             else {
34 2         6 push @args, $_[$i];
35             }
36             }
37 14         43 @_ = ( $class, @args );
38 14         14095 goto &Exporter::import;
39             }
40              
41             {
42             my $en_locale = DateTime::Locale->load('en');
43              
44             my $validator = validation_for(
45             params => {
46             pattern => { type => t('NonEmptyStr') },
47             time_zone => {
48             type => t('TimeZone'),
49             optional => 1,
50             },
51             zone_map => {
52             type => t('HashRef'),
53             default => sub { {} },
54             },
55             locale => {
56             type => t('Locale'),
57             default => sub {$en_locale},
58             },
59             on_error => {
60             type => t('OnError'),
61             default => 'undef',
62             },
63             strict => {
64             type => t('Bool'),
65             default => 0,
66             },
67             debug => {
68             type => t('Bool'),
69             default => $ENV{DATETIME_FORMAT_STRPTIME_DEBUG},
70             },
71             },
72             );
73              
74             sub new {
75 294     294 1 1483696 my $class = shift;
76 294         7372 my %args = $validator->(@_);
77              
78             my $self = bless {
79             %args,
80 294         8330 zone_map => $class->_build_zone_map( $args{zone_map} ),
81             }, $class;
82              
83             # Forces a check that the pattern is valid
84 294         1277 $self->_parser;
85              
86 293 50       9636 if ( $self->{debug} ) {
87 0 0       0 binmode STDERR, ':encoding(UTF-8)' or die $!;
88             }
89              
90 293         3538 return $self;
91             }
92             }
93              
94             {
95             my %zone_map = (
96             'A' => '+0100', 'ACDT' => '+1030', 'ACST' => '+0930',
97             'ADT' => undef, 'AEDT' => '+1100', 'AES' => '+1000',
98             'AEST' => '+1000', 'AFT' => '+0430', 'AHDT' => '-0900',
99             'AHST' => '-1000', 'AKDT' => '-0800', 'AKST' => '-0900',
100             'AMST' => '+0400', 'AMT' => '+0400', 'ANAST' => '+1300',
101             'ANAT' => '+1200', 'ART' => '-0300', 'AST' => undef,
102             'AT' => '-0100', 'AWST' => '+0800', 'AZOST' => '+0000',
103             'AZOT' => '-0100', 'AZST' => '+0500', 'AZT' => '+0400',
104             'B' => '+0200', 'BADT' => '+0400', 'BAT' => '+0600',
105             'BDST' => '+0200', 'BDT' => '+0600', 'BET' => '-1100',
106             'BNT' => '+0800', 'BORT' => '+0800', 'BOT' => '-0400',
107             'BRA' => '-0300', 'BST' => undef, 'BT' => undef,
108             'BTT' => '+0600', 'C' => '+0300', 'CAST' => '+0930',
109             'CAT' => undef, 'CCT' => undef, 'CDT' => undef,
110             'CEST' => '+0200', 'CET' => '+0100', 'CETDST' => '+0200',
111             'CHADT' => '+1345', 'CHAST' => '+1245', 'CKT' => '-1000',
112             'CLST' => '-0300', 'CLT' => '-0400', 'COT' => '-0500',
113             'CST' => undef, 'CSuT' => '+1030', 'CUT' => '+0000',
114             'CVT' => '-0100', 'CXT' => '+0700', 'ChST' => '+1000',
115             'D' => '+0400', 'DAVT' => '+0700', 'DDUT' => '+1000',
116             'DNT' => '+0100', 'DST' => '+0200', 'E' => '+0500',
117             'EASST' => '-0500', 'EAST' => undef, 'EAT' => '+0300',
118             'ECT' => undef, 'EDT' => undef, 'EEST' => '+0300',
119             'EET' => '+0200', 'EETDST' => '+0300', 'EGST' => '+0000',
120             'EGT' => '-0100', 'EMT' => '+0100', 'EST' => undef,
121             'ESuT' => '+1100', 'F' => '+0600', 'FDT' => undef,
122             'FJST' => '+1300', 'FJT' => '+1200', 'FKST' => '-0300',
123             'FKT' => '-0400', 'FST' => undef, 'FWT' => '+0100',
124             'G' => '+0700', 'GALT' => '-0600', 'GAMT' => '-0900',
125             'GEST' => '+0500', 'GET' => '+0400', 'GFT' => '-0300',
126             'GILT' => '+1200', 'GMT' => '+0000', 'GST' => undef,
127             'GT' => '+0000', 'GYT' => '-0400', 'GZ' => '+0000',
128             'H' => '+0800', 'HAA' => '-0300', 'HAC' => '-0500',
129             'HAE' => '-0400', 'HAP' => '-0700', 'HAR' => '-0600',
130             'HAT' => '-0230', 'HAY' => '-0800', 'HDT' => '-0930',
131             'HFE' => '+0200', 'HFH' => '+0100', 'HG' => '+0000',
132             'HKT' => '+0800', 'HL' => 'local', 'HNA' => '-0400',
133             'HNC' => '-0600', 'HNE' => '-0500', 'HNP' => '-0800',
134             'HNR' => '-0700', 'HNT' => '-0330', 'HNY' => '-0900',
135             'HOE' => '+0100', 'HST' => '-1000', 'I' => '+0900',
136             'ICT' => '+0700', 'IDLE' => '+1200', 'IDLW' => '-1200',
137             'IDT' => undef, 'IOT' => '+0500', 'IRDT' => '+0430',
138             'IRKST' => '+0900', 'IRKT' => '+0800', 'IRST' => '+0430',
139             'IRT' => '+0330', 'IST' => undef, 'IT' => '+0330',
140             'ITA' => '+0100', 'JAVT' => '+0700', 'JAYT' => '+0900',
141             'JST' => '+0900', 'JT' => '+0700', 'K' => '+1000',
142             'KDT' => '+1000', 'KGST' => '+0600', 'KGT' => '+0500',
143             'KOST' => '+1200', 'KRAST' => '+0800', 'KRAT' => '+0700',
144             'KST' => '+0900', 'L' => '+1100', 'LHDT' => '+1100',
145             'LHST' => '+1030', 'LIGT' => '+1000', 'LINT' => '+1400',
146             'LKT' => '+0600', 'LST' => 'local', 'LT' => 'local',
147             'M' => '+1200', 'MAGST' => '+1200', 'MAGT' => '+1100',
148             'MAL' => '+0800', 'MART' => '-0930', 'MAT' => '+0300',
149             'MAWT' => '+0600', 'MDT' => '-0600', 'MED' => '+0200',
150             'MEDST' => '+0200', 'MEST' => '+0200', 'MESZ' => '+0200',
151             'MET' => undef, 'MEWT' => '+0100', 'MEX' => '-0600',
152             'MEZ' => '+0100', 'MHT' => '+1200', 'MMT' => '+0630',
153             'MPT' => '+1000', 'MSD' => '+0400', 'MSK' => '+0300',
154             'MSKS' => '+0400', 'MST' => '-0700', 'MT' => '+0830',
155             'MUT' => '+0400', 'MVT' => '+0500', 'MYT' => '+0800',
156             'N' => '-0100', 'NCT' => '+1100', 'NDT' => '-0230',
157             'NFT' => undef, 'NOR' => '+0100', 'NOVST' => '+0700',
158             'NOVT' => '+0600', 'NPT' => '+0545', 'NRT' => '+1200',
159             'NST' => undef, 'NSUT' => '+0630', 'NT' => '-1100',
160             'NUT' => '-1100', 'NZDT' => '+1300', 'NZST' => '+1200',
161             'NZT' => '+1200', 'O' => '-0200', 'OESZ' => '+0300',
162             'OEZ' => '+0200', 'OMSST' => '+0700', 'OMST' => '+0600',
163             'OZ' => 'local', 'P' => '-0300', 'PDT' => '-0700',
164             'PET' => '-0500', 'PETST' => '+1300', 'PETT' => '+1200',
165             'PGT' => '+1000', 'PHOT' => '+1300', 'PHT' => '+0800',
166             'PKT' => '+0500', 'PMDT' => '-0200', 'PMT' => '-0300',
167             'PNT' => '-0830', 'PONT' => '+1100', 'PST' => undef,
168             'PWT' => '+0900', 'PYST' => '-0300', 'PYT' => '-0400',
169             'Q' => '-0400', 'R' => '-0500', 'R1T' => '+0200',
170             'R2T' => '+0300', 'RET' => '+0400', 'ROK' => '+0900',
171             'S' => '-0600', 'SADT' => '+1030', 'SAST' => undef,
172             'SBT' => '+1100', 'SCT' => '+0400', 'SET' => '+0100',
173             'SGT' => '+0800', 'SRT' => '-0300', 'SST' => undef,
174             'SWT' => '+0100', 'T' => '-0700', 'TFT' => '+0500',
175             'THA' => '+0700', 'THAT' => '-1000', 'TJT' => '+0500',
176             'TKT' => '-1000', 'TMT' => '+0500', 'TOT' => '+1300',
177             'TRUT' => '+1000', 'TST' => '+0300', 'TUC ' => '+0000',
178             'TVT' => '+1200', 'U' => '-0800', 'ULAST' => '+0900',
179             'ULAT' => '+0800', 'USZ1' => '+0200', 'USZ1S' => '+0300',
180             'USZ3' => '+0400', 'USZ3S' => '+0500', 'USZ4' => '+0500',
181             'USZ4S' => '+0600', 'USZ5' => '+0600', 'USZ5S' => '+0700',
182             'USZ6' => '+0700', 'USZ6S' => '+0800', 'USZ7' => '+0800',
183             'USZ7S' => '+0900', 'USZ8' => '+0900', 'USZ8S' => '+1000',
184             'USZ9' => '+1000', 'USZ9S' => '+1100', 'UTZ' => '-0300',
185             'UYT' => '-0300', 'UZ10' => '+1100', 'UZ10S' => '+1200',
186             'UZ11' => '+1200', 'UZ11S' => '+1300', 'UZ12' => '+1200',
187             'UZ12S' => '+1300', 'UZT' => '+0500', 'V' => '-0900',
188             'VET' => '-0400', 'VLAST' => '+1100', 'VLAT' => '+1000',
189             'VTZ' => '-0200', 'VUT' => '+1100', 'W' => '-1000',
190             'WAKT' => '+1200', 'WAST' => undef, 'WAT' => '+0100',
191             'WEST' => '+0100', 'WESZ' => '+0100', 'WET' => '+0000',
192             'WETDST' => '+0100', 'WEZ' => '+0000', 'WFT' => '+1200',
193             'WGST' => '-0200', 'WGT' => '-0300', 'WIB' => '+0700',
194             'WIT' => '+0900', 'WITA' => '+0800', 'WST' => undef,
195             'WTZ' => '-0100', 'WUT' => '+0100', 'X' => '-1100',
196             'Y' => '-1200', 'YAKST' => '+1000', 'YAKT' => '+0900',
197             'YAPT' => '+1000', 'YDT' => '-0800', 'YEKST' => '+0600',
198             'YEKT' => '+0500', 'YST' => '-0900', 'Z' => '+0000',
199             'UTC' => '+0000',
200             );
201              
202             for my $i ( map { sprintf( '%02d', $_ ) } 1 .. 12 ) {
203             $zone_map{ '-' . $i } = '-' . $i . '00';
204             $zone_map{ '+' . $i } = '+' . $i . '00';
205             }
206              
207             sub _build_zone_map {
208             return {
209             %zone_map,
210 294     294   10728 %{ $_[1] },
  294         30582  
211             };
212             }
213             }
214              
215             sub parse_datetime {
216 289     289 1 135872 my $self = shift;
217 289         566 my $string = shift;
218              
219 289         655 my $parser = $self->_parser;
220 289 50       755 if ( $self->{debug} ) {
221 0         0 warn "Regex for $self->{pattern}: $parser->{regex}\n";
222 0         0 warn "Fields: @{$parser->{fields}}\n";
  0         0  
223             }
224              
225 289         3525 my @matches = ( $string =~ $parser->{regex} );
226 289 100       870 unless (@matches) {
227 6         11 my $msg = 'Your datetime does not match your pattern';
228 6 50       16 if ( $self->{debug} ) {
229 0         0 $msg .= qq{ - string = "$string" - regex = $parser->{regex}};
230             }
231 6         13 $msg .= q{.};
232 6         19 $self->_our_croak($msg);
233 2         6 return;
234             }
235              
236 283         472 my %args;
237 283         453 my $i = 0;
238 283         421 for my $f ( @{ $parser->{fields} } ) {
  283         737  
239 1111 50       2218 unless ( defined $matches[$i] ) {
240 0         0 die
241             "Something horrible happened - the string matched $parser->{regex}"
242 0         0 . " but did not return the expected fields: [@{$parser->{fields}}]";
243             }
244 1111         2610 $args{$f} = $matches[ $i++ ];
245             }
246              
247             # We need to copy the %args here because _munge_args will delete keys in
248             # order to turn this into something that can be passed to a DateTime
249             # constructor.
250 283         1486 my ( $constructor, $args, $post_construct )
251             = $self->_munge_args( {%args} );
252 272 100 66     1225 return unless $constructor && $args;
253              
254 267     267   1518 my $dt = try { DateTime->$constructor($args) };
  267         7406  
255 267 100       126885 $self->_our_croak('Parsed values did not produce a valid date')
256             unless $dt;
257 261 100       1741 if ($post_construct) {
258 2         7 $post_construct->($dt);
259             }
260 261 100 100     2131 return unless $dt && $self->_check_dt( $dt, \%args );
261              
262             $dt->set_time_zone( $self->{time_zone} )
263 192 100       477 if $self->{time_zone};
264              
265 192         1469 return $dt;
266             }
267              
268             sub _parser {
269 583     583   1000 my $self = shift;
270              
271 583   66     2265 return $self->{parser} ||= $self->_build_parser;
272             }
273              
274             sub _build_parser {
275 294     294   487 my $self = shift;
276              
277             my (
278 294         698 $replacement_tokens_re,
279             $replacements,
280             $pattern_tokens_re,
281             $patterns,
282             ) = $self->_parser_pieces;
283              
284 294         1572 my $pattern = $self->{pattern};
285              
286             # When the first replacement is a glibc pattern, the first round of
287             # replacements may simply replace one replacement token (like %X) with
288             # another replacement token (like %I).
289 294         3596 $pattern =~ s/%($replacement_tokens_re)/$replacements->{$1}/g for 1 .. 2;
290              
291 294 50 33     1049 if ( $self->{debug} && $pattern ne $self->{pattern} ) {
292 0         0 warn "Pattern after replacement substitution: $pattern\n";
293             }
294              
295 294         514 my $regex = q{};
296 294         468 my @fields;
297              
298 294         2809 while (
299             $pattern =~ /
300             \G
301             %($pattern_tokens_re)
302             |
303             %([1-9]?)(N)
304             |
305             (%[0-9]*[a-zA-Z])
306             |
307             ([^%]+)
308             /xg
309             ) {
310             # Using \G in the regex match fails for some reason on Perl 5.8, so we
311             # do this hack instead.
312 1982         3438 substr( $pattern, 0, pos $pattern, q{} )
313             if PERL_58;
314 1982 100       5450 if ($1) {
    100          
    100          
315 1141 50       2874 my $p = $patterns->{$1}
316             or croak
317             "Unidentified token in pattern: $1 in $self->{pattern}";
318 1141 100       2266 if ( $p->{field} ) {
319 1130         25692 $regex .= qr/($p->{regex})/;
320 1130         8734 push @fields, $p->{field};
321             }
322             else {
323 11         83 $regex .= qr/$p->{regex}/;
324             }
325             }
326             elsif ($3) {
327 6 100       56 $regex .= $2 ? qr/([0-9]{$2})/ : qr/([0-9]+)/;
328 6         39 push @fields, 'nanosecond';
329             }
330             elsif ($4) {
331 1         268 croak qq{Pattern contained an unrecognized strptime token, "$4"};
332             }
333             else {
334 834         8127 $regex .= qr/\Q$5/;
335             }
336             }
337              
338             return {
339             regex =>
340 293 100       9494 ( $self->{strict} ? qr/(?:\A|\b)$regex(?:\b|\Z)/ : qr/$regex/ ),
341             fields => \@fields,
342             };
343             }
344              
345             {
346             my $digit = qr/(?:[0-9])/;
347             my $one_or_two_digits = qr/[0-9 ]?$digit/;
348              
349             # These patterns are all locale-independent. There are a few that depend
350             # on the locale, and must be re-calculated for each new parser object.
351             my %universal_patterns = (
352             '%' => {
353             regex => qr/%/,
354             },
355             C => {
356             regex => $one_or_two_digits,
357             field => 'century',
358             },
359             d => {
360             regex => $one_or_two_digits,
361             field => 'day',
362             },
363             g => {
364             regex => $one_or_two_digits,
365             field => 'iso_week_year_100',
366             },
367             G => {
368             regex => qr/$digit{4}/,
369             field => 'iso_week_year',
370             },
371             H => {
372             regex => $one_or_two_digits,
373             field => 'hour',
374             },
375             I => {
376             regex => $one_or_two_digits,
377             field => 'hour_12',
378             },
379             j => {
380             regex => qr/$digit{1,3}/,
381             field => 'day_of_year',
382             },
383             m => {
384             regex => $one_or_two_digits,
385             field => 'month',
386             },
387             M => {
388             regex => $one_or_two_digits,
389             field => 'minute',
390             },
391             n => {
392             regex => qr/\s+/,
393             },
394             O => {
395             regex => qr{[a-zA-Z_]+(?:/[a-zA-Z_]+(?:/[a-zA-Z_]+)?)?},
396             field => 'time_zone_name',
397             },
398             s => {
399             regex => qr/$digit+/,
400             field => 'epoch',
401             },
402             S => {
403             regex => $one_or_two_digits,
404             field => 'second',
405             },
406             U => {
407             regex => $one_or_two_digits,
408             field => 'week_sun_0',
409             },
410             u => {
411             regex => $one_or_two_digits,
412             field => 'day_of_week',
413             },
414             w => {
415             regex => $one_or_two_digits,
416             field => 'day_of_week_sun_0',
417             },
418             W => {
419             regex => $one_or_two_digits,
420             field => 'week_mon_1',
421             },
422             y => {
423             regex => $one_or_two_digits,
424             field => 'year_100',
425             },
426             Y => {
427             regex => qr/$digit{4}/,
428             field => 'year',
429             },
430             z => {
431             regex => qr/(?:Z|[+-]$digit{2}(?:[:]?$digit{2})?)/,
432             field => 'time_zone_offset',
433             },
434             Z => {
435             regex => qr/[a-zA-Z]{1,6}|[\-\+]$digit{2}/,
436             field => 'time_zone_abbreviation',
437             },
438             );
439              
440             $universal_patterns{e} = $universal_patterns{d};
441             $universal_patterns{k} = $universal_patterns{H};
442             $universal_patterns{l} = $universal_patterns{I};
443             $universal_patterns{t} = $universal_patterns{n};
444              
445             my %universal_replacements = (
446             D => '%m/%d/%y',
447             F => '%Y-%m-%d',
448             r => '%I:%M:%S %p',
449             R => '%H:%M',
450             T => '%H:%M:%S',
451             );
452              
453             sub _parser_pieces {
454 294     294   457 my $self = shift;
455              
456 294         1337 my %replacements = %universal_replacements;
457 294         1273 $replacements{c} = $self->{locale}->glibc_datetime_format;
458 294         1770 $replacements{x} = $self->{locale}->glibc_date_format;
459 294         1360 $replacements{X} = $self->{locale}->glibc_time_format;
460              
461 294         3783 my %patterns = %universal_patterns;
462             $patterns{a} = $patterns{A} = {
463 294         781 regex => do {
464 4116         7845 my $days = join '|', map {quotemeta}
465 11029 50       19932 sort { ( length $b <=> length $a ) or ( $a cmp $b ) }
466 294         512 keys %{ $self->_locale_days };
  294         635  
467 294         3332 qr/$days/i;
468             },
469             field => 'day_name',
470             };
471              
472             $patterns{b} = $patterns{B} = $patterns{h} = {
473 294         33879 regex => do {
474 6698         11599 my $months = join '|', map {quotemeta}
475 22333 50       38871 sort { ( length $b <=> length $a ) or ( $a cmp $b ) }
476 294         529 keys %{ $self->_locale_months };
  294         695  
477 294         4027 qr/$months/i;
478             },
479             field => 'month_name',
480             };
481              
482             $patterns{p} = $patterns{P} = {
483 294         9066 regex => do {
484             my $am_pm = join '|',
485 588         1415 map {quotemeta}
486 294 0       1864 sort { ( length $b <=> length $a ) or ( $a cmp $b ) }
487 294         455 @{ $self->{locale}->am_pm_abbreviated };
  294         926  
488 294         2679 qr/$am_pm/i;
489             },
490             field => 'am_pm',
491             };
492              
493             return (
494 294         1404 $self->_token_re_for( keys %replacements ),
495             \%replacements,
496             $self->_token_re_for( keys %patterns ),
497             \%patterns,
498             );
499             }
500             }
501              
502             sub _locale_days {
503 338     338   567 my $self = shift;
504              
505 338 100       952 return $self->{locale_days} if $self->{locale_days};
506              
507 294         816 my $wide = $self->{locale}->day_format_wide;
508 294         1356 my $abbr = $self->{locale}->day_format_abbreviated;
509              
510 294         975 my %locale_days;
511 294         784 for my $i ( 0 .. 6 ) {
512 2058         4512 $locale_days{ lc $wide->[$i] } = $i;
513 2058         4348 $locale_days{ lc $abbr->[$i] } = $i;
514             }
515              
516 294   50     3101 return $self->{locale_days} ||= \%locale_days;
517             }
518              
519             sub _locale_months {
520 369     369   605 my $self = shift;
521              
522 369 100       1126 return $self->{locale_months} if $self->{locale_months};
523              
524 294         914 my $wide = $self->{locale}->month_format_wide;
525 294         1335 my $abbr = $self->{locale}->month_format_abbreviated;
526              
527 294         940 my %locale_months;
528 294         625 for my $i ( 0 .. 11 ) {
529 3528         6784 $locale_months{ lc $wide->[$i] } = $i + 1;
530 3528         6990 $locale_months{ lc $abbr->[$i] } = $i + 1;
531             }
532              
533 294   50     2555 return $self->{locale_months} ||= \%locale_months;
534             }
535              
536             sub _token_re_for {
537 588     588   1290 shift;
538             my $t = join '|',
539 588 0       1473 sort { ( length $b <=> length $a ) or ( $a cmp $b ) } @_;
  42123         70307  
540              
541 588         31517 return qr/$t/;
542             }
543              
544             {
545             # These are fields we parse that cannot be passed to a DateTime
546             # constructor
547             my @non_dt_keys = qw(
548             am_pm
549             century
550             day_name
551             day_of_week
552             day_of_week_sun_0
553             hour_12
554             iso_week_year
555             iso_week_year_100
556             month_name
557             time_zone_abbreviation
558             time_zone_name
559             time_zone_offset
560             week_mon_1
561             week_sun_0
562             year_100
563             );
564              
565             ## no critic (Subroutines::ProhibitExcessComplexity)
566             sub _munge_args {
567 283     283   465 my $self = shift;
568 283         435 my $args = shift;
569              
570 283 100       722 if ( defined $args->{month_name} ) {
571             my $num = $self->_locale_months->{ lc $args->{month_name} }
572 75 50       174 or die "We somehow parsed a month name ($args->{month_name})"
573             . ' that does not correspond to any month in this locale!';
574              
575 75         190 $args->{month} = $num;
576             }
577              
578 283 100 100     1163 if ( defined $args->{am_pm} && defined $args->{hour_12} ) {
    100          
579 12         34 my ( $am, $pm ) = @{ $self->{locale}->am_pm_abbreviated };
  12         46  
580 12         73 $args->{hour} = $args->{hour_12};
581              
582 12 100       42 if ( lc $args->{am_pm} eq lc $am ) {
583 4 50       19 $args->{hour} = 0 if $args->{hour} == 12;
584             }
585             else {
586 8 50       40 $args->{hour} += 12 unless $args->{hour} == 12;
587             }
588             }
589             elsif ( defined $args->{hour_12} ) {
590 3         15 $self->_our_croak(
591             qq{Parsed a 12-hour based hour, "$args->{hour_12}",}
592             . ' but the pattern does not include an AM/PM specifier'
593             );
594 1         3 return;
595             }
596              
597 280 100       615 if ( defined $args->{year_100} ) {
598 10 100       46 if ( defined $args->{century} ) {
599             $args->{year}
600 1         7 = $args->{year_100} + ( $args->{century} * 100 );
601             }
602             else {
603             $args->{year} = $args->{year_100} + (
604 9 100       43 $args->{year_100} >= 69
605             ? 1900
606             : 2000
607             );
608             }
609             }
610              
611 280 100       656 if ( $args->{time_zone_offset} ) {
612 14         44 my $offset = $args->{time_zone_offset};
613              
614 14 100       68 if ( $offset eq 'Z' ) {
    100          
615 1         3 $offset = '+0000';
616             }
617             elsif ( $offset =~ /^[+-][0-9]{2}$/ ) {
618 2         8 $offset .= '00';
619             }
620              
621 14     14   76 my $tz = try { DateTime::TimeZone->new( name => $offset ) };
  14         422  
622 14 100       3659 unless ($tz) {
623 3         15 $self->_our_croak(
624             qq{The time zone name offset that was parsed does not appear to be valid, "$args->{time_zone_offset}"}
625             );
626 1         3 return;
627             }
628              
629 11         32 $args->{time_zone} = $tz;
630             }
631              
632 277 100       587 if ( defined $args->{time_zone_abbreviation} ) {
633 20         45 my $abbr = $args->{time_zone_abbreviation};
634 20 100       62 unless ( exists $self->{zone_map}{$abbr} ) {
635 3         14 $self->_our_croak(
636             qq{Parsed an unrecognized time zone abbreviation, "$args->{time_zone_abbreviation}"}
637             );
638 1         3 return;
639             }
640 17 100       48 if ( !defined $self->{zone_map}{$abbr} ) {
641 4         21 $self->_our_croak(
642             qq{The time zone abbreviation that was parsed is ambiguous, "$args->{time_zone_abbreviation}"}
643             );
644 1         3 return;
645             }
646             $args->{time_zone}
647 13         65 = DateTime::TimeZone->new( name => $self->{zone_map}{$abbr} );
648             }
649             else {
650 257   100     1068 $args->{time_zone} ||= 'floating';
651             }
652              
653 270 100       3847 if ( $args->{time_zone_name} ) {
654 8         18 my $name = $args->{time_zone_name};
655 8         21 my $tz;
656 8 100   8   46 unless ( $tz = try { DateTime::TimeZone->new( name => $name ) } )
  8         220  
657             {
658 6         2617 $name = lc $name;
659 6         93 $name =~ s{(^|[/_])(.)}{$1\U$2}g;
660             }
661 8     8   19655 $tz = try { DateTime::TimeZone->new( name => $name ) };
  8         222  
662 8 100       16924 unless ($tz) {
663 3         15 $self->_our_croak(
664             qq{The Olson time zone name that was parsed does not appear to be valid, "$args->{time_zone_name}"}
665             );
666 1         4 return;
667             }
668 5 50       24 $args->{time_zone} = $tz
669             if $tz;
670             }
671              
672 267         487 delete @{$args}{@non_dt_keys};
  267         1150  
673 267         600 $args->{locale} = $self->{locale};
674              
675 267         549 for my $k ( grep { defined $args->{$_} }
  1602         3434  
676             qw( month day hour minute second nanosecond ) ) {
677 587         1951 $args->{$k} =~ s/^\s+//;
678             }
679              
680 267 100       623 if ( defined $args->{nanosecond} ) {
681              
682             # If we parsed "12345" we treat it as "123450000" but if we parsed
683             # "000123456" we treat it as 123,456 nanoseconds. This is all a bit
684             # weird and confusing but it matches how this module has always
685             # worked.
686             $args->{nanosecond} *= 10**( 9 - length $args->{nanosecond} )
687 6 100       38 if length $args->{nanosecond} != 9;
688              
689             # If we parsed 000000123 we want to turn this into a number.
690 6         16 $args->{nanosecond} += 0;
691             }
692              
693 267         484 for my $k (qw( year month day )) {
694 801 100       1900 $args->{$k} = 1 unless defined $args->{$k};
695             }
696              
697 267 100       755 if ( defined $args->{epoch} ) {
    100          
698              
699             # We don't want to pass a non-integer epoch value since that gets
700             # truncated as of DateTime 1.22. Instead, we'll set the nanosecond
701             # to parsed value after constructing the object. This is a hack,
702             # but it's the best I can come up with.
703 28         42 my $post_construct;
704 28 100       68 if ( my $nano = $args->{nanosecond} ) {
705 2     2   11 $post_construct = sub { $_[0]->set( nanosecond => $nano ) };
  2         11  
706             }
707              
708 28         88 delete @{$args}{
709 28         48 qw( day_of_year year month day hour minute second nanosecond )
710             };
711              
712 28         154 return ( 'from_epoch', $args, $post_construct );
713             }
714             elsif ( $args->{day_of_year} ) {
715 4         9 delete @{$args}{qw( epoch month day )};
  4         14  
716 4         14 return ( 'from_day_of_year', $args );
717             }
718              
719 235         744 return ( 'new', $args );
720             }
721             }
722              
723             ## no critic (Subroutines::ProhibitExcessComplexity)
724             sub _check_dt {
725 258     258   1684 my $self = shift;
726 258         397 my $dt = shift;
727 258         397 my $args = shift;
728              
729             my $is_am = defined $args->{am_pm}
730 258   100     840 && lc $args->{am_pm} eq lc $self->{locale}->am_pm_abbreviated->[0];
731 258 100 100     983 if ( defined $args->{hour} && defined $args->{hour_12} ) {
732 4 100       23 unless ( ( $args->{hour} % 12 ) == $args->{hour_12} ) {
733 3         17 $self->_our_croak(
734             'Parsed an input with 24-hour and 12-hour time values that do not match'
735             . qq{ - "$args->{hour}" versus "$args->{hour_12}"} );
736 1         12 return;
737             }
738             }
739              
740 255 100 100     683 if ( defined $args->{hour} && defined $args->{am_pm} ) {
741 27 100 100     255 if ( ( $is_am && $args->{hour} >= 12 )
      100        
      100        
742             || ( !$is_am && $args->{hour} < 12 ) ) {
743 6         32 $self->_our_croak(
744             'Parsed an input with 24-hour and AM/PM values that do not match'
745             . qq{ - "$args->{hour}" versus "$args->{am_pm}"} );
746 2         21 return;
747             }
748             }
749              
750 249 100 100     992 if ( defined $args->{year} && defined $args->{century} ) {
751 4 100       23 unless ( int( $args->{year} / 100 ) == $args->{century} ) {
752 3         17 $self->_our_croak(
753             'Parsed an input with year and century values that do not match'
754             . qq{ - "$args->{year}" versus "$args->{century}"} );
755 1         11 return;
756             }
757             }
758              
759 246 100 100     856 if ( defined $args->{year} && defined $args->{year_100} ) {
760 4 100       26 unless ( ( $args->{year} % 100 ) == $args->{year_100} ) {
761 3         18 $self->_our_croak(
762             'Parsed an input with year and year-within-century values that do not match'
763             . qq{ - "$args->{year}" versus "$args->{year_100}"} );
764 1         11 return;
765             }
766             }
767              
768 243 100 100     615 if ( defined $args->{time_zone_abbreviation}
769             && defined $args->{time_zone_offset} ) {
770 4 100 66     26 unless ( $self->{zone_map}{ $args->{time_zone_abbreviation} }
771             && $self->{zone_map}{ $args->{time_zone_abbreviation} } eq
772             $args->{time_zone_offset} ) {
773              
774 3         19 $self->_our_croak(
775             'Parsed an input with time zone abbreviation and time zone offset values that do not match'
776             . qq{ - "$args->{time_zone_abbreviation}" versus "$args->{time_zone_offset}"}
777             );
778 1         11 return;
779             }
780             }
781              
782 240 100       531 if ( defined $args->{epoch} ) {
783 28         66 for my $key (
784             qw( year month day minute hour second hour_12 day_of_year )) {
785 140 100 100     417 if ( defined $args->{$key} && $dt->$key != $args->{$key} ) {
786 24 100       244 my $print_key
    100          
787             = $key eq 'hour_12' ? 'hour (1-12)'
788             : $key eq 'day_of_year' ? 'day of year'
789             : $key;
790 24         123 $self->_our_croak(
791             "Parsed an input with epoch and $print_key values that do not match"
792             . qq{ - "$args->{epoch}" versus "$args->{$key}"} );
793 8         81 return;
794             }
795             }
796             }
797              
798 216 100 100     702 if ( defined $args->{month} && defined $args->{day_of_year} ) {
799 4 100       13 unless ( $dt->month == $args->{month} ) {
800 3         34 $self->_our_croak(
801             'Parsed an input with month and day of year values that do not match'
802             . qq{ - "$args->{month}" versus "$args->{day_of_year}"} );
803 1         11 return;
804             }
805             }
806              
807 213 100       487 if ( defined $args->{day_name} ) {
808 44         124 my $dow = $self->_locale_days->{ lc $args->{day_name} };
809 44 50       118 defined $dow
810             or die "We somehow parsed a day name ($args->{day_name})"
811             . ' that does not correspond to any day in this locale!';
812              
813 44 100       127 unless ( $dt->day_of_week_0 == $dow ) {
814 3         27 $self->_our_croak(
815             'Parsed an input where the day name does not match the date'
816             . qq{ - "$args->{day_name}" versus "}
817             . $dt->ymd
818             . q{"} );
819 1         12 return;
820             }
821             }
822              
823 210 100       597 if ( defined $args->{day_of_week} ) {
824 4 100       14 unless ( $dt->day_of_week == $args->{day_of_week} ) {
825 3         26 $self->_our_croak(
826             'Parsed an input where the day of week does not match the date'
827             . qq{ - "$args->{day_of_week}" versus "}
828             . $dt->ymd
829             . q{"} );
830 1         11 return;
831             }
832             }
833              
834 207 100       451 if ( defined $args->{day_of_week_sun_0} ) {
835 4 100       12 unless ( ( $dt->day_of_week % 7 ) == $args->{day_of_week_sun_0} ) {
836 3         26 $self->_our_croak(
837             'Parsed an input where the day of week (Sunday as 0) does not match the date'
838             . qq{ - "$args->{day_of_week_sun_0}" versus "}
839             . $dt->ymd
840             . q{"} );
841 1         13 return;
842             }
843             }
844              
845 204 100       429 if ( defined $args->{iso_week_year} ) {
846 4 100       17 unless ( $dt->week_year == $args->{iso_week_year} ) {
847 3         108 $self->_our_croak(
848             'Parsed an input where the ISO week year does not match the date'
849             . qq{ - "$args->{iso_week_year}" versus "}
850             . $dt->ymd
851             . q{"} );
852 1         13 return;
853             }
854             }
855              
856 201 100       474 if ( defined $args->{iso_week_year_100} ) {
857 4 100       14 unless ( ( 0 + substr( $dt->week_year, -2 ) )
858             == $args->{iso_week_year_100} ) {
859 3         101 $self->_our_croak(
860             'Parsed an input where the ISO week year (without century) does not match the date'
861             . qq{ - "$args->{iso_week_year_100}" versus "}
862             . $dt->ymd
863             . q{"} );
864 1         13 return;
865             }
866             }
867              
868 198 100       451 if ( defined $args->{week_mon_1} ) {
869 4 100       14 unless ( ( 0 + $dt->strftime('%W') ) == $args->{week_mon_1} ) {
870 3         141 $self->_our_croak(
871             'Parsed an input where the ISO week number (Monday starts week) does not match the date'
872             . qq{ - "$args->{week_mon_1}" versus "}
873             . $dt->ymd
874             . q{"} );
875 1         12 return;
876             }
877             }
878              
879 195 100       600 if ( defined $args->{week_sun_0} ) {
880 4 100       13 unless ( ( 0 + $dt->strftime('%U') ) == $args->{week_sun_0} ) {
881 3         132 $self->_our_croak(
882             'Parsed an input where the ISO week number (Sunday starts week) does not match the date'
883             . qq{ - "$args->{week_sun_0}" versus "}
884             . $dt->ymd
885             . q{"} );
886 1         14 return;
887             }
888             }
889              
890 192         670 return 1;
891             }
892             ## use critic
893              
894             sub pattern {
895 29     29 1 58 my $self = shift;
896 29         78 return $self->{pattern};
897             }
898              
899             sub locale {
900 29     29 1 375 my $self = shift;
901             return $self->{locale}->can('code')
902             ? $self->{locale}->code
903 29 50       205 : $self->{locale}->id;
904             }
905              
906             sub time_zone {
907 0     0 1 0 my $self = shift;
908 0         0 return $self->{time_zone}->name;
909             }
910              
911             sub parse_duration {
912 0     0 0 0 croak q{DateTime::Format::Strptime doesn't do durations.};
913             }
914              
915             {
916             my $validator = validation_for( params => [ { type => t('DateTime') } ] );
917              
918             sub format_datetime {
919 30     30 1 89741 my $self = shift;
920 30         895 my ($dt) = $validator->(@_);
921              
922 29         471 my $pattern = $self->pattern;
923 29         83 $pattern =~ s/%O/$dt->time_zone->name/eg;
  2         9  
924 29         119 return $dt->clone->set_locale( $self->locale )->strftime($pattern);
925             }
926              
927             }
928              
929             sub format_duration {
930 0     0 0 0 croak q{DateTime::Format::Strptime doesn't do durations.};
931             }
932              
933             sub _our_croak {
934 97     97   441 my $self = shift;
935 97         154 my $error = shift;
936              
937 97 100       283 return $self->{on_error}->( $self, $error ) if ref $self->{on_error};
938 65 100       3130 croak $error if $self->{on_error} eq 'croak';
939 32         85 $self->{errmsg} = $error;
940 32         66 return;
941             }
942              
943             sub errmsg {
944 32     32 1 179 $_[0]->{errmsg};
945             }
946              
947             # Exportable functions:
948              
949             sub strftime {
950 1     1 1 1216 my ( $pattern, $dt ) = @_;
951 1         5 return DateTime::Format::Strptime->new(
952             pattern => $pattern,
953             on_error => 'croak'
954             )->format_datetime($dt);
955             }
956              
957             sub strptime {
958 1     1 1 116 my ( $pattern, $time_string ) = @_;
959 1         10 return DateTime::Format::Strptime->new(
960             pattern => $pattern,
961             on_error => 'croak'
962             )->parse_datetime($time_string);
963             }
964              
965             1;
966              
967             # ABSTRACT: Parse and format strp and strf time patterns
968              
969             __END__
970              
971             =pod
972              
973             =encoding UTF-8
974              
975             =head1 NAME
976              
977             DateTime::Format::Strptime - Parse and format strp and strf time patterns
978              
979             =head1 VERSION
980              
981             version 1.77
982              
983             =head1 SYNOPSIS
984              
985             use DateTime::Format::Strptime;
986              
987             my $strp = DateTime::Format::Strptime->new(
988             pattern => '%T',
989             locale => 'en_AU',
990             time_zone => 'Australia/Melbourne',
991             );
992              
993             my $dt = $strp->parse_datetime('23:16:42');
994              
995             $strp->format_datetime($dt);
996              
997             # 23:16:42
998              
999             # Croak when things go wrong:
1000             my $strp = DateTime::Format::Strptime->new(
1001             pattern => '%T',
1002             locale => 'en_AU',
1003             time_zone => 'Australia/Melbourne',
1004             on_error => 'croak',
1005             );
1006              
1007             # Do something else when things go wrong:
1008             my $strp = DateTime::Format::Strptime->new(
1009             pattern => '%T',
1010             locale => 'en_AU',
1011             time_zone => 'Australia/Melbourne',
1012             on_error => \&phone_police,
1013             );
1014              
1015             =head1 DESCRIPTION
1016              
1017             This module implements most of C<strptime(3)>, the POSIX function that is the
1018             reverse of C<strftime(3)>, for C<DateTime>. While C<strftime> takes a
1019             C<DateTime> and a pattern and returns a string, C<strptime> takes a string and
1020             a pattern and returns the C<DateTime> object associated.
1021              
1022             =for Pod::Coverage parse_duration format_duration
1023              
1024             =head1 METHODS
1025              
1026             This class offers the following methods.
1027              
1028             =head2 DateTime::Format::Strptime->new(%args)
1029              
1030             This methods creates a new object. It accepts the following arguments:
1031              
1032             =over 4
1033              
1034             =item * pattern
1035              
1036             This is the pattern to use for parsing. This is required.
1037              
1038             =item * strict
1039              
1040             This is a boolean which disables or enables strict matching mode.
1041              
1042             By default, this module turns your pattern into a regex that will match
1043             anywhere in a string. So given the pattern C<%Y%m%d%H%M%S> it will match a
1044             string like C<20161214233712>. However, this also means that a this pattern
1045             will match B<any> string that contains 14 or more numbers! This behavior can
1046             be very surprising.
1047              
1048             If you enable strict mode, then the generated regex is wrapped in boundary
1049             checks of the form C</(?:\A|\b)...(?:\b|\z_/)>. These checks ensure that the
1050             pattern will only match when at the beginning or end of a string, or when it
1051             is separated by other text with a word boundary (C<\w> versus C<\W>).
1052              
1053             By default, strict mode is off. This is done for backwards
1054             compatibility. Future releases may turn it on by default, as it produces less
1055             surprising behavior in many cases.
1056              
1057             Because the default may change in the future, B<< you are strongly encouraged
1058             to explicitly set this when constructing all C<DateTime::Format::Strptime>
1059             objects >>.
1060              
1061             =item * time_zone
1062              
1063             The default time zone to use for objects returned from parsing.
1064              
1065             =item * zone_map
1066              
1067             Some time zone abbreviations are ambiguous (e.g. PST, EST, EDT). By default,
1068             the parser will die when it parses an ambiguous abbreviation. You may specify
1069             a C<zone_map> parameter as a hashref to map zone abbreviations however you like:
1070              
1071             zone_map => { PST => '-0800', EST => '-0600' }
1072              
1073             Note that you can also override non-ambiguous mappings if you want to as well.
1074              
1075             =item * locale
1076              
1077             The locale to use for objects returned from parsing.
1078              
1079             =item * on_error
1080              
1081             This can be one of C<'undef'> (the string, not an C<undef>), 'croak', or a
1082             subroutine reference.
1083              
1084             =over 8
1085              
1086             =item * 'undef'
1087              
1088             This is the default behavior. The module will return C<undef> on errors. The
1089             error can be accessed using the C<< $object->errmsg >> method. This is the
1090             ideal behaviour for interactive use where a user might provide an illegal
1091             pattern or a date that doesn't match the pattern.
1092              
1093             =item * 'croak'
1094              
1095             The module will croak with an error message on errors.
1096              
1097             =item * sub{...} or \&subname
1098              
1099             When given a code ref, the module will call that sub on errors. The sub
1100             receives two parameters: the object and the error message.
1101              
1102             If your sub does not die, then the formatter will continue on as if
1103             C<on_error> was C<'undef'>.
1104              
1105             =back
1106              
1107             =back
1108              
1109             =head2 $strptime->parse_datetime($string)
1110              
1111             Given a string in the pattern specified in the constructor, this method
1112             will return a new C<DateTime> object.
1113              
1114             If given a string that doesn't match the pattern, the formatter will croak or
1115             return undef, depending on the setting of C<on_error> in the constructor.
1116              
1117             =head2 $strptime->format_datetime($datetime)
1118              
1119             Given a C<DateTime> object, this methods returns a string formatted in the
1120             object's format. This method is synonymous with C<DateTime>'s strftime method.
1121              
1122             =head2 $strptime->locale
1123              
1124             This method returns the locale passed to the object's constructor.
1125              
1126             =head2 $strptime->pattern
1127              
1128             This method returns the pattern passed to the object's constructor.
1129              
1130             =head2 $strptime->time_zone
1131              
1132             This method returns the time zone passed to the object's constructor.
1133              
1134             =head2 $strptime->errmsg
1135              
1136             If the on_error behavior of the object is 'undef', you can retrieve error
1137             messages with this method so you can work out why things went wrong.
1138              
1139             =head1 EXPORTS
1140              
1141             These subs are available as optional exports.
1142              
1143             =head2 strptime( $strptime_pattern, $string )
1144              
1145             Given a pattern and a string this function will return a new C<DateTime>
1146             object.
1147              
1148             =head2 strftime( $strftime_pattern, $datetime )
1149              
1150             Given a pattern and a C<DateTime> object this function will return a
1151             formatted string.
1152              
1153             =head1 STRPTIME PATTERN TOKENS
1154              
1155             The following tokens are allowed in the pattern string for strptime
1156             (parse_datetime):
1157              
1158             =over 4
1159              
1160             =item * %%
1161              
1162             The % character.
1163              
1164             =item * %a or %A
1165              
1166             The weekday name according to the given locale, in abbreviated form or
1167             the full name.
1168              
1169             =item * %b or %B or %h
1170              
1171             The month name according to the given locale, in abbreviated form or
1172             the full name.
1173              
1174             =item * %c
1175              
1176             The datetime format according to the given locale.
1177              
1178             =item * %C
1179              
1180             The century number (0-99).
1181              
1182             =item * %d or %e
1183              
1184             The day of month (01-31). This will parse single digit numbers as well.
1185              
1186             =item * %D
1187              
1188             Equivalent to %m/%d/%y. (This is the American style date, very confusing
1189             to non-Americans, especially since %d/%m/%y is widely used in Europe.
1190             The ISO 8601 standard pattern is %F.)
1191              
1192             =item * %F
1193              
1194             Equivalent to %Y-%m-%d. (This is the ISO style date)
1195              
1196             =item * %g
1197              
1198             The year corresponding to the ISO week number, but without the century
1199             (0-99).
1200              
1201             =item * %G
1202              
1203             The 4-digit year corresponding to the ISO week number.
1204              
1205             =item * %H
1206              
1207             The hour (00-23). This will parse single digit numbers as well.
1208              
1209             =item * %I
1210              
1211             The hour on a 12-hour clock (1-12).
1212              
1213             =item * %j
1214              
1215             The day number in the year (1-366).
1216              
1217             =item * %m
1218              
1219             The month number (01-12). This will parse single digit numbers as well.
1220              
1221             =item * %M
1222              
1223             The minute (00-59). This will parse single digit numbers as well.
1224              
1225             =item * %n
1226              
1227             Arbitrary whitespace.
1228              
1229             =item * %N
1230              
1231             Nanoseconds. For other sub-second values use C<%[number]N>.
1232              
1233             =item * %p or %P
1234              
1235             The equivalent of AM or PM according to the locale in use. See
1236             L<DateTime::Locale>.
1237              
1238             =item * %r
1239              
1240             Equivalent to %I:%M:%S %p.
1241              
1242             =item * %R
1243              
1244             Equivalent to %H:%M.
1245              
1246             =item * %s
1247              
1248             Number of seconds since the Epoch.
1249              
1250             =item * %S
1251              
1252             The second (0-60; 60 may occur for leap seconds. See
1253             L<DateTime::LeapSecond>).
1254              
1255             =item * %t
1256              
1257             Arbitrary whitespace.
1258              
1259             =item * %T
1260              
1261             Equivalent to %H:%M:%S.
1262              
1263             =item * %U
1264              
1265             The week number with Sunday the first day of the week (0-53). The first
1266             Sunday of January is the first day of week 1.
1267              
1268             =item * %u
1269              
1270             The weekday number (1-7) with Monday = 1. This is the C<DateTime> standard.
1271              
1272             =item * %w
1273              
1274             The weekday number (0-6) with Sunday = 0.
1275              
1276             =item * %W
1277              
1278             The week number with Monday the first day of the week (0-53). The first
1279             Monday of January is the first day of week 1.
1280              
1281             =item * %x
1282              
1283             The date format according to the given locale.
1284              
1285             =item * %X
1286              
1287             The time format according to the given locale.
1288              
1289             =item * %y
1290              
1291             The year within century (0-99). When a century is not otherwise specified
1292             (with a value for %C), values in the range 69-99 refer to years in the
1293             twentieth century (1969-1999); values in the range 00-68 refer to years in the
1294             twenty-first century (2000-2068).
1295              
1296             =item * %Y
1297              
1298             A 4-digit year, including century (for example, 1991).
1299              
1300             =item * %z
1301              
1302             An RFC-822/ISO 8601 standard time zone specification. (For example
1303             +1100) [See note below]
1304              
1305             =item * %Z
1306              
1307             The timezone name. (For example EST -- which is ambiguous) [See note
1308             below]
1309              
1310             =item * %O
1311              
1312             This extended token allows the use of Olson Time Zone names to appear
1313             in parsed strings. B<NOTE>: This pattern cannot be passed to C<DateTime>'s
1314             C<strftime()> method, but can be passed to C<format_datetime()>.
1315              
1316             =back
1317              
1318             =head1 AUTHOR EMERITUS
1319              
1320             This module was created by Rick Measham.
1321              
1322             =head1 SEE ALSO
1323              
1324             C<datetime@perl.org> mailing list.
1325              
1326             http://datetime.perl.org/
1327              
1328             L<perl>, L<DateTime>, L<DateTime::TimeZone>, L<DateTime::Locale>
1329              
1330             =head1 BUGS
1331              
1332             Please report any bugs or feature requests to
1333             C<bug-datetime-format-strptime@rt.cpan.org>, or through the web interface at
1334             L<http://rt.cpan.org>. I will be notified, and then you'll automatically be
1335             notified of progress on your bug as I make changes.
1336              
1337             Bugs may be submitted at L<https://github.com/houseabsolute/DateTime-Format-Strptime/issues>.
1338              
1339             There is a mailing list available for users of this distribution,
1340             L<mailto:datetime@perl.org>.
1341              
1342             I am also usually active on IRC as 'autarch' on C<irc://irc.perl.org>.
1343              
1344             =head1 SOURCE
1345              
1346             The source code repository for DateTime-Format-Strptime can be found at L<https://github.com/houseabsolute/DateTime-Format-Strptime>.
1347              
1348             =head1 DONATIONS
1349              
1350             If you'd like to thank me for the work I've done on this module, please
1351             consider making a "donation" to me via PayPal. I spend a lot of free time
1352             creating free software, and would appreciate any support you'd care to offer.
1353              
1354             Please note that B<I am not suggesting that you must do this> in order for me
1355             to continue working on this particular software. I will continue to do so,
1356             inasmuch as I have in the past, for as long as it interests me.
1357              
1358             Similarly, a donation made in this way will probably not make me work on this
1359             software much more, unless I get so many donations that I can consider working
1360             on free software full time (let's all have a chuckle at that together).
1361              
1362             To donate, log into PayPal and send money to autarch@urth.org, or use the
1363             button at L<http://www.urth.org/~autarch/fs-donation.html>.
1364              
1365             =head1 AUTHORS
1366              
1367             =over 4
1368              
1369             =item *
1370              
1371             Dave Rolsky <autarch@urth.org>
1372              
1373             =item *
1374              
1375             Rick Measham <rickm@cpan.org>
1376              
1377             =back
1378              
1379             =head1 CONTRIBUTORS
1380              
1381             =for stopwords Christian Hansen D. Ilmari MannsÃ¥ker gregor herrmann key-amb Mohammad S Anwar
1382              
1383             =over 4
1384              
1385             =item *
1386              
1387             Christian Hansen <chansen@cpan.org>
1388              
1389             =item *
1390              
1391             D. Ilmari MannsÃ¥ker <ilmari.mannsaker@net-a-porter.com>
1392              
1393             =item *
1394              
1395             gregor herrmann <gregoa@debian.org>
1396              
1397             =item *
1398              
1399             key-amb <yasutake.kiyoshi@gmail.com>
1400              
1401             =item *
1402              
1403             Mohammad S Anwar <mohammad.anwar@yahoo.com>
1404              
1405             =back
1406              
1407             =head1 COPYRIGHT AND LICENSE
1408              
1409             This software is Copyright (c) 2015 - 2020 by Dave Rolsky.
1410              
1411             This is free software, licensed under:
1412              
1413             The Artistic License 2.0 (GPL Compatible)
1414              
1415             The full text of the license can be found in the
1416             F<LICENSE> file included with this distribution.
1417              
1418             =cut