Filename | /usr/share/perl5/DateTime/Format/Strptime.pm |
Statements | Executed 26 statements in 4.66ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 11µs | 21µs | BEGIN@5 | DateTime::Format::Strptime::
1 | 1 | 1 | 11µs | 17µs | BEGIN@9 | DateTime::Format::Strptime::
1 | 1 | 1 | 10µs | 54µs | BEGIN@10 | DateTime::Format::Strptime::
1 | 1 | 1 | 10µs | 16µs | BEGIN@8 | DateTime::Format::Strptime::
1 | 1 | 1 | 10µs | 18µs | BEGIN@7 | DateTime::Format::Strptime::
1 | 1 | 1 | 8µs | 22µs | BEGIN@13 | DateTime::Format::Strptime::
1 | 1 | 1 | 7µs | 32µs | BEGIN@11 | DateTime::Format::Strptime::
1 | 1 | 1 | 6µs | 66µs | BEGIN@14 | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | _build_parser | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | errmsg | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | format_datetime | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | format_duration | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | local_carp | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | local_croak | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | locale | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | new | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | parse_datetime | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | parse_duration | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | pattern | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | strftime | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | strptime | DateTime::Format::Strptime::
0 | 0 | 0 | 0s | 0s | time_zone | DateTime::Format::Strptime::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package DateTime::Format::Strptime; | ||||
2 | # git description: v1.54-8-g6aa82d9 | ||||
3 | 1 | 500ns | $DateTime::Format::Strptime::VERSION = '1.56'; | ||
4 | |||||
5 | 2 | 24µs | 2 | 31µs | # spent 21µs (11+10) within DateTime::Format::Strptime::BEGIN@5 which was called:
# once (11µs+10µs) by DateTime::Format::Builder::Parser::Strptime::BEGIN@10 at line 5 # spent 21µs making 1 call to DateTime::Format::Strptime::BEGIN@5
# spent 10µs making 1 call to strict::import |
6 | |||||
7 | 3 | 36µs | 2 | 26µs | # spent 18µs (10+8) within DateTime::Format::Strptime::BEGIN@7 which was called:
# once (10µs+8µs) by DateTime::Format::Builder::Parser::Strptime::BEGIN@10 at line 7 # spent 18µs making 1 call to DateTime::Format::Strptime::BEGIN@7
# spent 8µs making 1 call to version::_VERSION |
8 | 3 | 36µs | 2 | 23µs | # spent 16µs (10+7) within DateTime::Format::Strptime::BEGIN@8 which was called:
# once (10µs+7µs) by DateTime::Format::Builder::Parser::Strptime::BEGIN@10 at line 8 # spent 16µs making 1 call to DateTime::Format::Strptime::BEGIN@8
# spent 6µs making 1 call to version::_VERSION |
9 | 3 | 39µs | 2 | 23µs | # spent 17µs (11+6) within DateTime::Format::Strptime::BEGIN@9 which was called:
# once (11µs+6µs) by DateTime::Format::Builder::Parser::Strptime::BEGIN@10 at line 9 # spent 17µs making 1 call to DateTime::Format::Strptime::BEGIN@9
# spent 6µs making 1 call to version::_VERSION |
10 | 3 | 32µs | 3 | 98µs | # spent 54µs (10+44) within DateTime::Format::Strptime::BEGIN@10 which was called:
# once (10µs+44µs) by DateTime::Format::Builder::Parser::Strptime::BEGIN@10 at line 10 # spent 54µs making 1 call to DateTime::Format::Strptime::BEGIN@10
# spent 38µs making 1 call to Exporter::import
# spent 6µs making 1 call to version::_VERSION |
11 | 2 | 21µs | 2 | 57µs | # spent 32µs (7+25) within DateTime::Format::Strptime::BEGIN@11 which was called:
# once (7µs+25µs) by DateTime::Format::Builder::Parser::Strptime::BEGIN@10 at line 11 # spent 32µs making 1 call to DateTime::Format::Strptime::BEGIN@11
# spent 25µs making 1 call to Exporter::import |
12 | |||||
13 | 2 | 24µs | 2 | 37µs | # spent 22µs (8+15) within DateTime::Format::Strptime::BEGIN@13 which was called:
# once (8µs+15µs) by DateTime::Format::Builder::Parser::Strptime::BEGIN@10 at line 13 # spent 22µs making 1 call to DateTime::Format::Strptime::BEGIN@13
# spent 15µs making 1 call to Exporter::import |
14 | 2 | 4.30ms | 2 | 126µs | # spent 66µs (6+60) within DateTime::Format::Strptime::BEGIN@14 which was called:
# once (6µs+60µs) by DateTime::Format::Builder::Parser::Strptime::BEGIN@10 at line 14 # spent 66µs making 1 call to DateTime::Format::Strptime::BEGIN@14
# spent 60µs making 1 call to vars::import |
15 | |||||
16 | 1 | 7µs | @ISA = 'Exporter'; | ||
17 | 1 | 400ns | @EXPORT_OK = qw( &strftime &strptime ); | ||
18 | 1 | 200ns | @EXPORT = (); | ||
19 | |||||
20 | 1 | 114µs | %ZONEMAP = ( | ||
21 | 'A' => '+0100', 'ACDT' => '+1030', 'ACST' => '+0930', | ||||
22 | 'ADT' => 'Ambiguous', 'AEDT' => '+1100', 'AES' => '+1000', | ||||
23 | 'AEST' => '+1000', 'AFT' => '+0430', 'AHDT' => '-0900', | ||||
24 | 'AHST' => '-1000', 'AKDT' => '-0800', 'AKST' => '-0900', | ||||
25 | 'AMST' => '+0400', 'AMT' => '+0400', 'ANAST' => '+1300', | ||||
26 | 'ANAT' => '+1200', 'ART' => '-0300', 'AST' => 'Ambiguous', | ||||
27 | 'AT' => '-0100', 'AWST' => '+0800', 'AZOST' => '+0000', | ||||
28 | 'AZOT' => '-0100', 'AZST' => '+0500', 'AZT' => '+0400', | ||||
29 | 'B' => '+0200', 'BADT' => '+0400', 'BAT' => '+0600', | ||||
30 | 'BDST' => '+0200', 'BDT' => '+0600', 'BET' => '-1100', | ||||
31 | 'BNT' => '+0800', 'BORT' => '+0800', 'BOT' => '-0400', | ||||
32 | 'BRA' => '-0300', 'BST' => 'Ambiguous', 'BT' => 'Ambiguous', | ||||
33 | 'BTT' => '+0600', 'C' => '+0300', 'CAST' => '+0930', | ||||
34 | 'CAT' => 'Ambiguous', 'CCT' => 'Ambiguous', 'CDT' => 'Ambiguous', | ||||
35 | 'CEST' => '+0200', 'CET' => '+0100', 'CETDST' => '+0200', | ||||
36 | 'CHADT' => '+1345', 'CHAST' => '+1245', 'CKT' => '-1000', | ||||
37 | 'CLST' => '-0300', 'CLT' => '-0400', 'COT' => '-0500', | ||||
38 | 'CST' => 'Ambiguous', 'CSuT' => '+1030', 'CUT' => '+0000', | ||||
39 | 'CVT' => '-0100', 'CXT' => '+0700', 'ChST' => '+1000', | ||||
40 | 'D' => '+0400', 'DAVT' => '+0700', 'DDUT' => '+1000', | ||||
41 | 'DNT' => '+0100', 'DST' => '+0200', 'E' => '+0500', | ||||
42 | 'EASST' => '-0500', 'EAST' => 'Ambiguous', 'EAT' => '+0300', | ||||
43 | 'ECT' => 'Ambiguous', 'EDT' => 'Ambiguous', 'EEST' => '+0300', | ||||
44 | 'EET' => '+0200', 'EETDST' => '+0300', 'EGST' => '+0000', | ||||
45 | 'EGT' => '-0100', 'EMT' => '+0100', 'EST' => 'Ambiguous', | ||||
46 | 'ESuT' => '+1100', 'F' => '+0600', 'FDT' => 'Ambiguous', | ||||
47 | 'FJST' => '+1300', 'FJT' => '+1200', 'FKST' => '-0300', | ||||
48 | 'FKT' => '-0400', 'FST' => 'Ambiguous', 'FWT' => '+0100', | ||||
49 | 'G' => '+0700', 'GALT' => '-0600', 'GAMT' => '-0900', | ||||
50 | 'GEST' => '+0500', 'GET' => '+0400', 'GFT' => '-0300', | ||||
51 | 'GILT' => '+1200', 'GMT' => '+0000', 'GST' => 'Ambiguous', | ||||
52 | 'GT' => '+0000', 'GYT' => '-0400', 'GZ' => '+0000', | ||||
53 | 'H' => '+0800', 'HAA' => '-0300', 'HAC' => '-0500', | ||||
54 | 'HAE' => '-0400', 'HAP' => '-0700', 'HAR' => '-0600', | ||||
55 | 'HAT' => '-0230', 'HAY' => '-0800', 'HDT' => '-0930', | ||||
56 | 'HFE' => '+0200', 'HFH' => '+0100', 'HG' => '+0000', | ||||
57 | 'HKT' => '+0800', 'HL' => 'local', 'HNA' => '-0400', | ||||
58 | 'HNC' => '-0600', 'HNE' => '-0500', 'HNP' => '-0800', | ||||
59 | 'HNR' => '-0700', 'HNT' => '-0330', 'HNY' => '-0900', | ||||
60 | 'HOE' => '+0100', 'HST' => '-1000', 'I' => '+0900', | ||||
61 | 'ICT' => '+0700', 'IDLE' => '+1200', 'IDLW' => '-1200', | ||||
62 | 'IDT' => 'Ambiguous', 'IOT' => '+0500', 'IRDT' => '+0430', | ||||
63 | 'IRKST' => '+0900', 'IRKT' => '+0800', 'IRST' => '+0430', | ||||
64 | 'IRT' => '+0330', 'IST' => 'Ambiguous', 'IT' => '+0330', | ||||
65 | 'ITA' => '+0100', 'JAVT' => '+0700', 'JAYT' => '+0900', | ||||
66 | 'JST' => '+0900', 'JT' => '+0700', 'K' => '+1000', | ||||
67 | 'KDT' => '+1000', 'KGST' => '+0600', 'KGT' => '+0500', | ||||
68 | 'KOST' => '+1200', 'KRAST' => '+0800', 'KRAT' => '+0700', | ||||
69 | 'KST' => '+0900', 'L' => '+1100', 'LHDT' => '+1100', | ||||
70 | 'LHST' => '+1030', 'LIGT' => '+1000', 'LINT' => '+1400', | ||||
71 | 'LKT' => '+0600', 'LST' => 'local', 'LT' => 'local', | ||||
72 | 'M' => '+1200', 'MAGST' => '+1200', 'MAGT' => '+1100', | ||||
73 | 'MAL' => '+0800', 'MART' => '-0930', 'MAT' => '+0300', | ||||
74 | 'MAWT' => '+0600', 'MDT' => '-0600', 'MED' => '+0200', | ||||
75 | 'MEDST' => '+0200', 'MEST' => '+0200', 'MESZ' => '+0200', | ||||
76 | 'MET' => 'Ambiguous', 'MEWT' => '+0100', 'MEX' => '-0600', | ||||
77 | 'MEZ' => '+0100', 'MHT' => '+1200', 'MMT' => '+0630', | ||||
78 | 'MPT' => '+1000', 'MSD' => '+0400', 'MSK' => '+0300', | ||||
79 | 'MSKS' => '+0400', 'MST' => '-0700', 'MT' => '+0830', | ||||
80 | 'MUT' => '+0400', 'MVT' => '+0500', 'MYT' => '+0800', | ||||
81 | 'N' => '-0100', 'NCT' => '+1100', 'NDT' => '-0230', | ||||
82 | 'NFT' => 'Ambiguous', 'NOR' => '+0100', 'NOVST' => '+0700', | ||||
83 | 'NOVT' => '+0600', 'NPT' => '+0545', 'NRT' => '+1200', | ||||
84 | 'NST' => 'Ambiguous', 'NSUT' => '+0630', 'NT' => '-1100', | ||||
85 | 'NUT' => '-1100', 'NZDT' => '+1300', 'NZST' => '+1200', | ||||
86 | 'NZT' => '+1200', 'O' => '-0200', 'OESZ' => '+0300', | ||||
87 | 'OEZ' => '+0200', 'OMSST' => '+0700', 'OMST' => '+0600', | ||||
88 | 'OZ' => 'local', 'P' => '-0300', 'PDT' => '-0700', | ||||
89 | 'PET' => '-0500', 'PETST' => '+1300', 'PETT' => '+1200', | ||||
90 | 'PGT' => '+1000', 'PHOT' => '+1300', 'PHT' => '+0800', | ||||
91 | 'PKT' => '+0500', 'PMDT' => '-0200', 'PMT' => '-0300', | ||||
92 | 'PNT' => '-0830', 'PONT' => '+1100', 'PST' => 'Ambiguous', | ||||
93 | 'PWT' => '+0900', 'PYST' => '-0300', 'PYT' => '-0400', | ||||
94 | 'Q' => '-0400', 'R' => '-0500', 'R1T' => '+0200', | ||||
95 | 'R2T' => '+0300', 'RET' => '+0400', 'ROK' => '+0900', | ||||
96 | 'S' => '-0600', 'SADT' => '+1030', 'SAST' => 'Ambiguous', | ||||
97 | 'SBT' => '+1100', 'SCT' => '+0400', 'SET' => '+0100', | ||||
98 | 'SGT' => '+0800', 'SRT' => '-0300', 'SST' => 'Ambiguous', | ||||
99 | 'SWT' => '+0100', 'T' => '-0700', 'TFT' => '+0500', | ||||
100 | 'THA' => '+0700', 'THAT' => '-1000', 'TJT' => '+0500', | ||||
101 | 'TKT' => '-1000', 'TMT' => '+0500', 'TOT' => '+1300', | ||||
102 | 'TRUT' => '+1000', 'TST' => '+0300', 'TUC ' => '+0000', | ||||
103 | 'TVT' => '+1200', 'U' => '-0800', 'ULAST' => '+0900', | ||||
104 | 'ULAT' => '+0800', 'USZ1' => '+0200', 'USZ1S' => '+0300', | ||||
105 | 'USZ3' => '+0400', 'USZ3S' => '+0500', 'USZ4' => '+0500', | ||||
106 | 'USZ4S' => '+0600', 'USZ5' => '+0600', 'USZ5S' => '+0700', | ||||
107 | 'USZ6' => '+0700', 'USZ6S' => '+0800', 'USZ7' => '+0800', | ||||
108 | 'USZ7S' => '+0900', 'USZ8' => '+0900', 'USZ8S' => '+1000', | ||||
109 | 'USZ9' => '+1000', 'USZ9S' => '+1100', 'UTZ' => '-0300', | ||||
110 | 'UYT' => '-0300', 'UZ10' => '+1100', 'UZ10S' => '+1200', | ||||
111 | 'UZ11' => '+1200', 'UZ11S' => '+1300', 'UZ12' => '+1200', | ||||
112 | 'UZ12S' => '+1300', 'UZT' => '+0500', 'V' => '-0900', | ||||
113 | 'VET' => '-0400', 'VLAST' => '+1100', 'VLAT' => '+1000', | ||||
114 | 'VTZ' => '-0200', 'VUT' => '+1100', 'W' => '-1000', | ||||
115 | 'WAKT' => '+1200', 'WAST' => 'Ambiguous', 'WAT' => '+0100', | ||||
116 | 'WEST' => '+0100', 'WESZ' => '+0100', 'WET' => '+0000', | ||||
117 | 'WETDST' => '+0100', 'WEZ' => '+0000', 'WFT' => '+1200', | ||||
118 | 'WGST' => '-0200', 'WGT' => '-0300', 'WIB' => '+0700', | ||||
119 | 'WIT' => '+0900', 'WITA' => '+0800', 'WST' => 'Ambiguous', | ||||
120 | 'WTZ' => '-0100', 'WUT' => '+0100', 'X' => '-1100', | ||||
121 | 'Y' => '-1200', 'YAKST' => '+1000', 'YAKT' => '+0900', | ||||
122 | 'YAPT' => '+1000', 'YDT' => '-0800', 'YEKST' => '+0600', | ||||
123 | 'YEKT' => '+0500', 'YST' => '-0900', 'Z' => '+0000', | ||||
124 | 'UTC' => '+0000', | ||||
125 | ); | ||||
126 | |||||
127 | sub new { | ||||
128 | my $class = shift; | ||||
129 | my %args = validate( | ||||
130 | @_, { | ||||
131 | pattern => { type => SCALAR | SCALARREF }, | ||||
132 | time_zone => { type => SCALAR | OBJECT, optional => 1 }, | ||||
133 | locale => { type => SCALAR | OBJECT, default => 'English' }, | ||||
134 | on_error => { type => SCALAR | CODEREF, default => 'undef' }, | ||||
135 | diagnostic => { type => SCALAR, default => 0 }, | ||||
136 | } | ||||
137 | ); | ||||
138 | |||||
139 | croak( | ||||
140 | "The value supplied to on_error must be either 'croak', 'undef' or a code reference." | ||||
141 | ) | ||||
142 | unless ref( $args{on_error} ) eq 'CODE' | ||||
143 | or $args{on_error} eq 'croak' | ||||
144 | or $args{on_error} eq 'undef'; | ||||
145 | |||||
146 | # Deal with locale | ||||
147 | unless ( ref( $args{locale} ) ) { | ||||
148 | my $locale = DateTime::Locale->load( $args{locale} ); | ||||
149 | |||||
150 | croak("Could not create locale from $args{locale}") unless $locale; | ||||
151 | |||||
152 | $args{_locale} = $locale; | ||||
153 | } | ||||
154 | else { | ||||
155 | $args{_locale} = $args{locale}; | ||||
156 | ( $args{locale} ) = ref( $args{_locale} ) =~ /::(\w+)[^:]+$/; | ||||
157 | } | ||||
158 | |||||
159 | if ( $args{time_zone} ) { | ||||
160 | unless ( ref( $args{time_zone} ) ) { | ||||
161 | $args{time_zone} | ||||
162 | = DateTime::TimeZone->new( name => $args{time_zone} ); | ||||
163 | |||||
164 | croak("Could not create time zone from $args{time_zone}") | ||||
165 | unless $args{time_zone}; | ||||
166 | } | ||||
167 | $args{set_time_zone} = $args{time_zone}; | ||||
168 | } | ||||
169 | else { | ||||
170 | $args{time_zone} = DateTime::TimeZone->new( name => 'floating' ); | ||||
171 | $args{set_time_zone} = ''; | ||||
172 | } | ||||
173 | |||||
174 | my $self = bless \%args, $class; | ||||
175 | |||||
176 | # Deal with the parser | ||||
177 | $self->{parser} = $self->_build_parser( $args{pattern} ); | ||||
178 | if ( $self->{parser} =~ /(%\{\w+\}|%\w)/ and $args{pattern} !~ /\%$1/ ) { | ||||
179 | croak("Unidentified token in pattern: $1 in $self->{pattern}"); | ||||
180 | } | ||||
181 | |||||
182 | return $self; | ||||
183 | } | ||||
184 | |||||
185 | sub pattern { | ||||
186 | my $self = shift; | ||||
187 | my $pattern = shift; | ||||
188 | |||||
189 | if ($pattern) { | ||||
190 | my $possible_parser = $self->_build_parser($pattern); | ||||
191 | if ( $possible_parser =~ /(%\{\w+\}|%\w)/ and $pattern !~ /\%$1/ ) { | ||||
192 | $self->local_carp( | ||||
193 | "Unidentified token in pattern: $1 in $pattern. Leaving old pattern intact." | ||||
194 | ) and return undef; | ||||
195 | } | ||||
196 | else { | ||||
197 | $self->{parser} = $possible_parser; | ||||
198 | $self->{pattern} = $pattern; | ||||
199 | } | ||||
200 | } | ||||
201 | return $self->{pattern}; | ||||
202 | } | ||||
203 | |||||
204 | sub locale { | ||||
205 | my $self = shift; | ||||
206 | my $locale = shift; | ||||
207 | |||||
208 | if ($locale) { | ||||
209 | my $possible_locale = DateTime::Locale->load($locale); | ||||
210 | unless ($possible_locale) { | ||||
211 | $self->local_carp( | ||||
212 | "Could not create locale from $locale. Leaving old locale intact." | ||||
213 | ) and return undef; | ||||
214 | } | ||||
215 | else { | ||||
216 | $self->{locale} = $locale; | ||||
217 | $self->{_locale} = $possible_locale; | ||||
218 | |||||
219 | # When the locale changes we need to rebuild the parser | ||||
220 | $self->{parser} = $self->_build_parser( $self->{pattern} ); | ||||
221 | } | ||||
222 | } | ||||
223 | return $self->{locale}; | ||||
224 | } | ||||
225 | |||||
226 | sub time_zone { | ||||
227 | my $self = shift; | ||||
228 | my $time_zone = shift; | ||||
229 | |||||
230 | if ($time_zone) { | ||||
231 | my $possible_time_zone | ||||
232 | = DateTime::TimeZone->new( name => $time_zone ); | ||||
233 | unless ($possible_time_zone) { | ||||
234 | $self->local_carp( | ||||
235 | "Could not create time zone from $time_zone. Leaving old time zone intact." | ||||
236 | ) and return undef; | ||||
237 | } | ||||
238 | else { | ||||
239 | $self->{time_zone} = $possible_time_zone; | ||||
240 | $self->{set_time_zone} = $self->{time_zone}; | ||||
241 | } | ||||
242 | } | ||||
243 | return $self->{time_zone}->name; | ||||
244 | } | ||||
245 | |||||
246 | sub parse_datetime { | ||||
247 | my ( $self, $time_string ) = @_; | ||||
248 | |||||
249 | local $^W = undef; | ||||
250 | |||||
251 | # Variables from the parser | ||||
252 | my ( | ||||
253 | $dow_name, $month_name, $century, $day, | ||||
254 | $hour_24, $hour_12, $doy, $month, | ||||
255 | $minute, $ampm, $second, $week_sun_0, | ||||
256 | $dow_sun_0, $dow_mon_1, $week_mon_1, $year_100, | ||||
257 | $year, $iso_week_year_100, $iso_week_year, | ||||
258 | $epoch, $tz_offset, $timezone, $tz_olson, | ||||
259 | $nanosecond, $ce_year, | ||||
260 | |||||
261 | $doy_dt, $epoch_dt, $use_timezone, $set_time_zone, | ||||
262 | ); | ||||
263 | |||||
264 | # Variables for DateTime | ||||
265 | my ( | ||||
266 | $Year, $Month, $Day, | ||||
267 | $Hour, $Minute, $Second, $Nanosecond, | ||||
268 | $Am, $Pm | ||||
269 | ) = (); | ||||
270 | |||||
271 | # Run the parser | ||||
272 | my $parser = $self->{parser}; | ||||
273 | eval($parser); | ||||
274 | die $@ if $@; | ||||
275 | |||||
276 | if ( $self->{diagnostic} ) { | ||||
277 | print qq| | ||||
278 | |||||
279 | Entered = $time_string | ||||
280 | Parser = $parser | ||||
281 | |||||
282 | dow_name = $dow_name | ||||
283 | month_name = $month_name | ||||
284 | century = $century | ||||
285 | day = $day | ||||
286 | hour_24 = $hour_24 | ||||
287 | hour_12 = $hour_12 | ||||
288 | doy = $doy | ||||
289 | month = $month | ||||
290 | minute = $minute | ||||
291 | ampm = $ampm | ||||
292 | second = $second | ||||
293 | nanosecond = $nanosecond | ||||
294 | week_sun_0 = $week_sun_0 | ||||
295 | dow_sun_0 = $dow_sun_0 | ||||
296 | dow_mon_1 = $dow_mon_1 | ||||
297 | week_mon_1 = $week_mon_1 | ||||
298 | year_100 = $year_100 | ||||
299 | year = $year | ||||
300 | ce_year = $ce_year | ||||
301 | tz_offset = $tz_offset | ||||
302 | tz_olson = $tz_olson | ||||
303 | timezone = $timezone | ||||
304 | epoch = $epoch | ||||
305 | iso_week_year = $iso_week_year | ||||
306 | iso_week_year_100 = $iso_week_year_100 | ||||
307 | |||||
308 | |; | ||||
309 | |||||
310 | } | ||||
311 | |||||
312 | $self->local_croak("Your datetime does not match your pattern.") | ||||
313 | and return undef | ||||
314 | if ( ( $self->{parser} =~ /\$dow_name\b/ and $dow_name eq '' ) | ||||
315 | or ( $self->{parser} =~ /\$month_name\b/ and $month_name eq '' ) | ||||
316 | or ( $self->{parser} =~ /\$century\b/ and $century eq '' ) | ||||
317 | or ( $self->{parser} =~ /\$day\b/ and $day eq '' ) | ||||
318 | or ( $self->{parser} =~ /\$hour_24\b/ and $hour_24 eq '' ) | ||||
319 | or ( $self->{parser} =~ /\$hour_12\b/ and $hour_12 eq '' ) | ||||
320 | or ( $self->{parser} =~ /\$doy\b/ and $doy eq '' ) | ||||
321 | or ( $self->{parser} =~ /\$month\b/ and $month eq '' ) | ||||
322 | or ( $self->{parser} =~ /\$minute\b/ and $minute eq '' ) | ||||
323 | or ( $self->{parser} =~ /\$ampm\b/ and $ampm eq '' ) | ||||
324 | or ( $self->{parser} =~ /\$second\b/ and $second eq '' ) | ||||
325 | or ( $self->{parser} =~ /\$nanosecond\b/ and $nanosecond eq '' ) | ||||
326 | or ( $self->{parser} =~ /\$week_sun_0\b/ and $week_sun_0 eq '' ) | ||||
327 | or ( $self->{parser} =~ /\$dow_sun_0\b/ and $dow_sun_0 eq '' ) | ||||
328 | or ( $self->{parser} =~ /\$dow_mon_1\b/ and $dow_mon_1 eq '' ) | ||||
329 | or ( $self->{parser} =~ /\$week_mon_1\b/ and $week_mon_1 eq '' ) | ||||
330 | or ( $self->{parser} =~ /\$year_100\b/ and $year_100 eq '' ) | ||||
331 | or ( $self->{parser} =~ /\$year\b/ and $year eq '' ) | ||||
332 | or ( $self->{parser} =~ /\$ce_year\b/ and $ce_year eq '' ) | ||||
333 | or ( $self->{parser} =~ /\$tz_offset\b/ and $tz_offset eq '' ) | ||||
334 | or ( $self->{parser} =~ /\$tz_olson\b/ and $tz_olson eq '' ) | ||||
335 | or ( $self->{parser} =~ /\$timezone\b/ and $timezone eq '' ) | ||||
336 | or ( $self->{parser} =~ /\$epoch\b/ and $epoch eq '' ) ); | ||||
337 | |||||
338 | # Create a timezone to work with | ||||
339 | if ($tz_offset) { | ||||
340 | $use_timezone = $tz_offset; | ||||
341 | } | ||||
342 | |||||
343 | if ($timezone) { | ||||
344 | $self->local_croak("I don't recognise the timezone $timezone.") | ||||
345 | and return undef | ||||
346 | unless $ZONEMAP{$timezone}; | ||||
347 | $self->local_croak("The timezone '$timezone' is ambiguous.") | ||||
348 | and return undef | ||||
349 | if $ZONEMAP{$timezone} eq 'Ambiguous' | ||||
350 | and not( $tz_offset or $tz_olson ); | ||||
351 | $self->local_croak( | ||||
352 | "Your timezones ('$tz_offset' and '$timezone') do not match.") | ||||
353 | and return undef | ||||
354 | if $tz_offset | ||||
355 | and $ZONEMAP{$timezone} ne 'Ambiguous' | ||||
356 | and $ZONEMAP{$timezone} != $tz_offset; | ||||
357 | $use_timezone = $ZONEMAP{$timezone} | ||||
358 | if $ZONEMAP{$timezone} ne 'Ambiguous'; | ||||
359 | } | ||||
360 | |||||
361 | if ($tz_olson) { | ||||
362 | my $tz = eval { DateTime::TimeZone->new( name => $tz_olson ) }; | ||||
363 | if ( not $tz ) { | ||||
364 | |||||
365 | "Provided olson TZ didn't work ($tz_olson). Attempting to normalize it.\n" | ||||
366 | if $self->{diagnostic}; | ||||
367 | $tz_olson = ucfirst lc $tz_olson; | ||||
368 | $tz_olson =~ s|([/_])(\w)|$1\U$2|g; | ||||
369 | print " Trying $tz_olson.\n" if $self->{diagnostic}; | ||||
370 | $tz = eval { DateTime::TimeZone->new( name => $tz_olson ) }; | ||||
371 | } | ||||
372 | $self->local_croak("I don't recognise the time zone '$tz_olson'.") | ||||
373 | and return undef | ||||
374 | unless $tz; | ||||
375 | $use_timezone = $set_time_zone = $tz; | ||||
376 | |||||
377 | } | ||||
378 | |||||
379 | $use_timezone = $self->{time_zone} unless ($use_timezone); | ||||
380 | |||||
381 | print "Using timezone $use_timezone.\n" if $self->{diagnostic}; | ||||
382 | |||||
383 | # If there's an epoch, we're done. Just need to check all the others | ||||
384 | if ($epoch) { | ||||
385 | $epoch_dt = DateTime->from_epoch( | ||||
386 | epoch => $epoch, | ||||
387 | time_zone => $use_timezone | ||||
388 | ); | ||||
389 | |||||
390 | $Year = $epoch_dt->year; | ||||
391 | $Month = $epoch_dt->month; | ||||
392 | $Day = $epoch_dt->day; | ||||
393 | |||||
394 | $Hour = $epoch_dt->hour; | ||||
395 | $Minute = $epoch_dt->minute; | ||||
396 | $Second = $epoch_dt->second; | ||||
397 | $Nanosecond = $epoch_dt->nanosecond; | ||||
398 | |||||
399 | print $epoch_dt->strftime("Epoch: %D %T.%N\n") if $self->{diagnostic}; | ||||
400 | } | ||||
401 | |||||
402 | # Work out the year we're working with: | ||||
403 | if ($year_100) { | ||||
404 | if ($century) { | ||||
405 | $Year = ( ( $century * 100 ) - 0 ) + $year_100; | ||||
406 | } | ||||
407 | else { | ||||
408 | print "No century, guessing for $year_100" if $self->{diagnostic}; | ||||
409 | if ( $year_100 >= 69 and $year_100 <= 99 ) { | ||||
410 | print "Guessed 1900s" if $self->{diagnostic}; | ||||
411 | $Year = 1900 + $year_100; | ||||
412 | } | ||||
413 | else { | ||||
414 | print "Guessed 2000s" if $self->{diagnostic}; | ||||
415 | $Year = 2000 + $year_100; | ||||
416 | } | ||||
417 | } | ||||
418 | } | ||||
419 | if ($year) { | ||||
420 | $self->local_croak( | ||||
421 | "Your two year values ($year_100 and $year) do not match.") | ||||
422 | and return undef | ||||
423 | if ( $Year && ( $year != $Year ) ); | ||||
424 | $Year = $year; | ||||
425 | } | ||||
426 | if ($ce_year) { | ||||
427 | $self->local_croak( | ||||
428 | "Your two year values ($ce_year and $year) do not match.") | ||||
429 | and return undef | ||||
430 | if ( $Year && ( $ce_year != $Year ) ); | ||||
431 | $Year = $ce_year; | ||||
432 | } | ||||
433 | $self->local_croak("Your year value does not match your epoch.") | ||||
434 | and return undef | ||||
435 | if $epoch_dt | ||||
436 | and $Year | ||||
437 | and $Year != $epoch_dt->year; | ||||
438 | |||||
439 | # Work out which month we want | ||||
440 | # Month names | ||||
441 | if ($month_name) { | ||||
442 | $self->local_croak( | ||||
443 | "There is no use providing a month name ($month_name) without providing a year." | ||||
444 | ) | ||||
445 | and return undef | ||||
446 | unless $Year; | ||||
447 | my $month_count = 0; | ||||
448 | my $month_number = 0; | ||||
449 | foreach my $month ( @{ $self->{_locale}->month_format_wide } ) { | ||||
450 | $month_count++; | ||||
451 | |||||
452 | if ( lc $month eq lc $month_name ) { | ||||
453 | $month_number = $month_count; | ||||
454 | last; | ||||
455 | } | ||||
456 | } | ||||
457 | unless ($month_number) { | ||||
458 | my $month_count = 0; | ||||
459 | foreach | ||||
460 | my $month ( @{ $self->{_locale}->month_format_abbreviated } ) | ||||
461 | { | ||||
462 | $month_count++; | ||||
463 | |||||
464 | # When abbreviating, sometimes there's a period, sometimes not. | ||||
465 | $month =~ s/\.$//; | ||||
466 | $month_name =~ s/\.$//; | ||||
467 | if ( lc $month eq lc $month_name ) { | ||||
468 | $month_number = $month_count; | ||||
469 | last; | ||||
470 | } | ||||
471 | } | ||||
472 | } | ||||
473 | unless ($month_number) { | ||||
474 | $self->local_croak( | ||||
475 | "$month_name is not a recognised month in this locale.") | ||||
476 | and return undef; | ||||
477 | } | ||||
478 | $Month = $month_number; | ||||
479 | } | ||||
480 | if ($month) { | ||||
481 | $self->local_croak( | ||||
482 | "There is no use providing a month without providing a year.") | ||||
483 | and return undef | ||||
484 | unless $Year; | ||||
485 | $self->local_croak("$month is too large to be a month of the year.") | ||||
486 | and return undef | ||||
487 | unless $month <= 12; | ||||
488 | $self->local_croak( | ||||
489 | "Your two month values ($month_name and $month) do not match.") | ||||
490 | and return undef | ||||
491 | if $Month | ||||
492 | and $month != $Month; | ||||
493 | $Month = $month; | ||||
494 | } | ||||
495 | $self->local_croak("Your month value does not match your epoch.") | ||||
496 | and return undef | ||||
497 | if $epoch_dt | ||||
498 | and $Month | ||||
499 | and $Month != $epoch_dt->month; | ||||
500 | if ($doy) { | ||||
501 | $self->local_croak( | ||||
502 | "There is no use providing a day of the year without providing a year." | ||||
503 | ) | ||||
504 | and return undef | ||||
505 | unless $Year; | ||||
506 | $doy_dt = eval { | ||||
507 | DateTime->from_day_of_year( | ||||
508 | year => $Year, day_of_year => $doy, | ||||
509 | time_zone => $use_timezone | ||||
510 | ); | ||||
511 | }; | ||||
512 | $self->local_croak("Day of year $Year-$doy is not valid") | ||||
513 | and return undef | ||||
514 | if $@; | ||||
515 | |||||
516 | my $month = $doy_dt->month; | ||||
517 | $self->local_croak( "Your day of the year ($doy - in " | ||||
518 | . $doy_dt->month_name | ||||
519 | . ") is not in your month ($Month)" ) | ||||
520 | and return undef | ||||
521 | if $Month | ||||
522 | and $month != $Month; | ||||
523 | $Month = $month; | ||||
524 | } | ||||
525 | $self->local_croak("Your day of the year does not match your epoch.") | ||||
526 | and return undef | ||||
527 | if $epoch_dt | ||||
528 | and $doy_dt | ||||
529 | and $doy_dt->doy != $epoch_dt->doy; | ||||
530 | |||||
531 | # Day of the month | ||||
532 | $self->local_croak("$day is too large to be a day of the month.") | ||||
533 | and return undef | ||||
534 | unless $day <= 31; | ||||
535 | $self->local_croak( | ||||
536 | "Your day of the month ($day) does not match your day of the year.") | ||||
537 | and return undef | ||||
538 | if $doy_dt | ||||
539 | and $day | ||||
540 | and $day != $doy_dt->day; | ||||
541 | $Day ||= | ||||
542 | ($day) ? $day | ||||
543 | : ($doy_dt) ? $doy_dt->day | ||||
544 | : ''; | ||||
545 | if ($Day) { | ||||
546 | $self->local_croak( | ||||
547 | "There is no use providing a day without providing a month and year." | ||||
548 | ) | ||||
549 | and return undef | ||||
550 | unless $Year | ||||
551 | and $Month; | ||||
552 | my $dt = eval { | ||||
553 | DateTime->new( | ||||
554 | year => $Year + 0, month => $Month + 0, day => $Day + 0, | ||||
555 | hour => 12, time_zone => $use_timezone | ||||
556 | ); | ||||
557 | }; | ||||
558 | $self->local_croak("Datetime $Year-$Month-$Day is not a valid date") | ||||
559 | and return undef | ||||
560 | if $@; | ||||
561 | $self->local_croak("There is no day $Day in $dt->month_name, $Year") | ||||
562 | and return undef | ||||
563 | unless $dt->month == $Month; | ||||
564 | } | ||||
565 | $self->local_croak("Your day of the month does not match your epoch.") | ||||
566 | and return undef | ||||
567 | if $epoch_dt | ||||
568 | and $Day | ||||
569 | and $Day != $epoch_dt->day; | ||||
570 | |||||
571 | # Hour of the day | ||||
572 | $self->local_croak("$hour_24 is too large to be an hour of the day.") | ||||
573 | and return undef | ||||
574 | unless $hour_24 <= 23; #OK so leap seconds will break! | ||||
575 | $self->local_croak("$hour_12 is too large to be an hour of the day.") | ||||
576 | and return undef | ||||
577 | unless $hour_12 <= 12; | ||||
578 | $self->local_croak( | ||||
579 | "You must specify am or pm for 12 hour clocks ($hour_12|$ampm).") | ||||
580 | and return undef | ||||
581 | if ( $hour_12 && ( !$ampm ) ); | ||||
582 | ( $Am, $Pm ) = @{ $self->{_locale}->am_pm_abbreviated }; | ||||
583 | if ( lc $ampm eq lc $Pm ) { | ||||
584 | if ($hour_12) { | ||||
585 | $hour_12 += 12 if $hour_12 and $hour_12 != 12; | ||||
586 | } | ||||
587 | $self->local_croak( | ||||
588 | "Your am/pm value ($ampm) does not match your hour ($hour_24)") | ||||
589 | and return undef | ||||
590 | if $hour_24 | ||||
591 | and $hour_24 < 12; | ||||
592 | } | ||||
593 | elsif ( lc $ampm eq lc $Am ) { | ||||
594 | if ($hour_12) { | ||||
595 | $hour_12 = 0 if $hour_12 == 12; | ||||
596 | } | ||||
597 | $self->local_croak( | ||||
598 | "Your am/pm value ($ampm) does not match your hour ($hour_24)") | ||||
599 | and return undef | ||||
600 | if $hour_24 >= 12; | ||||
601 | } | ||||
602 | if ( $hour_12 and $hour_24 ) { | ||||
603 | $self->local_croak( | ||||
604 | "You have specified mis-matching 12 and 24 hour clock information" | ||||
605 | ) | ||||
606 | and return undef | ||||
607 | unless $hour_12 == $hour_24; | ||||
608 | $Hour = $hour_24; | ||||
609 | } | ||||
610 | elsif ($hour_12) { | ||||
611 | $Hour = $hour_12; | ||||
612 | } | ||||
613 | elsif ($hour_24) { | ||||
614 | $Hour = $hour_24; | ||||
615 | } | ||||
616 | $self->local_croak("Your hour does not match your epoch.") | ||||
617 | and return undef | ||||
618 | if $epoch_dt | ||||
619 | and $Hour | ||||
620 | and $Hour != $epoch_dt->hour; | ||||
621 | print "Set hour to $Hour.\n" if $self->{diagnostic}; | ||||
622 | |||||
623 | # Minutes | ||||
624 | $self->local_croak("$minute is too large to be a minute.") | ||||
625 | and return undef | ||||
626 | unless $minute <= 59; | ||||
627 | $Minute ||= $minute; | ||||
628 | $self->local_croak("Your minute does not match your epoch.") | ||||
629 | and return undef | ||||
630 | if $epoch_dt | ||||
631 | and $Minute | ||||
632 | and $Minute != $epoch_dt->minute; | ||||
633 | print "Set minute to $Minute.\n" if $self->{diagnostic}; | ||||
634 | |||||
635 | # Seconds | ||||
636 | $self->local_croak("$second is too large to be a second.") | ||||
637 | and return undef | ||||
638 | unless $second <= 59; #OK so leap seconds will break! | ||||
639 | $Second ||= $second; | ||||
640 | $self->local_croak("Your second does not match your epoch.") | ||||
641 | and return undef | ||||
642 | if $epoch_dt | ||||
643 | and $Second | ||||
644 | and $Second != $epoch_dt->second; | ||||
645 | print "Set second to $Second.\n" if $self->{diagnostic}; | ||||
646 | |||||
647 | # Nanoeconds | ||||
648 | $self->local_croak("$nanosecond is too large to be a nanosecond.") | ||||
649 | and return undef | ||||
650 | unless length($nanosecond) <= 9; | ||||
651 | $Nanosecond ||= $nanosecond; | ||||
652 | $Nanosecond .= '0' while length($Nanosecond) < 9; | ||||
653 | |||||
654 | # Epoch doesn't return nanoseconds | ||||
655 | # croak "Your nanosecond does not match your epoch." if $epoch_dt and $Nanosecond and $Nanosecond != $epoch_dt->nanosecond; | ||||
656 | print "Set nanosecond to $Nanosecond.\n" if $self->{diagnostic}; | ||||
657 | |||||
658 | my $potential_return = eval { | ||||
659 | DateTime->new( | ||||
660 | year => ( $Year || 1 ) + 0, | ||||
661 | month => ( $Month || 1 ) + 0, | ||||
662 | day => ( $Day || 1 ) + 0, | ||||
663 | |||||
664 | hour => ( $Hour || 0 ) + 0, | ||||
665 | minute => ( $Minute || 0 ) + 0, | ||||
666 | second => ( $Second || 0 ) + 0, | ||||
667 | nanosecond => ( $Nanosecond || 0 ) + 0, | ||||
668 | |||||
669 | locale => $self->{_locale}, | ||||
670 | time_zone => $use_timezone, | ||||
671 | ); | ||||
672 | }; | ||||
673 | $self->local_croak("Datetime is not a valid date") and return undef if $@; | ||||
674 | |||||
675 | $self->local_croak( | ||||
676 | "Your day of the week ($dow_mon_1) does not match the date supplied: " | ||||
677 | . $potential_return->ymd ) | ||||
678 | and return undef | ||||
679 | if $dow_mon_1 | ||||
680 | and $potential_return->dow != $dow_mon_1; | ||||
681 | |||||
682 | $self->local_croak( | ||||
683 | "Your day of the week ($dow_sun_0) does not match the date supplied: " | ||||
684 | . $potential_return->ymd ) | ||||
685 | and return undef | ||||
686 | if $dow_sun_0 | ||||
687 | and ( $potential_return->dow % 7 ) != $dow_sun_0; | ||||
688 | |||||
689 | if ($dow_name) { | ||||
690 | my $dow_count = 0; | ||||
691 | my $dow_number = 0; | ||||
692 | foreach my $dow ( @{ $self->{_locale}->day_format_wide } ) { | ||||
693 | $dow_count++; | ||||
694 | if ( lc $dow eq lc $dow_name ) { | ||||
695 | $dow_number = $dow_count; | ||||
696 | last; | ||||
697 | } | ||||
698 | } | ||||
699 | unless ($dow_number) { | ||||
700 | my $dow_count = 0; | ||||
701 | foreach my $dow ( @{ $self->{_locale}->day_format_abbreviated } ) | ||||
702 | { | ||||
703 | $dow_count++; | ||||
704 | if ( lc $dow eq lc $dow_name ) { | ||||
705 | $dow_number = $dow_count; | ||||
706 | last; | ||||
707 | } | ||||
708 | } | ||||
709 | } | ||||
710 | unless ($dow_number) { | ||||
711 | $self->local_croak( | ||||
712 | "$dow_name is not a recognised day in this locale.") | ||||
713 | and return undef; | ||||
714 | } | ||||
715 | $self->local_croak( | ||||
716 | "Your day of the week ($dow_name) does not match the date supplied: " | ||||
717 | . $potential_return->ymd ) | ||||
718 | and return undef | ||||
719 | if $dow_number | ||||
720 | and $potential_return->dow != $dow_number; | ||||
721 | } | ||||
722 | |||||
723 | $self->local_croak( | ||||
724 | "Your week number ($week_sun_0) does not match the date supplied: " | ||||
725 | . $potential_return->ymd ) | ||||
726 | and return undef | ||||
727 | if $week_sun_0 | ||||
728 | and $potential_return->strftime('%U') != $week_sun_0; | ||||
729 | $self->local_croak( | ||||
730 | "Your week number ($week_mon_1) does not match the date supplied: " | ||||
731 | . $potential_return->ymd ) | ||||
732 | and return undef | ||||
733 | if $week_mon_1 | ||||
734 | and $potential_return->strftime('%W') != $week_mon_1; | ||||
735 | $self->local_croak( | ||||
736 | "Your ISO week year ($iso_week_year) does not match the date supplied: " | ||||
737 | . $potential_return->ymd ) | ||||
738 | and return undef | ||||
739 | if $iso_week_year | ||||
740 | and $potential_return->strftime('%G') != $iso_week_year; | ||||
741 | $self->local_croak( | ||||
742 | "Your ISO week year ($iso_week_year_100) does not match the date supplied: " | ||||
743 | . $potential_return->ymd ) | ||||
744 | and return undef | ||||
745 | if $iso_week_year_100 | ||||
746 | and $potential_return->strftime('%g') != $iso_week_year_100; | ||||
747 | |||||
748 | # Move into the timezone in the object - if there is one | ||||
749 | print "Potential Datetime: " | ||||
750 | . $potential_return->strftime("%F %T %z %Z") . "\n" | ||||
751 | if $self->{diagnostic}; | ||||
752 | print "Setting timezone: " . $self->{set_time_zone} . "\n" | ||||
753 | if $self->{diagnostic}; | ||||
754 | if ( $self->{set_time_zone} ) { | ||||
755 | $potential_return->set_time_zone( $self->{set_time_zone} ); | ||||
756 | } | ||||
757 | elsif ($set_time_zone) { | ||||
758 | $potential_return->set_time_zone($set_time_zone); | ||||
759 | } | ||||
760 | print "Actual Datetime: " | ||||
761 | . $potential_return->strftime("%F %T %z %Z") . "\n" | ||||
762 | if $self->{diagnostic}; | ||||
763 | |||||
764 | return $potential_return; | ||||
765 | } | ||||
766 | |||||
767 | sub parse_duration { | ||||
768 | croak "DateTime::Format::Strptime doesn't do durations."; | ||||
769 | } | ||||
770 | |||||
771 | sub format_datetime { | ||||
772 | my ( $self, $dt ) = @_; | ||||
773 | my $pattern = $self->pattern; | ||||
774 | $pattern =~ s/%O/$dt->time_zone->name/eg; | ||||
775 | return $dt->clone->set_locale( $self->locale )->strftime($pattern); | ||||
776 | } | ||||
777 | |||||
778 | sub format_duration { | ||||
779 | croak "DateTime::Format::Strptime doesn't do durations."; | ||||
780 | } | ||||
781 | |||||
782 | sub _build_parser { | ||||
783 | my $self = shift; | ||||
784 | my $regex = my $field_list = shift; | ||||
785 | if ( ref $regex eq 'Regexp' ) { | ||||
786 | $field_list =~ s/^\(\?-xism:(.+)\)$/$1/; | ||||
787 | } | ||||
788 | my @fields = $field_list =~ m/(%\{\w+\}|%\d*.)/g; | ||||
789 | $field_list = join( '', @fields ); | ||||
790 | |||||
791 | # Locale-ize the parser | ||||
792 | my $ampm_list = join( '|', @{ $self->{_locale}->am_pm_abbreviated } ); | ||||
793 | $ampm_list .= '|' . lc $ampm_list; | ||||
794 | |||||
795 | my $default_date_format = $self->{_locale}->glibc_date_format; | ||||
796 | my @locale_format = $default_date_format =~ m/(%\{\w+\}|%\d*.)/g; | ||||
797 | $default_date_format = join( '', @locale_format ); | ||||
798 | |||||
799 | my $default_time_format = $self->{_locale}->glibc_time_format; | ||||
800 | @locale_format = $default_time_format =~ m/(%\{\w+\}|%\d*.)/g; | ||||
801 | $default_time_format = join( '', @locale_format ); | ||||
802 | |||||
803 | my $default_datetime_format = $self->{_locale}->glibc_datetime_format; | ||||
804 | @locale_format = $default_datetime_format =~ m/(%\{\w+\}|%\d*.)/g; | ||||
805 | $default_datetime_format = join( '', @locale_format ); | ||||
806 | |||||
807 | |||||
808 | "Date format: $default_date_format\nTime format: $default_time_format\nDatetime format: $default_datetime_format\n" | ||||
809 | if $self->{diagnostic}; | ||||
810 | |||||
811 | $regex =~ s/%%/__ESCAPED_PERCENT_SIGN_MARKER__/g; | ||||
812 | $field_list =~ s/%%/__ESCAPED_PERCENT_SIGN_MARKER__/g; | ||||
813 | |||||
814 | $regex =~ s/%c/$self->{_locale}->glibc_datetime_format/eg; | ||||
815 | $field_list =~ s/%c/$default_datetime_format/eg; | ||||
816 | |||||
817 | # %c is the locale's default datetime format. | ||||
818 | |||||
819 | $regex =~ s/%x/$self->{_locale}->glibc_date_format/eg; | ||||
820 | $field_list =~ s/%x/$default_date_format/eg; | ||||
821 | |||||
822 | # %x is the locale's default date format. | ||||
823 | |||||
824 | $regex =~ s/%X/$self->{_locale}->glibc_time_format/eg; | ||||
825 | $field_list =~ s/%X/$default_time_format/eg; | ||||
826 | |||||
827 | # %x is the locale's default time format. | ||||
828 | |||||
829 | if ( ref $regex ne 'Regexp' ) { | ||||
830 | $regex = quotemeta($regex); | ||||
831 | $regex =~ s/(?<!\\)\\%/%/g; | ||||
832 | $regex =~ s/%\\\{([^\}]+)\\\}/%{$1}/g; | ||||
833 | } | ||||
834 | |||||
835 | $regex =~ s/%T/%H:%M:%S/g; | ||||
836 | $field_list =~ s/%T/%H%M%S/g; | ||||
837 | |||||
838 | # %T is the time as %H:%M:%S. | ||||
839 | |||||
840 | $regex =~ s/%r/%I:%M:%S %p/g; | ||||
841 | $field_list =~ s/%r/%I%M%S%p/g; | ||||
842 | |||||
843 | #is the time as %I:%M:%S %p. | ||||
844 | |||||
845 | $regex =~ s/%R/%H:%M/g; | ||||
846 | $field_list =~ s/%R/%H%M/g; | ||||
847 | |||||
848 | #is the time as %H:%M. | ||||
849 | |||||
850 | $regex =~ s|%D|%m\\/%d\\/%y|g; | ||||
851 | $field_list =~ s|%D|%m%d%y|g; | ||||
852 | |||||
853 | #is the same as %m/%d/%y. | ||||
854 | |||||
855 | $regex =~ s|%F|%Y\\-%m\\-%d|g; | ||||
856 | $field_list =~ s|%F|%Y%m%d|g; | ||||
857 | |||||
858 | #is the same as %Y-%m-%d - the ISO date format. | ||||
859 | |||||
860 | my $day_re = join( | ||||
861 | '|', | ||||
862 | map { quotemeta $_ } | ||||
863 | sort { length $b <=> length $a } | ||||
864 | grep( /\W/, @{ $self->{_locale}->day_format_wide }, | ||||
865 | @{ $self->{_locale}->day_format_abbreviated } ) | ||||
866 | ); | ||||
867 | $day_re .= '|' if $day_re; | ||||
868 | $regex =~ s/%a/($day_re\\w+)/gi; | ||||
869 | $field_list =~ s/%a/#dow_name#/gi; | ||||
870 | |||||
871 | # %a is the day of the week, using the locale's weekday names; either the abbreviated or full name may be specified. | ||||
872 | # %A is the same as %a. | ||||
873 | |||||
874 | my $month_re = join( | ||||
875 | '|', | ||||
876 | map { quotemeta $_ } | ||||
877 | sort { length $b <=> length $a } | ||||
878 | grep( /\s|\d/, @{ $self->{_locale}->month_format_wide }, | ||||
879 | @{ $self->{_locale}->month_format_abbreviated } ) | ||||
880 | ); | ||||
881 | $month_re .= '|' if $month_re; | ||||
882 | $month_re .= '[^\\s\\d]+'; | ||||
883 | $regex =~ s/%[bBh]/($month_re)/g; | ||||
884 | $field_list =~ s/%[bBh]/#month_name#/g; | ||||
885 | |||||
886 | #is the month, using the locale's month names; either the abbreviated or full name may be specified. | ||||
887 | # %B is the same as %b. | ||||
888 | # %h is the same as %b. | ||||
889 | |||||
890 | #s/%c//g; | ||||
891 | #is replaced by the locale's appropriate date and time representation. | ||||
892 | |||||
893 | $regex =~ s/%C/([\\d ]?\\d)/g; | ||||
894 | $field_list =~ s/%C/#century#/g; | ||||
895 | |||||
896 | #is the century number [0,99]; leading zeros are permitted by not required. | ||||
897 | |||||
898 | $regex =~ s/%[de]/([\\d ]?\\d)/g; | ||||
899 | $field_list =~ s/%[de]/#day#/g; | ||||
900 | |||||
901 | #is the day of the month [1,31]; leading zeros are permitted but not required. | ||||
902 | #%e is the same as %d. | ||||
903 | |||||
904 | $regex =~ s/%[Hk]/([\\d ]?\\d)/g; | ||||
905 | $field_list =~ s/%[Hk]/#hour_24#/g; | ||||
906 | |||||
907 | #is the hour (24-hour clock) [0,23]; leading zeros are permitted but not required. | ||||
908 | # %k is the same as %H | ||||
909 | |||||
910 | $regex =~ s/%g/([\\d ]?\\d)/g; | ||||
911 | $field_list =~ s/%g/#iso_week_year_100#/g; | ||||
912 | |||||
913 | # The year corresponding to the ISO week number, but without the century (0-99). | ||||
914 | |||||
915 | $regex =~ s/%G/(\\d{4})/g; | ||||
916 | $field_list =~ s/%G/#iso_week_year#/g; | ||||
917 | |||||
918 | # The year corresponding to the ISO week number. | ||||
919 | |||||
920 | $regex =~ s/%[Il]/([\\d ]?\\d)/g; | ||||
921 | $field_list =~ s/%[Il]/#hour_12#/g; | ||||
922 | |||||
923 | #is the hour (12-hour clock) [1-12]; leading zeros are permitted but not required. | ||||
924 | # %l is the same as %I. | ||||
925 | |||||
926 | $regex =~ s/%j/(\\d{1,3})/g; | ||||
927 | $field_list =~ s/%j/#doy#/g; | ||||
928 | |||||
929 | #is the day of the year [1,366]; leading zeros are permitted but not required. | ||||
930 | |||||
931 | $regex =~ s/%m/([\\d ]?\\d)/g; | ||||
932 | $field_list =~ s/%m/#month#/g; | ||||
933 | |||||
934 | #is the month number [1-12]; leading zeros are permitted but not required. | ||||
935 | |||||
936 | $regex =~ s/%M/([\\d ]?\\d)/g; | ||||
937 | $field_list =~ s/%M/#minute#/g; | ||||
938 | |||||
939 | #is the minute [0-59]; leading zeros are permitted but not required. | ||||
940 | |||||
941 | $regex =~ s/%[nt]/\\s+/g; | ||||
942 | $field_list =~ s/%[nt]//g; | ||||
943 | |||||
944 | # %n is any white space. | ||||
945 | # %t is any white space. | ||||
946 | |||||
947 | $regex =~ s/%p/($ampm_list)/gi; | ||||
948 | $field_list =~ s/%p/#ampm#/gi; | ||||
949 | |||||
950 | # %p is the locale's equivalent of either A.M./P.M. indicator for 12-hour clock. | ||||
951 | |||||
952 | $regex =~ s/%s/(\\d+)/g; | ||||
953 | $field_list =~ s/%s/#epoch#/g; | ||||
954 | |||||
955 | # %s is the seconds since the epoch | ||||
956 | |||||
957 | $regex =~ s/%S/([\\d ]?\\d)/g; | ||||
958 | $field_list =~ s/%S/#second#/g; | ||||
959 | |||||
960 | # %S is the seconds [0-61]; leading zeros are permitted but not required. | ||||
961 | |||||
962 | $regex =~ s/%(\d*)N/($1) ? "(\\d{$1})" : "(\\d+)"/eg; | ||||
963 | $field_list =~ s/%\d*N/#nanosecond#/g; | ||||
964 | |||||
965 | # %N is the nanoseconds (or sub seconds really) | ||||
966 | |||||
967 | $regex =~ s/%U/([\\d ]?\\d)/g; | ||||
968 | $field_list =~ s/%U/#week_sun_0#/g; | ||||
969 | |||||
970 | # %U is the week number of the year (Sunday as the first day of the week) as a decimal number [0-53]; leading zeros are permitted but not required. | ||||
971 | |||||
972 | $regex =~ s/%w/([0-6])/g; | ||||
973 | $field_list =~ s/%w/#dow_sun_0#/g; | ||||
974 | |||||
975 | # is the weekday as a decimal number [0-6], with 0 representing Sunday. | ||||
976 | |||||
977 | $regex =~ s/%u/([1-7])/g; | ||||
978 | $field_list =~ s/%u/#dow_mon_1#/g; | ||||
979 | |||||
980 | # is the weekday as a decimal number [1-7], with 1 representing Monday - a la DateTime. | ||||
981 | |||||
982 | $regex =~ s/%W/([\\d ]?\\d)/g; | ||||
983 | $field_list =~ s/%W/#week_mon_1#/g; | ||||
984 | |||||
985 | #is the week number of the year (Monday as the first day of the week) as a decimal number [0,53]; leading zeros are permitted but not required. | ||||
986 | |||||
987 | $regex =~ s/%y/([\\d ]?\\d)/g; | ||||
988 | $field_list =~ s/%y/#year_100#/g; | ||||
989 | |||||
990 | # is the year within the century. When a century is not otherwise specified, values in the range 69-99 refer to years in the twentieth century (1969 to 1999 inclusive); values in the range 0-68 refer to years in the twenty-first century (2000-2068 inclusive). Leading zeros are permitted but not required. | ||||
991 | |||||
992 | $regex =~ s/%Y/(\\d{4})/g; | ||||
993 | $field_list =~ s/%Y/#year#/g; | ||||
994 | |||||
995 | # is the year including the century (for example, 1998). | ||||
996 | |||||
997 | $regex =~ s|%z|([+-]\\d{4})|g; | ||||
998 | $field_list =~ s/%z/#tz_offset#/g; | ||||
999 | |||||
1000 | # Timezone Offset. | ||||
1001 | |||||
1002 | $regex =~ s|%Z|(\\w+)|g; | ||||
1003 | $field_list =~ s/%Z/#timezone#/g; | ||||
1004 | |||||
1005 | # The short timezone name. | ||||
1006 | |||||
1007 | $regex =~ s|%O|(\\w+\\/\\w+)|g; | ||||
1008 | $field_list =~ s/%O/#tz_olson#/g; | ||||
1009 | |||||
1010 | # The Olson timezone name. | ||||
1011 | |||||
1012 | $regex =~ s|%\{(\w+)\}|(DateTime->can($1)) ? "(.+)" : ".+"|eg; | ||||
1013 | $field_list =~ s|(%\{(\w+)\})|(DateTime->can($2)) ? "#$2#" : $1 |eg; | ||||
1014 | |||||
1015 | # Any function in DateTime. | ||||
1016 | |||||
1017 | $regex =~ s/__ESCAPED_PERCENT_SIGN_MARKER__/\\%/g; | ||||
1018 | $field_list =~ s/__ESCAPED_PERCENT_SIGN_MARKER__//g; | ||||
1019 | |||||
1020 | # is replaced by %. | ||||
1021 | #print $regex; | ||||
1022 | |||||
1023 | $field_list =~ s/#([a-z0-9_]+)#/\$$1, /gi; | ||||
1024 | $field_list =~ s/,\s*$//; | ||||
1025 | |||||
1026 | return qq|($field_list) = \$time_string =~ /$regex/|; | ||||
1027 | } | ||||
1028 | |||||
1029 | # Utility functions | ||||
1030 | |||||
1031 | sub local_croak { | ||||
1032 | my $self = $_[0]; | ||||
1033 | return &{ $self->{on_error} }(@_) if ref( $self->{on_error} ); | ||||
1034 | croak( $_[1] ) if $self->{on_error} eq 'croak'; | ||||
1035 | $self->{errmsg} = $_[1]; | ||||
1036 | return ( $self->{on_error} eq 'undef' ); | ||||
1037 | } | ||||
1038 | |||||
1039 | sub local_carp { | ||||
1040 | my $self = $_[0]; | ||||
1041 | return &{ $self->{on_error} }(@_) if ref( $self->{on_error} ); | ||||
1042 | carp( $_[1] ) if $self->{on_error} eq 'croak'; | ||||
1043 | $self->{errmsg} = $_[1]; | ||||
1044 | return ( $self->{on_error} eq 'undef' ); | ||||
1045 | } | ||||
1046 | |||||
1047 | sub errmsg { | ||||
1048 | $_[0]->{errmsg}; | ||||
1049 | } | ||||
1050 | |||||
1051 | # Exportable functions: | ||||
1052 | |||||
1053 | sub strftime { | ||||
1054 | my ( $pattern, $dt ) = @_; | ||||
1055 | return $dt->strftime($pattern); | ||||
1056 | } | ||||
1057 | |||||
1058 | sub strptime { | ||||
1059 | my ( $pattern, $time_string ) = @_; | ||||
1060 | return DateTime::Format::Strptime->new( | ||||
1061 | pattern => $pattern, | ||||
1062 | on_error => 'croak' | ||||
1063 | )->parse_datetime($time_string); | ||||
1064 | } | ||||
1065 | |||||
1066 | 1 | 27µs | 1; | ||
1067 | |||||
1068 | # ABSTRACT: Parse and format strp and strf time patterns | ||||
1069 | |||||
1070 | __END__ |