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   1514608 use strict;
  12         29  
  12         467  
4 12     12   64 use warnings;
  12         68  
  12         846  
5              
6             our $VERSION = '1.80';
7              
8 12     12   77 use Carp qw( carp croak );
  12         25  
  12         743  
9 12     12   11034 use DateTime 1.00;
  12         7757094  
  12         911  
10 12     12   128 use DateTime::Locale 1.30;
  12         175  
  12         346  
11 12     12   7642 use DateTime::Format::Strptime::Types;
  12         78  
  12         206  
12 12     12   283086 use DateTime::TimeZone 2.09;
  12         293  
  12         432  
13 12     12   89 use Exporter ();
  12         36  
  12         402  
14 12     12   69 use Params::ValidationCompiler qw( validation_for );
  12         23  
  12         1179  
15 12     12   113 use Try::Tiny;
  12         26  
  12         1417  
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         680  
  12         83001  
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   3092 my $class = shift;
27 14         30 my @args;
28             ## no critic (ControlStructures::ProhibitCStyleForLoops)
29 14         85 for ( my $i = 0; $i < @_; $i++ ) {
30 3 100       8 if ( $_[$i] eq '-api_version' ) {
31 1         2 $i++;
32             }
33             else {
34 2         7 push @args, $_[$i];
35             }
36             }
37 14         67 @_ = ( $class, @args );
38 14         17214 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 8311239 my $class = shift;
76 294         11417 my %args = $validator->(@_);
77              
78             my $self = bless {
79             %args,
80 294         20376 zone_map => $class->_build_zone_map( $args{zone_map} ),
81             }, $class;
82              
83             # Forces a check that the pattern is valid
84 294         1997 $self->_parser;
85              
86 293 50       1336 if ( $self->{debug} ) {
87 0 0       0 binmode STDERR, ':encoding(UTF-8)' or die $!;
88             }
89              
90 293         5199 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   21154 %{ $_[1] },
  294         58610  
211             };
212             }
213             }
214              
215             sub parse_datetime {
216 289     289 1 180223 my $self = shift;
217 289         729 my $string = shift;
218              
219 289         869 my $parser = $self->_parser;
220 289 50       1083 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         4986 my @matches = ( $string =~ $parser->{regex} );
226 289 100       1047 unless (@matches) {
227 6         49 my $msg = 'Your datetime does not match your pattern';
228 6 50       19 if ( $self->{debug} ) {
229 0         0 $msg .= qq{ - string = "$string" - regex = $parser->{regex}};
230             }
231 6         12 $msg .= q{.};
232 6         24 $self->_our_croak($msg);
233 2         6 return;
234             }
235              
236 283         559 my %args;
237 283         560 my $i = 0;
238 283         538 for my $f ( @{ $parser->{fields} } ) {
  283         944  
239 1109 50       2446 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 1109         3310 $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         2131 my ( $constructor, $args, $post_construct )
251             = $self->_munge_args( {%args} );
252 272 100 66     1522 return unless $constructor && $args;
253              
254 267     267   2616 my $dt = try { DateTime->$constructor($args) };
  267         10801  
255 267 100       190772 $self->_our_croak('Parsed values did not produce a valid date')
256             unless $dt;
257 261 100       4549 if ($post_construct) {
258 2         8 $post_construct->($dt);
259             }
260 261 100 100     2145 return unless $dt && $self->_check_dt( $dt, \%args );
261              
262             $dt->set_time_zone( $self->{time_zone} )
263 192 100       712 if $self->{time_zone};
264              
265 192         2113 return $dt;
266             }
267              
268             sub _parser {
269 583     583   1232 my $self = shift;
270              
271 583   66     3090 return $self->{parser} ||= $self->_build_parser;
272             }
273              
274             sub _build_parser {
275 294     294   578 my $self = shift;
276              
277             my (
278 294         1013 $replacement_tokens_re,
279             $replacements,
280             $pattern_tokens_re,
281             $patterns,
282             ) = $self->_parser_pieces;
283              
284 294         2285 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         4747 $pattern =~ s/%($replacement_tokens_re)/$replacements->{$1}/g for 1 .. 2;
290              
291 294 50 33     1275 if ( $self->{debug} && $pattern ne $self->{pattern} ) {
292 0         0 warn "Pattern after replacement substitution: $pattern\n";
293             }
294              
295 294         656 my $regex = q{};
296 294         561 my @fields;
297              
298 294         3823 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 1978         3247 substr( $pattern, 0, pos $pattern, q{} )
313             if PERL_58;
314 1978 100       6797 if ($1) {
    100          
    100          
315 1139 50       3695 my $p = $patterns->{$1}
316             or croak
317             "Unidentified token in pattern: $1 in $self->{pattern}";
318 1139 100       2795 if ( $p->{field} ) {
319 1128         40009 $regex .= qr/($p->{regex})/;
320 1128         10283 push @fields, $p->{field};
321             }
322             else {
323 11         92 $regex .= qr/$p->{regex}/;
324             }
325             }
326             elsif ($3) {
327 6 100       72 $regex .= $2 ? qr/([0-9]{$2})/ : qr/([0-9]+)/;
328 6         38 push @fields, 'nanosecond';
329             }
330             elsif ($4) {
331 1         315 croak qq{Pattern contained an unrecognized strptime token, "$4"};
332             }
333             else {
334 832         10183 $regex .= qr/\Q$5/;
335             }
336             }
337              
338             return {
339             regex => (
340 293 100       16891 $self->{strict} ? qr/(?:\A|\b)$regex(?:\b|\Z)/ : qr/$regex/
341             ),
342             fields => \@fields,
343             };
344             }
345              
346             {
347             my $digit = qr/(?:[0-9])/;
348             my $one_or_two_digits = qr/[0-9 ]?$digit/;
349              
350             # These patterns are all locale-independent. There are a few that depend
351             # on the locale, and must be re-calculated for each new parser object.
352             my %universal_patterns = (
353             '%' => {
354             regex => qr/%/,
355             },
356             C => {
357             regex => $one_or_two_digits,
358             field => 'century',
359             },
360             d => {
361             regex => $one_or_two_digits,
362             field => 'day',
363             },
364             g => {
365             regex => $one_or_two_digits,
366             field => 'iso_week_year_100',
367             },
368             G => {
369             regex => qr/$digit{4}/,
370             field => 'iso_week_year',
371             },
372             H => {
373             regex => $one_or_two_digits,
374             field => 'hour',
375             },
376             I => {
377             regex => $one_or_two_digits,
378             field => 'hour_12',
379             },
380             j => {
381             regex => qr/$digit{1,3}/,
382             field => 'day_of_year',
383             },
384             m => {
385             regex => $one_or_two_digits,
386             field => 'month',
387             },
388             M => {
389             regex => $one_or_two_digits,
390             field => 'minute',
391             },
392             n => {
393             regex => qr/\s+/,
394             },
395             O => {
396             regex => qr{[a-zA-Z_]+(?:/[a-zA-Z_]+(?:/[a-zA-Z_]+)?)?},
397             field => 'time_zone_name',
398             },
399             s => {
400             regex => qr/$digit+/,
401             field => 'epoch',
402             },
403             S => {
404             regex => $one_or_two_digits,
405             field => 'second',
406             },
407             U => {
408             regex => $one_or_two_digits,
409             field => 'week_sun_0',
410             },
411             u => {
412             regex => $one_or_two_digits,
413             field => 'day_of_week',
414             },
415             w => {
416             regex => $one_or_two_digits,
417             field => 'day_of_week_sun_0',
418             },
419             W => {
420             regex => $one_or_two_digits,
421             field => 'week_mon_1',
422             },
423             y => {
424             regex => $one_or_two_digits,
425             field => 'year_100',
426             },
427             Y => {
428             regex => qr/$digit{4}/,
429             field => 'year',
430             },
431             z => {
432             regex => qr/(?:Z|[+-]$digit{2}(?:[:]?$digit{2})?)/,
433             field => 'time_zone_offset',
434             },
435             Z => {
436             regex => qr/[a-zA-Z]{1,6}|[\-\+]$digit{2}/,
437             field => 'time_zone_abbreviation',
438             },
439             );
440              
441             $universal_patterns{e} = $universal_patterns{d};
442             $universal_patterns{k} = $universal_patterns{H};
443             $universal_patterns{l} = $universal_patterns{I};
444             $universal_patterns{t} = $universal_patterns{n};
445              
446             my %universal_replacements = (
447             D => '%m/%d/%y',
448             F => '%Y-%m-%d',
449             r => '%I:%M:%S %p',
450             R => '%H:%M',
451             T => '%H:%M:%S',
452             );
453              
454             sub _parser_pieces {
455 294     294   606 my $self = shift;
456              
457 294         1932 my %replacements = %universal_replacements;
458 294         2034 $replacements{c} = $self->{locale}->glibc_datetime_format;
459 294         2693 $replacements{x} = $self->{locale}->glibc_date_format;
460 294         2370 $replacements{X} = $self->{locale}->glibc_time_format;
461              
462 294         5824 my %patterns = %universal_patterns;
463             $patterns{a} = $patterns{A} = {
464 294         1132 regex => do {
465 4116         9070 my $days = join '|', map {quotemeta}
466 11144 50       23549 sort { ( length $b <=> length $a ) or ( $a cmp $b ) }
467 294         634 keys %{ $self->_locale_days };
  294         953  
468 294         5662 qr/$days/i;
469             },
470             field => 'day_name',
471             };
472              
473             $patterns{b} = $patterns{B} = $patterns{h} = {
474 294         783 regex => do {
475 6692         15600 my $months = join '|', map {quotemeta}
476 22767 50       47366 sort { ( length $b <=> length $a ) or ( $a cmp $b ) }
477 294         623 keys %{ $self->_locale_months };
  294         1086  
478 294         6693 qr/$months/i;
479             },
480             field => 'month_name',
481             };
482              
483             $patterns{p} = $patterns{P} = {
484 294         737 regex => do {
485             my $am_pm = join '|',
486 588         1625 map {quotemeta}
487 294 0       2923 sort { ( length $b <=> length $a ) or ( $a cmp $b ) }
488 294         613 @{ $self->{locale}->am_pm_abbreviated };
  294         1566  
489 294         2416 qr/$am_pm/i;
490             },
491             field => 'am_pm',
492             };
493              
494             return (
495 294         1680 $self->_token_re_for( keys %replacements ),
496             \%replacements,
497             $self->_token_re_for( keys %patterns ),
498             \%patterns,
499             );
500             }
501             }
502              
503             sub _locale_days {
504 338     338   729 my $self = shift;
505              
506 338 100       1406 return $self->{locale_days} if $self->{locale_days};
507              
508 294         1347 my $wide = $self->{locale}->day_format_wide;
509 294         1932 my $abbr = $self->{locale}->day_format_abbreviated;
510              
511 294         1193 my %locale_days;
512 294         1048 for my $i ( 0 .. 6 ) {
513 2058         5564 $locale_days{ lc $wide->[$i] } = $i;
514 2058         5344 $locale_days{ lc $abbr->[$i] } = $i;
515             }
516              
517 294   50     4354 return $self->{locale_days} ||= \%locale_days;
518             }
519              
520             sub _locale_months {
521 369     369   770 my $self = shift;
522              
523 369 100       1473 return $self->{locale_months} if $self->{locale_months};
524              
525 294         1450 my $wide = $self->{locale}->month_format_wide;
526 294         2228 my $abbr = $self->{locale}->month_format_abbreviated;
527              
528 294         1263 my %locale_months;
529 294         959 for my $i ( 0 .. 11 ) {
530 3528         9305 $locale_months{ lc $wide->[$i] } = $i + 1;
531 3528         8601 $locale_months{ lc $abbr->[$i] } = $i + 1;
532             }
533              
534 294   50     4674 return $self->{locale_months} ||= \%locale_months;
535             }
536              
537             sub _token_re_for {
538 588     588   1323 shift;
539             my $t = join '|',
540 588 0       1747 sort { ( length $b <=> length $a ) or ( $a cmp $b ) } @_;
  42309         79107  
541              
542 588         52993 return qr/$t/;
543             }
544              
545             {
546             # These are fields we parse that cannot be passed to a DateTime
547             # constructor
548             my @non_dt_keys = qw(
549             am_pm
550             century
551             day_name
552             day_of_week
553             day_of_week_sun_0
554             hour_12
555             iso_week_year
556             iso_week_year_100
557             month_name
558             time_zone_abbreviation
559             time_zone_name
560             time_zone_offset
561             week_mon_1
562             week_sun_0
563             year_100
564             );
565              
566             ## no critic (Subroutines::ProhibitExcessComplexity)
567             sub _munge_args {
568 283     283   607 my $self = shift;
569 283         540 my $args = shift;
570              
571 283 100       1068 if ( defined $args->{month_name} ) {
572             my $num = $self->_locale_months->{ lc $args->{month_name} }
573 75 50       237 or die "We somehow parsed a month name ($args->{month_name})"
574             . ' that does not correspond to any month in this locale!';
575              
576 75         266 $args->{month} = $num;
577             }
578              
579 283 100 100     1756 if ( defined $args->{am_pm} && defined $args->{hour_12} ) {
    100          
580 12         27 my ( $am, $pm ) = @{ $self->{locale}->am_pm_abbreviated };
  12         65  
581 12         118 $args->{hour} = $args->{hour_12};
582              
583 12 100       55 if ( lc $args->{am_pm} eq lc $am ) {
584 4 50       21 $args->{hour} = 0 if $args->{hour} == 12;
585             }
586             else {
587 8 50       45 $args->{hour} += 12 unless $args->{hour} == 12;
588             }
589             }
590             elsif ( defined $args->{hour_12} ) {
591 3         20 $self->_our_croak(
592             qq{Parsed a 12-hour based hour, "$args->{hour_12}",}
593             . ' but the pattern does not include an AM/PM specifier'
594             );
595 1         4 return;
596             }
597              
598 280 100       876 if ( defined $args->{year_100} ) {
599 10 100       37 if ( defined $args->{century} ) {
600             $args->{year}
601 1         7 = $args->{year_100} + ( $args->{century} * 100 );
602             }
603             else {
604             $args->{year} = $args->{year_100} + (
605 9 100       55 $args->{year_100} >= 69
606             ? 1900
607             : 2000
608             );
609             }
610             }
611              
612 280 100       861 if ( $args->{time_zone_offset} ) {
613 14         35 my $offset = $args->{time_zone_offset};
614              
615 14 100       86 if ( $offset eq 'Z' ) {
    100          
616 1         2 $offset = '+0000';
617             }
618             elsif ( $offset =~ /^[+-][0-9]{2}$/ ) {
619 2         7 $offset .= '00';
620             }
621              
622 14     14   139 my $tz = try { DateTime::TimeZone->new( name => $offset ) };
  14         456  
623 14 100       9888 unless ($tz) {
624 3         13 $self->_our_croak(
625             qq{The time zone name offset that was parsed does not appear to be valid, "$args->{time_zone_offset}"}
626             );
627 1         3 return;
628             }
629              
630 11         45 $args->{time_zone} = $tz;
631             }
632              
633 277 100       761 if ( defined $args->{time_zone_abbreviation} ) {
634 18         41 my $abbr = $args->{time_zone_abbreviation};
635 18 100       72 unless ( exists $self->{zone_map}{$abbr} ) {
636 3         18 $self->_our_croak(
637             qq{Parsed an unrecognized time zone abbreviation, "$args->{time_zone_abbreviation}"}
638             );
639 1         4 return;
640             }
641 15 100       53 if ( !defined $self->{zone_map}{$abbr} ) {
642 4         23 $self->_our_croak(
643             qq{The time zone abbreviation that was parsed is ambiguous, "$args->{time_zone_abbreviation}"}
644             );
645 1         5 return;
646             }
647             $args->{time_zone}
648 11         85 = DateTime::TimeZone->new( name => $self->{zone_map}{$abbr} );
649             }
650             else {
651 259   100     1356 $args->{time_zone} ||= 'floating';
652             }
653              
654 270 100       4575 if ( $args->{time_zone_name} ) {
655 8         19 my $name = $args->{time_zone_name};
656 8         14 my $tz;
657 8 100   8   48 unless ( $tz = try { DateTime::TimeZone->new( name => $name ) } )
  8         215  
658             {
659 6         2766 $name = lc $name;
660 6         91 $name =~ s{(^|[/_])(.)}{$1\U$2}g;
661             }
662 8     8   27540 $tz = try { DateTime::TimeZone->new( name => $name ) };
  8         276  
663 8 100       20842 unless ($tz) {
664 3         19 $self->_our_croak(
665             qq{The Olson time zone name that was parsed does not appear to be valid, "$args->{time_zone_name}"}
666             );
667 1         4 return;
668             }
669 5 50       37 $args->{time_zone} = $tz
670             if $tz;
671             }
672              
673 267         951 delete @{$args}{@non_dt_keys};
  267         1476  
674 267         886 $args->{locale} = $self->{locale};
675              
676 267         782 for my $k ( grep { defined $args->{$_} }
  1602         3694  
677             qw( month day hour minute second nanosecond ) ) {
678 587         1887 $args->{$k} =~ s/^\s+//;
679             }
680              
681 267 100       930 if ( defined $args->{nanosecond} ) {
682              
683             # If we parsed "12345" we treat it as "123450000" but if we parsed
684             # "000123456" we treat it as 123,456 nanoseconds. This is all a bit
685             # weird and confusing but it matches how this module has always
686             # worked.
687             $args->{nanosecond} *= 10**( 9 - length $args->{nanosecond} )
688 6 100       42 if length $args->{nanosecond} != 9;
689              
690             # If we parsed 000000123 we want to turn this into a number.
691 6         21 $args->{nanosecond} += 0;
692             }
693              
694 267         688 for my $k (qw( year month day )) {
695 801 100       2295 $args->{$k} = 1 unless defined $args->{$k};
696             }
697              
698 267 100       1145 if ( defined $args->{epoch} ) {
    100          
699              
700             # We don't want to pass a non-integer epoch value since that gets
701             # truncated as of DateTime 1.22. Instead, we'll set the nanosecond
702             # to parsed value after constructing the object. This is a hack,
703             # but it's the best I can come up with.
704 28         43 my $post_construct;
705 28 100       84 if ( my $nano = $args->{nanosecond} ) {
706 2     2   14 $post_construct = sub { $_[0]->set( nanosecond => $nano ) };
  2         56  
707             }
708              
709 28         96 delete @{$args}{
710 28         81 qw( day_of_year year month day hour minute second nanosecond )
711             };
712              
713 28         130 return ( 'from_epoch', $args, $post_construct );
714             }
715             elsif ( $args->{day_of_year} ) {
716 4         8 delete @{$args}{qw( epoch month day )};
  4         10  
717 4         17 return ( 'from_day_of_year', $args );
718             }
719              
720 235         919 return ( 'new', $args );
721             }
722             }
723              
724             ## no critic (Subroutines::ProhibitExcessComplexity)
725             sub _check_dt {
726 258     258   2372 my $self = shift;
727 258         532 my $dt = shift;
728 258         503 my $args = shift;
729              
730             my $is_am = defined $args->{am_pm}
731 258   100     1207 && lc $args->{am_pm} eq lc $self->{locale}->am_pm_abbreviated->[0];
732 258 100 100     1391 if ( defined $args->{hour} && defined $args->{hour_12} ) {
733 4 100       24 unless ( ( $args->{hour} % 12 ) == $args->{hour_12} ) {
734 3         48 $self->_our_croak(
735             'Parsed an input with 24-hour and 12-hour time values that do not match'
736             . qq{ - "$args->{hour}" versus "$args->{hour_12}"} );
737 1         19 return;
738             }
739             }
740              
741 255 100 100     1106 if ( defined $args->{hour} && defined $args->{am_pm} ) {
742 27 100 100     300 if ( ( $is_am && $args->{hour} >= 12 )
      100        
      100        
743             || ( !$is_am && $args->{hour} < 12 ) ) {
744 6         41 $self->_our_croak(
745             'Parsed an input with 24-hour and AM/PM values that do not match'
746             . qq{ - "$args->{hour}" versus "$args->{am_pm}"} );
747 2         30 return;
748             }
749             }
750              
751 249 100 100     1361 if ( defined $args->{year} && defined $args->{century} ) {
752 4 100       27 unless ( int( $args->{year} / 100 ) == $args->{century} ) {
753 3         20 $self->_our_croak(
754             'Parsed an input with year and century values that do not match'
755             . qq{ - "$args->{year}" versus "$args->{century}"} );
756 1         19 return;
757             }
758             }
759              
760 246 100 100     1156 if ( defined $args->{year} && defined $args->{year_100} ) {
761 4 100       21 unless ( ( $args->{year} % 100 ) == $args->{year_100} ) {
762 3         18 $self->_our_croak(
763             'Parsed an input with year and year-within-century values that do not match'
764             . qq{ - "$args->{year}" versus "$args->{year_100}"} );
765 1         15 return;
766             }
767             }
768              
769 243 100 100     971 if ( defined $args->{time_zone_abbreviation}
770             && defined $args->{time_zone_offset} ) {
771 4 100 66     30 unless ( $self->{zone_map}{ $args->{time_zone_abbreviation} }
772             && $self->{zone_map}{ $args->{time_zone_abbreviation} } eq
773             $args->{time_zone_offset} ) {
774              
775 3         17 $self->_our_croak(
776             'Parsed an input with time zone abbreviation and time zone offset values that do not match'
777             . qq{ - "$args->{time_zone_abbreviation}" versus "$args->{time_zone_offset}"}
778             );
779 1         10 return;
780             }
781             }
782              
783 240 100       845 if ( defined $args->{epoch} ) {
784 28         75 for my $key (
785             qw( year month day minute hour second hour_12 day_of_year )) {
786 140 100 100     417 if ( defined $args->{$key} && $dt->$key != $args->{$key} ) {
787 24 100       250 my $print_key
    100          
788             = $key eq 'hour_12' ? 'hour (1-12)'
789             : $key eq 'day_of_year' ? 'day of year'
790             : $key;
791 24         130 $self->_our_croak(
792             "Parsed an input with epoch and $print_key values that do not match"
793             . qq{ - "$args->{epoch}" versus "$args->{$key}"} );
794 8         116 return;
795             }
796             }
797             }
798              
799 216 100 100     1158 if ( defined $args->{month} && defined $args->{day_of_year} ) {
800 4 100       14 unless ( $dt->month == $args->{month} ) {
801 3         37 $self->_our_croak(
802             'Parsed an input with month and day of year values that do not match'
803             . qq{ - "$args->{month}" versus "$args->{day_of_year}"} );
804 1         15 return;
805             }
806             }
807              
808 213 100       707 if ( defined $args->{day_name} ) {
809 44         138 my $dow = $self->_locale_days->{ lc $args->{day_name} };
810 44 50       153 defined $dow
811             or die "We somehow parsed a day name ($args->{day_name})"
812             . ' that does not correspond to any day in this locale!';
813              
814 44 100       168 unless ( $dt->day_of_week_0 == $dow ) {
815 3         23 $self->_our_croak(
816             'Parsed an input where the day name does not match the date'
817             . qq{ - "$args->{day_name}" versus "}
818             . $dt->ymd
819             . q{"} );
820 1         12 return;
821             }
822             }
823              
824 210 100       907 if ( defined $args->{day_of_week} ) {
825 4 100       17 unless ( $dt->day_of_week == $args->{day_of_week} ) {
826 3         28 $self->_our_croak(
827             'Parsed an input where the day of week does not match the date'
828             . qq{ - "$args->{day_of_week}" versus "}
829             . $dt->ymd
830             . q{"} );
831 1         10 return;
832             }
833             }
834              
835 207 100       676 if ( defined $args->{day_of_week_sun_0} ) {
836 4 100       11 unless ( ( $dt->day_of_week % 7 ) == $args->{day_of_week_sun_0} ) {
837 3         23 $self->_our_croak(
838             'Parsed an input where the day of week (Sunday as 0) does not match the date'
839             . qq{ - "$args->{day_of_week_sun_0}" versus "}
840             . $dt->ymd
841             . q{"} );
842 1         11 return;
843             }
844             }
845              
846 204 100       689 if ( defined $args->{iso_week_year} ) {
847 4 100       22 unless ( $dt->week_year == $args->{iso_week_year} ) {
848 3         129 $self->_our_croak(
849             'Parsed an input where the ISO week year does not match the date'
850             . qq{ - "$args->{iso_week_year}" versus "}
851             . $dt->ymd
852             . q{"} );
853 1         18 return;
854             }
855             }
856              
857 201 100       628 if ( defined $args->{iso_week_year_100} ) {
858 4 100       17 unless ( ( 0 + substr( $dt->week_year, -2 ) )
859             == $args->{iso_week_year_100} ) {
860 3         118 $self->_our_croak(
861             'Parsed an input where the ISO week year (without century) does not match the date'
862             . qq{ - "$args->{iso_week_year_100}" versus "}
863             . $dt->ymd
864             . q{"} );
865 1         12 return;
866             }
867             }
868              
869 198 100       673 if ( defined $args->{week_mon_1} ) {
870 4 100       19 unless ( ( 0 + $dt->strftime('%W') ) == $args->{week_mon_1} ) {
871 3         159 $self->_our_croak(
872             'Parsed an input where the ISO week number (Monday starts week) does not match the date'
873             . qq{ - "$args->{week_mon_1}" versus "}
874             . $dt->ymd
875             . q{"} );
876 1         17 return;
877             }
878             }
879              
880 195 100       675 if ( defined $args->{week_sun_0} ) {
881 4 100       16 unless ( ( 0 + $dt->strftime('%U') ) == $args->{week_sun_0} ) {
882 3         131 $self->_our_croak(
883             'Parsed an input where the ISO week number (Sunday starts week) does not match the date'
884             . qq{ - "$args->{week_sun_0}" versus "}
885             . $dt->ymd
886             . q{"} );
887 1         16 return;
888             }
889             }
890              
891 192         971 return 1;
892             }
893             ## use critic
894              
895             sub pattern {
896 29     29 1 91 my $self = shift;
897 29         133 return $self->{pattern};
898             }
899              
900             sub locale {
901 29     29 1 558 my $self = shift;
902             return $self->{locale}->can('code')
903             ? $self->{locale}->code
904 29 50       372 : $self->{locale}->id;
905             }
906              
907             sub time_zone {
908 0     0 1 0 my $self = shift;
909 0         0 return $self->{time_zone}->name;
910             }
911              
912             sub parse_duration {
913 0     0 0 0 croak q{DateTime::Format::Strptime doesn't do durations.};
914             }
915              
916             {
917             my $validator = validation_for( params => [ { type => t('DateTime') } ] );
918              
919             sub format_datetime {
920 30     30 1 160262 my $self = shift;
921 30         1175 my ($dt) = $validator->(@_);
922              
923 29         568 my $pattern = $self->pattern;
924 29         115 $pattern =~ s/%O/$dt->time_zone->name/eg;
  2         15  
925 29         176 return $dt->clone->set_locale( $self->locale )->strftime($pattern);
926             }
927              
928             }
929              
930             sub format_duration {
931 0     0 0 0 croak q{DateTime::Format::Strptime doesn't do durations.};
932             }
933              
934             sub _our_croak {
935 97     97   508 my $self = shift;
936 97         164 my $error = shift;
937              
938 97 100       437 return $self->{on_error}->( $self, $error ) if ref $self->{on_error};
939 65 100       7284 croak $error if $self->{on_error} eq 'croak';
940 32         85 $self->{errmsg} = $error;
941 32         63 return;
942             }
943              
944             sub errmsg {
945 32     32 1 438 $_[0]->{errmsg};
946             }
947              
948             # Exportable functions:
949              
950             sub strftime {
951 1     1 1 1678 my ( $pattern, $dt ) = @_;
952 1         7 return DateTime::Format::Strptime->new(
953             pattern => $pattern,
954             on_error => 'croak'
955             )->format_datetime($dt);
956             }
957              
958             sub strptime {
959 1     1 1 681123 my ( $pattern, $time_string ) = @_;
960 1         11 return DateTime::Format::Strptime->new(
961             pattern => $pattern,
962             on_error => 'croak'
963             )->parse_datetime($time_string);
964             }
965              
966             1;
967              
968             # ABSTRACT: Parse and format strp and strf time patterns
969              
970             __END__
971              
972             =pod
973              
974             =encoding UTF-8
975              
976             =head1 NAME
977              
978             DateTime::Format::Strptime - Parse and format strp and strf time patterns
979              
980             =head1 VERSION
981              
982             version 1.80
983              
984             =head1 SYNOPSIS
985              
986             use DateTime::Format::Strptime;
987              
988             my $strp = DateTime::Format::Strptime->new(
989             pattern => '%T',
990             locale => 'en_AU',
991             time_zone => 'Australia/Melbourne',
992             );
993              
994             my $dt = $strp->parse_datetime('23:16:42');
995              
996             $strp->format_datetime($dt);
997              
998             # 23:16:42
999              
1000             # Croak when things go wrong:
1001             my $strp = DateTime::Format::Strptime->new(
1002             pattern => '%T',
1003             locale => 'en_AU',
1004             time_zone => 'Australia/Melbourne',
1005             on_error => 'croak',
1006             );
1007              
1008             # Do something else when things go wrong:
1009             my $strp = DateTime::Format::Strptime->new(
1010             pattern => '%T',
1011             locale => 'en_AU',
1012             time_zone => 'Australia/Melbourne',
1013             on_error => \&phone_police,
1014             );
1015              
1016             =head1 DESCRIPTION
1017              
1018             This module implements most of C<strptime(3)>, the POSIX function that is the
1019             reverse of C<strftime(3)>, for C<DateTime>. While C<strftime> takes a
1020             C<DateTime> and a pattern and returns a string, C<strptime> takes a string and
1021             a pattern and returns the C<DateTime> object associated.
1022              
1023             =for Pod::Coverage parse_duration format_duration
1024              
1025             =head1 METHODS
1026              
1027             This class offers the following methods.
1028              
1029             =head2 DateTime::Format::Strptime->new(%args)
1030              
1031             This methods creates a new object. It accepts the following arguments:
1032              
1033             =over 4
1034              
1035             =item * pattern
1036              
1037             This is the pattern to use for parsing. This is required.
1038              
1039             =item * strict
1040              
1041             This is a boolean which disables or enables strict matching mode.
1042              
1043             By default, this module turns your pattern into a regex that will match
1044             anywhere in a string. So given the pattern C<%Y%m%d%H%M%S> it will match a
1045             string like C<20161214233712>. However, this also means that a this pattern
1046             will match B<any> string that contains 14 or more numbers! This behavior can be
1047             very surprising.
1048              
1049             If you enable strict mode, then the generated regex is wrapped in boundary
1050             checks of the form C</(?:\A|\b)...(?:\b|\z_/)>. These checks ensure that the
1051             pattern will only match when at the beginning or end of a string, or when it is
1052             separated by other text with a word boundary (C<\w> versus C<\W>).
1053              
1054             By default, strict mode is off. This is done for backwards compatibility.
1055             Future releases may turn it on by default, as it produces less surprising
1056             behavior in many cases.
1057              
1058             Because the default may change in the future, B<< you are strongly encouraged
1059             to explicitly set this when constructing all C<DateTime::Format::Strptime>
1060             objects >>.
1061              
1062             =item * time_zone
1063              
1064             The default time zone to use for objects returned from parsing.
1065              
1066             =item * zone_map
1067              
1068             Some time zone abbreviations are ambiguous (e.g. PST, EST, EDT). By default,
1069             the parser will die when it parses an ambiguous abbreviation. You may specify a
1070             C<zone_map> parameter as a hashref to map zone abbreviations however you like:
1071              
1072             zone_map => { PST => '-0800', EST => '-0600' }
1073              
1074             Note that you can also override non-ambiguous mappings if you want to as well.
1075              
1076             =item * locale
1077              
1078             The locale to use for objects returned from parsing.
1079              
1080             =item * on_error
1081              
1082             This can be one of C<'undef'> (the string, not an C<undef>), 'croak', or a
1083             subroutine reference.
1084              
1085             =over 8
1086              
1087             =item * 'undef'
1088              
1089             This is the default behavior. The module will return C<undef> on errors. The
1090             error can be accessed using the C<< $object->errmsg >> method. This is the
1091             ideal behaviour for interactive use where a user might provide an illegal
1092             pattern or a date that doesn't match the pattern.
1093              
1094             =item * 'croak'
1095              
1096             The module will croak with an error message on errors.
1097              
1098             =item * sub{...} or \&subname
1099              
1100             When given a code ref, the module will call that sub on errors. The sub
1101             receives two parameters: the object and the error message.
1102              
1103             If your sub does not die, then the formatter will continue on as if C<on_error>
1104             was C<'undef'>.
1105              
1106             =back
1107              
1108             =back
1109              
1110             =head2 $strptime->parse_datetime($string)
1111              
1112             Given a string in the pattern specified in the constructor, this method will
1113             return a new C<DateTime> object.
1114              
1115             If given a string that doesn't match the pattern, the formatter will croak or
1116             return an empty list or C<undef>, depending on the setting of C<on_error> in
1117             the constructor.
1118              
1119             =head2 $strptime->format_datetime($datetime)
1120              
1121             Given a C<DateTime> object, this methods returns a string formatted in the
1122             object's format. This method is synonymous with C<DateTime>'s strftime method.
1123              
1124             =head2 $strptime->locale
1125              
1126             This method returns the locale passed to the object's constructor.
1127              
1128             =head2 $strptime->pattern
1129              
1130             This method returns the pattern passed to the object's constructor.
1131              
1132             =head2 $strptime->time_zone
1133              
1134             This method returns the time zone passed to the object's constructor.
1135              
1136             =head2 $strptime->errmsg
1137              
1138             If the on_error behavior of the object is 'undef', you can retrieve error
1139             messages with this method so you can work out why things went wrong.
1140              
1141             =head1 EXPORTS
1142              
1143             These subs are available as optional exports.
1144              
1145             =head2 strptime( $strptime_pattern, $string )
1146              
1147             Given a pattern and a string this function will return a new C<DateTime>
1148             object.
1149              
1150             =head2 strftime( $strftime_pattern, $datetime )
1151              
1152             Given a pattern and a C<DateTime> object this function will return a formatted
1153             string.
1154              
1155             =head1 STRPTIME PATTERN TOKENS
1156              
1157             The following tokens are allowed in the pattern string for strptime
1158             (parse_datetime):
1159              
1160             =over 4
1161              
1162             =item * %%
1163              
1164             The % character.
1165              
1166             =item * %a or %A
1167              
1168             The weekday name according to the given locale, in abbreviated form or the full
1169             name.
1170              
1171             =item * %b or %B or %h
1172              
1173             The month name according to the given locale, in abbreviated form or the full
1174             name.
1175              
1176             =item * %c
1177              
1178             The datetime format according to the given locale.
1179              
1180             Note that this format can change without warning in new versions of
1181             L<DateTime::Locale>. You should not use this pattern unless the string you are
1182             parsing was generated by using this pattern with L<DateTime> B<and> you are
1183             sure that this string was generated with the same version of
1184             L<DateTime::Locale> that the parser is using.
1185              
1186             =item * %C
1187              
1188             The century number (0-99).
1189              
1190             =item * %d or %e
1191              
1192             The day of month (01-31). This will parse single digit numbers as well.
1193              
1194             =item * %D
1195              
1196             Equivalent to %m/%d/%y. (This is the American style date, very confusing to
1197             non-Americans, especially since %d/%m/%y is widely used in Europe. The ISO 8601
1198             standard pattern is %F.)
1199              
1200             =item * %F
1201              
1202             Equivalent to %Y-%m-%d. (This is the ISO style date)
1203              
1204             =item * %g
1205              
1206             The year corresponding to the ISO week number, but without the century (0-99).
1207              
1208             =item * %G
1209              
1210             The 4-digit year corresponding to the ISO week number.
1211              
1212             =item * %H
1213              
1214             The hour (00-23). This will parse single digit numbers as well.
1215              
1216             =item * %I
1217              
1218             The hour on a 12-hour clock (1-12).
1219              
1220             =item * %j
1221              
1222             The day number in the year (1-366).
1223              
1224             =item * %m
1225              
1226             The month number (01-12). This will parse single digit numbers as well.
1227              
1228             =item * %M
1229              
1230             The minute (00-59). This will parse single digit numbers as well.
1231              
1232             =item * %n
1233              
1234             Arbitrary whitespace.
1235              
1236             =item * %N
1237              
1238             Nanoseconds. For other sub-second values use C<%[number]N>.
1239              
1240             =item * %p or %P
1241              
1242             The equivalent of AM or PM according to the locale in use. See
1243             L<DateTime::Locale>.
1244              
1245             =item * %r
1246              
1247             Equivalent to %I:%M:%S %p.
1248              
1249             =item * %R
1250              
1251             Equivalent to %H:%M.
1252              
1253             =item * %s
1254              
1255             Number of seconds since the Epoch.
1256              
1257             =item * %S
1258              
1259             The second (0-60; 60 may occur for leap seconds. See L<DateTime::LeapSecond>).
1260              
1261             =item * %t
1262              
1263             Arbitrary whitespace.
1264              
1265             =item * %T
1266              
1267             Equivalent to %H:%M:%S.
1268              
1269             =item * %U
1270              
1271             The week number with Sunday the first day of the week (0-53). The first Sunday
1272             of January is the first day of week 1.
1273              
1274             =item * %u
1275              
1276             The weekday number (1-7) with Monday = 1. This is the C<DateTime> standard.
1277              
1278             =item * %w
1279              
1280             The weekday number (0-6) with Sunday = 0.
1281              
1282             =item * %W
1283              
1284             The week number with Monday the first day of the week (0-53). The first Monday
1285             of January is the first day of week 1.
1286              
1287             =item * %x
1288              
1289             The date format according to the given locale.
1290              
1291             Note that this format can change without warning in new versions of
1292             L<DateTime::Locale>. You should not use this pattern unless the string you are
1293             parsing was generated by using this pattern with L<DateTime> B<and> you are
1294             sure that this string was generated with the same version of
1295             L<DateTime::Locale> that the parser is using.
1296              
1297             =item * %X
1298              
1299             The time format according to the given locale.
1300              
1301             Note that this format can change without warning in new versions of
1302             L<DateTime::Locale>. You should not use this pattern unless the string you are
1303             parsing was generated by using this pattern with L<DateTime> B<and> you are
1304             sure that this string was generated with the same version of
1305             L<DateTime::Locale> that the parser is using.
1306              
1307             =item * %y
1308              
1309             The year within century (0-99). When a century is not otherwise specified (with
1310             a value for %C), values in the range 69-99 refer to years in the twentieth
1311             century (1969-1999); values in the range 00-68 refer to years in the
1312             twenty-first century (2000-2068).
1313              
1314             =item * %Y
1315              
1316             A 4-digit year, including century (for example, 1991).
1317              
1318             =item * %z
1319              
1320             An RFC-822/ISO 8601 standard time zone specification. (For example +1100) [See
1321             note below]
1322              
1323             =item * %Z
1324              
1325             The timezone name. (For example EST -- which is ambiguous) [See note below]
1326              
1327             =item * %O
1328              
1329             This extended token allows the use of Olson Time Zone names to appear in parsed
1330             strings. B<NOTE>: This pattern cannot be passed to C<DateTime>'s C<strftime()>
1331             method, but can be passed to C<format_datetime()>.
1332              
1333             =back
1334              
1335             =head1 AUTHOR EMERITUS
1336              
1337             This module was created by Rick Measham.
1338              
1339             =head1 SEE ALSO
1340              
1341             C<datetime@perl.org> mailing list.
1342              
1343             L<perl>, L<DateTime>, L<DateTime::TimeZone>, L<DateTime::Locale>
1344              
1345             =head1 BUGS
1346              
1347             Please report any bugs or feature requests to
1348             C<bug-datetime-format-strptime@rt.cpan.org>, or through the web interface at
1349             L<http://rt.cpan.org>. I will be notified, and then you'll automatically be
1350             notified of progress on your bug as I make changes.
1351              
1352             Bugs may be submitted at L<https://github.com/houseabsolute/DateTime-Format-Strptime/issues>.
1353              
1354             There is a mailing list available for users of this distribution,
1355             L<mailto:datetime@perl.org>.
1356              
1357             =head1 SOURCE
1358              
1359             The source code repository for DateTime-Format-Strptime can be found at L<https://github.com/houseabsolute/DateTime-Format-Strptime>.
1360              
1361             =head1 DONATIONS
1362              
1363             If you'd like to thank me for the work I've done on this module, please
1364             consider making a "donation" to me via PayPal. I spend a lot of free time
1365             creating free software, and would appreciate any support you'd care to offer.
1366              
1367             Please note that B<I am not suggesting that you must do this> in order for me
1368             to continue working on this particular software. I will continue to do so,
1369             inasmuch as I have in the past, for as long as it interests me.
1370              
1371             Similarly, a donation made in this way will probably not make me work on this
1372             software much more, unless I get so many donations that I can consider working
1373             on free software full time (let's all have a chuckle at that together).
1374              
1375             To donate, log into PayPal and send money to autarch@urth.org, or use the
1376             button at L<https://houseabsolute.com/foss-donations/>.
1377              
1378             =head1 AUTHORS
1379              
1380             =over 4
1381              
1382             =item *
1383              
1384             Dave Rolsky <autarch@urth.org>
1385              
1386             =item *
1387              
1388             Rick Measham <rickm@cpan.org>
1389              
1390             =back
1391              
1392             =head1 CONTRIBUTORS
1393              
1394             =for stopwords Christian Hansen D. Ilmari Mannsåker gregor herrmann key-amb Mohammad S Anwar
1395              
1396             =over 4
1397              
1398             =item *
1399              
1400             Christian Hansen <chansen@cpan.org>
1401              
1402             =item *
1403              
1404             D. Ilmari Mannsåker <ilmari.mannsaker@net-a-porter.com>
1405              
1406             =item *
1407              
1408             gregor herrmann <gregoa@debian.org>
1409              
1410             =item *
1411              
1412             key-amb <yasutake.kiyoshi@gmail.com>
1413              
1414             =item *
1415              
1416             Mohammad S Anwar <mohammad.anwar@yahoo.com>
1417              
1418             =back
1419              
1420             =head1 COPYRIGHT AND LICENSE
1421              
1422             This software is Copyright (c) 2015 - 2025 by Dave Rolsky.
1423              
1424             This is free software, licensed under:
1425              
1426             The Artistic License 2.0 (GPL Compatible)
1427              
1428             The full text of the license can be found in the
1429             F<LICENSE> file included with this distribution.
1430              
1431             =cut