1 | |
2 | #ifndef _DATE_TIME_FACET__HPP__ |
3 | #define _DATE_TIME_FACET__HPP__ |
4 | |
5 | /* Copyright (c) 2004-2005 CrystalClear Software, Inc. |
6 | * Use, modification and distribution is subject to the |
7 | * Boost Software License, Version 1.0. (See accompanying |
8 | * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) |
9 | * Author: Martin Andrian, Jeff Garland, Bart Garst |
10 | * $Date$ |
11 | */ |
12 | |
13 | #include <cctype> |
14 | #include <locale> |
15 | #include <limits> |
16 | #include <string> |
17 | #include <sstream> |
18 | #include <iomanip> |
19 | #include <iterator> // i/ostreambuf_iterator |
20 | #include <exception> |
21 | #include <boost/assert.hpp> |
22 | #include <boost/lexical_cast.hpp> |
23 | #include <boost/throw_exception.hpp> |
24 | #include <boost/range/as_literal.hpp> |
25 | #include <boost/algorithm/string/erase.hpp> |
26 | #include <boost/algorithm/string/replace.hpp> |
27 | #include <boost/date_time/compiler_config.hpp> |
28 | #include <boost/date_time/date_facet.hpp> |
29 | #include <boost/date_time/string_convert.hpp> |
30 | #include <boost/date_time/special_defs.hpp> |
31 | #include <boost/date_time/time_resolution_traits.hpp> // absolute_value |
32 | |
33 | namespace boost { |
34 | namespace date_time { |
35 | |
36 | template <class CharT> |
37 | struct time_formats { |
38 | public: |
39 | typedef CharT char_type; |
40 | static const char_type fractional_seconds_format[3]; // f |
41 | static const char_type fractional_seconds_or_none_format[3]; // F |
42 | static const char_type seconds_with_fractional_seconds_format[3]; // s |
43 | static const char_type seconds_format[3]; // S |
44 | static const char_type hours_format[3]; // H |
45 | static const char_type unrestricted_hours_format[3]; // O |
46 | static const char_type full_24_hour_time_format[3]; // T |
47 | static const char_type full_24_hour_time_expanded_format[9]; // HH:MM:SS |
48 | static const char_type short_24_hour_time_format[3]; // R |
49 | static const char_type short_24_hour_time_expanded_format[6]; // HH:MM |
50 | static const char_type standard_format[9]; // x X |
51 | static const char_type zone_abbrev_format[3]; // z |
52 | static const char_type zone_name_format[3]; // Z |
53 | static const char_type zone_iso_format[3]; // q |
54 | static const char_type zone_iso_extended_format[3]; // Q |
55 | static const char_type posix_zone_string_format[4]; // ZP |
56 | static const char_type duration_sign_negative_only[3]; // - |
57 | static const char_type duration_sign_always[3]; // + |
58 | static const char_type duration_seperator[2]; |
59 | static const char_type negative_sign[2]; //- |
60 | static const char_type positive_sign[2]; //+ |
61 | static const char_type iso_time_format_specifier[18]; |
62 | static const char_type iso_time_format_extended_specifier[22]; |
63 | //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz] |
64 | static const char_type default_time_format[23]; |
65 | // default_time_input_format uses a posix_time_zone_string instead of a time zone abbrev |
66 | static const char_type default_time_input_format[24]; |
67 | //default time_duration format is HH:MM:SS[.fff...] |
68 | static const char_type default_time_duration_format[11]; |
69 | }; |
70 | |
71 | template <class CharT> |
72 | const typename time_formats<CharT>::char_type |
73 | time_formats<CharT>::fractional_seconds_format[3] = {'%','f'}; |
74 | |
75 | template <class CharT> |
76 | const typename time_formats<CharT>::char_type |
77 | time_formats<CharT>::fractional_seconds_or_none_format[3] = {'%','F'}; |
78 | |
79 | template <class CharT> |
80 | const typename time_formats<CharT>::char_type |
81 | time_formats<CharT>::seconds_with_fractional_seconds_format[3] = {'%','s'}; |
82 | |
83 | template <class CharT> |
84 | const typename time_formats<CharT>::char_type |
85 | time_formats<CharT>::seconds_format[3] = {'%','S'}; |
86 | |
87 | template <class CharT> |
88 | const typename time_formats<CharT>::char_type |
89 | time_formats<CharT>::hours_format[3] = {'%','H'}; |
90 | |
91 | template <class CharT> |
92 | const typename time_formats<CharT>::char_type |
93 | time_formats<CharT>::unrestricted_hours_format[3] = {'%','O'}; |
94 | |
95 | template <class CharT> |
96 | const typename time_formats<CharT>::char_type |
97 | time_formats<CharT>::full_24_hour_time_format[3] = {'%','T'}; |
98 | |
99 | template <class CharT> |
100 | const typename time_formats<CharT>::char_type |
101 | time_formats<CharT>::full_24_hour_time_expanded_format[9] = |
102 | {'%','H',':','%','M',':','%','S'}; |
103 | |
104 | template <class CharT> |
105 | const typename time_formats<CharT>::char_type |
106 | time_formats<CharT>::short_24_hour_time_format[3] = {'%','R'}; |
107 | |
108 | template <class CharT> |
109 | const typename time_formats<CharT>::char_type |
110 | time_formats<CharT>::short_24_hour_time_expanded_format[6] = |
111 | {'%','H',':','%','M'}; |
112 | |
113 | template <class CharT> |
114 | const typename time_formats<CharT>::char_type |
115 | //time_formats<CharT>::standard_format[5] = {'%','c',' ','%','z'}; |
116 | time_formats<CharT>::standard_format[9] = {'%','x',' ','%','X',' ','%','z'}; |
117 | |
118 | template <class CharT> |
119 | const typename time_formats<CharT>::char_type |
120 | time_formats<CharT>::zone_abbrev_format[3] = {'%','z'}; |
121 | |
122 | template <class CharT> |
123 | const typename time_formats<CharT>::char_type |
124 | time_formats<CharT>::zone_name_format[3] = {'%','Z'}; |
125 | |
126 | template <class CharT> |
127 | const typename time_formats<CharT>::char_type |
128 | time_formats<CharT>::zone_iso_format[3] = {'%','q'}; |
129 | |
130 | template <class CharT> |
131 | const typename time_formats<CharT>::char_type |
132 | time_formats<CharT>::zone_iso_extended_format[3] ={'%','Q'}; |
133 | |
134 | template <class CharT> |
135 | const typename time_formats<CharT>::char_type |
136 | time_formats<CharT>::posix_zone_string_format[4] ={'%','Z','P'}; |
137 | |
138 | template <class CharT> |
139 | const typename time_formats<CharT>::char_type |
140 | time_formats<CharT>::duration_seperator[2] = {':'}; |
141 | |
142 | template <class CharT> |
143 | const typename time_formats<CharT>::char_type |
144 | time_formats<CharT>::negative_sign[2] = {'-'}; |
145 | |
146 | template <class CharT> |
147 | const typename time_formats<CharT>::char_type |
148 | time_formats<CharT>::positive_sign[2] = {'+'}; |
149 | |
150 | template <class CharT> |
151 | const typename time_formats<CharT>::char_type |
152 | time_formats<CharT>::duration_sign_negative_only[3] ={'%','-'}; |
153 | |
154 | template <class CharT> |
155 | const typename time_formats<CharT>::char_type |
156 | time_formats<CharT>::duration_sign_always[3] ={'%','+'}; |
157 | |
158 | template <class CharT> |
159 | const typename time_formats<CharT>::char_type |
160 | time_formats<CharT>::iso_time_format_specifier[18] = |
161 | {'%', 'Y', '%', 'm', '%', 'd', 'T', |
162 | '%', 'H', '%', 'M', '%', 'S', '%', 'F', '%','q' }; |
163 | |
164 | template <class CharT> |
165 | const typename time_formats<CharT>::char_type |
166 | time_formats<CharT>::iso_time_format_extended_specifier[22] = |
167 | {'%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ', |
168 | '%', 'H', ':', '%', 'M', ':', '%', 'S', '%', 'F','%','Q'}; |
169 | |
170 | template <class CharT> |
171 | const typename time_formats<CharT>::char_type |
172 | time_formats<CharT>::default_time_format[23] = |
173 | {'%','Y','-','%','b','-','%','d',' ', |
174 | '%','H',':','%','M',':','%','S','%','F',' ','%','z'}; |
175 | |
176 | template <class CharT> |
177 | const typename time_formats<CharT>::char_type |
178 | time_formats<CharT>::default_time_input_format[24] = |
179 | {'%','Y','-','%','b','-','%','d',' ', |
180 | '%','H',':','%','M',':','%','S','%','F',' ','%','Z','P'}; |
181 | |
182 | template <class CharT> |
183 | const typename time_formats<CharT>::char_type |
184 | time_formats<CharT>::default_time_duration_format[11] = |
185 | {'%','O',':','%','M',':','%','S','%','F'}; |
186 | |
187 | |
188 | |
189 | /*! Facet used for format-based output of time types |
190 | * This class provides for the use of format strings to output times. In addition |
191 | * to the flags for formatting date elements, the following are the allowed format flags: |
192 | * - %x %X => default format - enables addition of more flags to default (ie. "%x %X %z") |
193 | * - %f => fractional seconds ".123456" |
194 | * - %F => fractional seconds or none: like frac sec but empty if frac sec == 0 |
195 | * - %s => seconds w/ fractional sec "02.123" (this is the same as "%S%f) |
196 | * - %S => seconds "02" |
197 | * - %z => abbreviated time zone "EDT" |
198 | * - %Z => full time zone name "Eastern Daylight Time" |
199 | */ |
200 | template <class time_type, |
201 | class CharT, |
202 | class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > > |
203 | class time_facet : |
204 | public boost::date_time::date_facet<typename time_type::date_type , CharT, OutItrT> { |
205 | typedef time_formats< CharT > formats_type; |
206 | public: |
207 | typedef typename time_type::date_type date_type; |
208 | typedef typename time_type::time_duration_type time_duration_type; |
209 | typedef boost::date_time::period<time_type,time_duration_type> period_type; |
210 | typedef boost::date_time::date_facet<typename time_type::date_type, CharT, OutItrT> base_type; |
211 | typedef typename base_type::string_type string_type; |
212 | typedef typename base_type::char_type char_type; |
213 | typedef typename base_type::period_formatter_type period_formatter_type; |
214 | typedef typename base_type::special_values_formatter_type special_values_formatter_type; |
215 | typedef typename base_type::date_gen_formatter_type date_gen_formatter_type; |
216 | static const char_type* fractional_seconds_format; // %f |
217 | static const char_type* fractional_seconds_or_none_format; // %F |
218 | static const char_type* seconds_with_fractional_seconds_format; // %s |
219 | static const char_type* seconds_format; // %S |
220 | static const char_type* hours_format; // %H |
221 | static const char_type* unrestricted_hours_format; // %O |
222 | static const char_type* standard_format; // %x X |
223 | static const char_type* zone_abbrev_format; // %z |
224 | static const char_type* zone_name_format; // %Z |
225 | static const char_type* zone_iso_format; // %q |
226 | static const char_type* zone_iso_extended_format; // %Q |
227 | static const char_type* posix_zone_string_format; // %ZP |
228 | static const char_type* duration_seperator; |
229 | static const char_type* duration_sign_always; // %+ |
230 | static const char_type* duration_sign_negative_only; // %- |
231 | static const char_type* negative_sign; //- |
232 | static const char_type* positive_sign; //+ |
233 | static const char_type* iso_time_format_specifier; |
234 | static const char_type* iso_time_format_extended_specifier; |
235 | |
236 | //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz] |
237 | static const char_type* default_time_format; |
238 | //default time_duration format is HH:MM:SS[.fff...] |
239 | static const char_type* default_time_duration_format; |
240 | static std::locale::id id; |
241 | |
242 | #if defined (__SUNPRO_CC) && defined (_RWSTD_VER) |
243 | std::locale::id& __get_id (void) const { return id; } |
244 | #endif |
245 | |
246 | //! sets default formats for ptime, local_date_time, and time_duration |
247 | explicit time_facet(::size_t ref_arg = 0) |
248 | : base_type(default_time_format, period_formatter_type(), special_values_formatter_type(), date_gen_formatter_type(), ref_arg), |
249 | m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format) |
250 | {} |
251 | |
252 | //! Construct the facet with an explicitly specified format |
253 | explicit time_facet(const char_type* format_arg, |
254 | period_formatter_type period_formatter_arg = period_formatter_type(), |
255 | const special_values_formatter_type& special_value_formatter = special_values_formatter_type(), |
256 | date_gen_formatter_type dg_formatter = date_gen_formatter_type(), |
257 | ::size_t ref_arg = 0) |
258 | : base_type(format_arg, |
259 | period_formatter_arg, |
260 | special_value_formatter, |
261 | dg_formatter, |
262 | ref_arg), |
263 | m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format) |
264 | {} |
265 | |
266 | //! Changes format for time_duration |
267 | void time_duration_format(const char_type* const format) |
268 | { |
269 | m_time_duration_format = format; |
270 | } |
271 | |
272 | virtual void set_iso_format() |
273 | { |
274 | this->m_format = iso_time_format_specifier; |
275 | } |
276 | virtual void set_iso_extended_format() |
277 | { |
278 | this->m_format = iso_time_format_extended_specifier; |
279 | } |
280 | |
281 | OutItrT put(OutItrT next_arg, |
282 | std::ios_base& ios_arg, |
283 | char_type fill_arg, |
284 | const time_type& time_arg) const |
285 | { |
286 | if (time_arg.is_special()) { |
287 | return this->do_put_special(next_arg, ios_arg, fill_arg, |
288 | time_arg.date().as_special()); |
289 | } |
290 | string_type local_format(this->m_format); |
291 | |
292 | // %T and %R have to be replaced here since they are not standard |
293 | boost::algorithm::replace_all(local_format, |
294 | boost::as_literal(formats_type::full_24_hour_time_format), |
295 | boost::as_literal(formats_type::full_24_hour_time_expanded_format)); |
296 | boost::algorithm::replace_all(local_format, |
297 | boost::as_literal(formats_type::short_24_hour_time_format), |
298 | boost::as_literal(formats_type::short_24_hour_time_expanded_format)); |
299 | |
300 | string_type frac_str; |
301 | if (local_format.find(seconds_with_fractional_seconds_format) != string_type::npos) { |
302 | // replace %s with %S.nnn |
303 | frac_str = |
304 | fractional_seconds_as_string(time_arg: time_arg.time_of_day(), null_when_zero: false); |
305 | char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point(); |
306 | |
307 | string_type replace_string(seconds_format); |
308 | replace_string += sep; |
309 | replace_string += frac_str; |
310 | boost::algorithm::replace_all(local_format, |
311 | seconds_with_fractional_seconds_format, |
312 | replace_string); |
313 | } |
314 | /* NOTE: replacing posix_zone_string_format must be done BEFORE |
315 | * zone_name_format: "%ZP" & "%Z", if Z is checked first it will |
316 | * incorrectly replace a zone_name where a posix_string should go */ |
317 | if (local_format.find(posix_zone_string_format) != string_type::npos) { |
318 | if(time_arg.zone_abbrev().empty()) { |
319 | // if zone_abbrev() returns an empty string, we want to |
320 | // erase posix_zone_string_format from format |
321 | boost::algorithm::erase_all(local_format, posix_zone_string_format); |
322 | } |
323 | else{ |
324 | boost::algorithm::replace_all(local_format, |
325 | posix_zone_string_format, |
326 | time_arg.zone_as_posix_string()); |
327 | } |
328 | } |
329 | if (local_format.find(zone_name_format) != string_type::npos) { |
330 | if(time_arg.zone_name().empty()) { |
331 | /* TODO: this'll probably create problems if a user places |
332 | * the zone_*_format flag in the format with a ptime. This |
333 | * code removes the flag from the default formats */ |
334 | |
335 | // if zone_name() returns an empty string, we want to |
336 | // erase zone_name_format & one preceeding space |
337 | std::basic_ostringstream<char_type> ss; |
338 | ss << ' ' << zone_name_format; |
339 | boost::algorithm::erase_all(local_format, ss.str()); |
340 | } |
341 | else{ |
342 | boost::algorithm::replace_all(local_format, |
343 | zone_name_format, |
344 | time_arg.zone_name()); |
345 | } |
346 | } |
347 | if (local_format.find(zone_abbrev_format) != string_type::npos) { |
348 | if(time_arg.zone_abbrev(false).empty()) { |
349 | /* TODO: this'll probably create problems if a user places |
350 | * the zone_*_format flag in the format with a ptime. This |
351 | * code removes the flag from the default formats */ |
352 | |
353 | // if zone_abbrev() returns an empty string, we want to |
354 | // erase zone_abbrev_format & one preceeding space |
355 | std::basic_ostringstream<char_type> ss; |
356 | ss << ' ' << zone_abbrev_format; |
357 | boost::algorithm::erase_all(local_format, ss.str()); |
358 | } |
359 | else{ |
360 | boost::algorithm::replace_all(local_format, |
361 | zone_abbrev_format, |
362 | time_arg.zone_abbrev(false)); |
363 | } |
364 | } |
365 | if (local_format.find(zone_iso_extended_format) != string_type::npos) { |
366 | if(time_arg.zone_name(true).empty()) { |
367 | /* TODO: this'll probably create problems if a user places |
368 | * the zone_*_format flag in the format with a ptime. This |
369 | * code removes the flag from the default formats */ |
370 | |
371 | // if zone_name() returns an empty string, we want to |
372 | // erase zone_iso_extended_format from format |
373 | boost::algorithm::erase_all(local_format, zone_iso_extended_format); |
374 | } |
375 | else{ |
376 | boost::algorithm::replace_all(local_format, |
377 | zone_iso_extended_format, |
378 | time_arg.zone_name(true)); |
379 | } |
380 | } |
381 | |
382 | if (local_format.find(zone_iso_format) != string_type::npos) { |
383 | if(time_arg.zone_abbrev(true).empty()) { |
384 | /* TODO: this'll probably create problems if a user places |
385 | * the zone_*_format flag in the format with a ptime. This |
386 | * code removes the flag from the default formats */ |
387 | |
388 | // if zone_abbrev() returns an empty string, we want to |
389 | // erase zone_iso_format from format |
390 | boost::algorithm::erase_all(local_format, zone_iso_format); |
391 | } |
392 | else{ |
393 | boost::algorithm::replace_all(local_format, |
394 | zone_iso_format, |
395 | time_arg.zone_abbrev(true)); |
396 | } |
397 | } |
398 | if (local_format.find(fractional_seconds_format) != string_type::npos) { |
399 | // replace %f with nnnnnnn |
400 | if (frac_str.empty()) { |
401 | frac_str = fractional_seconds_as_string(time_arg: time_arg.time_of_day(), null_when_zero: false); |
402 | } |
403 | boost::algorithm::replace_all(local_format, |
404 | fractional_seconds_format, |
405 | frac_str); |
406 | } |
407 | |
408 | if (local_format.find(fractional_seconds_or_none_format) != string_type::npos) { |
409 | // replace %F with nnnnnnn or nothing if fs == 0 |
410 | frac_str = |
411 | fractional_seconds_as_string(time_arg: time_arg.time_of_day(), null_when_zero: true); |
412 | if (frac_str.size()) { |
413 | char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point(); |
414 | string_type replace_string; |
415 | replace_string += sep; |
416 | replace_string += frac_str; |
417 | boost::algorithm::replace_all(local_format, |
418 | fractional_seconds_or_none_format, |
419 | replace_string); |
420 | } |
421 | else { |
422 | boost::algorithm::erase_all(local_format, |
423 | fractional_seconds_or_none_format); |
424 | } |
425 | } |
426 | |
427 | return this->do_put_tm(next_arg, ios_arg, fill_arg, |
428 | to_tm(time_arg), local_format); |
429 | } |
430 | |
431 | //! put function for time_duration |
432 | OutItrT put(OutItrT next_arg, |
433 | std::ios_base& ios_arg, |
434 | char_type fill_arg, |
435 | const time_duration_type& time_dur_arg) const |
436 | { |
437 | if (time_dur_arg.is_special()) { |
438 | return this->do_put_special(next_arg, ios_arg, fill_arg, |
439 | time_dur_arg.get_rep().as_special()); |
440 | } |
441 | |
442 | string_type format(m_time_duration_format); |
443 | if (time_dur_arg.is_negative()) { |
444 | // replace %- with minus sign. Should we use the numpunct facet? |
445 | boost::algorithm::replace_all(format, |
446 | duration_sign_negative_only, |
447 | negative_sign); |
448 | // remove all the %+ in the string with '-' |
449 | boost::algorithm::replace_all(format, |
450 | duration_sign_always, |
451 | negative_sign); |
452 | } |
453 | else { //duration is positive |
454 | // remove all the %- combos from the string |
455 | boost::algorithm::erase_all(format, duration_sign_negative_only); |
456 | // remove all the %+ in the string with '+' |
457 | boost::algorithm::replace_all(format, |
458 | duration_sign_always, |
459 | positive_sign); |
460 | } |
461 | |
462 | // %T and %R have to be replaced here since they are not standard |
463 | boost::algorithm::replace_all(format, |
464 | boost::as_literal(formats_type::full_24_hour_time_format), |
465 | boost::as_literal(formats_type::full_24_hour_time_expanded_format)); |
466 | boost::algorithm::replace_all(format, |
467 | boost::as_literal(formats_type::short_24_hour_time_format), |
468 | boost::as_literal(formats_type::short_24_hour_time_expanded_format)); |
469 | |
470 | /* |
471 | * It is possible for a time duration to span more then 24 hours. |
472 | * Standard time_put::put is obliged to behave the same as strftime |
473 | * (See ISO 14882-2003 22.2.5.3.1 par. 1) and strftime's behavior is |
474 | * unspecified for the case when tm_hour field is outside 0-23 range |
475 | * (See ISO 9899-1999 7.23.3.5 par. 3). So we must output %H and %O |
476 | * here ourself. |
477 | */ |
478 | string_type hours_str; |
479 | if (format.find(unrestricted_hours_format) != string_type::npos) { |
480 | hours_str = hours_as_string(time_arg: time_dur_arg); |
481 | boost::algorithm::replace_all(format, unrestricted_hours_format, hours_str); |
482 | } |
483 | // We still have to process restricted hours format specifier. In order to |
484 | // support parseability of durations in ISO format (%H%M%S), we'll have to |
485 | // restrict the stringified hours length to 2 characters. |
486 | if (format.find(hours_format) != string_type::npos) { |
487 | if (hours_str.empty()) |
488 | hours_str = hours_as_string(time_arg: time_dur_arg); |
489 | BOOST_ASSERT(hours_str.length() <= 2); |
490 | boost::algorithm::replace_all(format, hours_format, hours_str); |
491 | } |
492 | |
493 | string_type frac_str; |
494 | if (format.find(seconds_with_fractional_seconds_format) != string_type::npos) { |
495 | // replace %s with %S.nnn |
496 | frac_str = |
497 | fractional_seconds_as_string(time_arg: time_dur_arg, null_when_zero: false); |
498 | char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point(); |
499 | |
500 | string_type replace_string(seconds_format); |
501 | replace_string += sep; |
502 | replace_string += frac_str; |
503 | boost::algorithm::replace_all(format, |
504 | seconds_with_fractional_seconds_format, |
505 | replace_string); |
506 | } |
507 | if (format.find(fractional_seconds_format) != string_type::npos) { |
508 | // replace %f with nnnnnnn |
509 | if (!frac_str.size()) { |
510 | frac_str = fractional_seconds_as_string(time_arg: time_dur_arg, null_when_zero: false); |
511 | } |
512 | boost::algorithm::replace_all(format, |
513 | fractional_seconds_format, |
514 | frac_str); |
515 | } |
516 | |
517 | if (format.find(fractional_seconds_or_none_format) != string_type::npos) { |
518 | // replace %F with nnnnnnn or nothing if fs == 0 |
519 | frac_str = |
520 | fractional_seconds_as_string(time_arg: time_dur_arg, null_when_zero: true); |
521 | if (frac_str.size()) { |
522 | char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point(); |
523 | string_type replace_string; |
524 | replace_string += sep; |
525 | replace_string += frac_str; |
526 | boost::algorithm::replace_all(format, |
527 | fractional_seconds_or_none_format, |
528 | replace_string); |
529 | } |
530 | else { |
531 | boost::algorithm::erase_all(format, |
532 | fractional_seconds_or_none_format); |
533 | } |
534 | } |
535 | |
536 | return this->do_put_tm(next_arg, ios_arg, fill_arg, |
537 | to_tm(time_dur_arg), format); |
538 | } |
539 | |
540 | OutItrT put(OutItrT next, std::ios_base& ios_arg, |
541 | char_type fill, const period_type& p) const |
542 | { |
543 | return this->m_period_formatter.put_period(next, ios_arg, fill,p,*this); |
544 | } |
545 | |
546 | |
547 | protected: |
548 | |
549 | static |
550 | string_type |
551 | fractional_seconds_as_string(const time_duration_type& time_arg, |
552 | bool null_when_zero) |
553 | { |
554 | typename time_duration_type::fractional_seconds_type frac_sec = |
555 | time_arg.fractional_seconds(); |
556 | |
557 | if (null_when_zero && (frac_sec == 0)) { |
558 | return string_type(); |
559 | } |
560 | |
561 | //make sure there is no sign |
562 | return integral_as_string( |
563 | date_time::absolute_value(frac_sec), |
564 | time_duration_type::num_fractional_digits()); |
565 | } |
566 | |
567 | static |
568 | string_type |
569 | hours_as_string(const time_duration_type& time_arg, int width = 2) |
570 | { |
571 | return integral_as_string(date_time::absolute_value(time_arg.hours()), width); |
572 | } |
573 | |
574 | template< typename IntT > |
575 | static |
576 | string_type |
577 | integral_as_string(IntT val, int width = 2) |
578 | { |
579 | std::basic_ostringstream<char_type> ss; |
580 | ss.imbue(std::locale::classic()); // don't want any formatting |
581 | ss << std::setw(width) |
582 | << std::setfill(static_cast<char_type>('0')); |
583 | #if (defined(BOOST_MSVC) && (_MSC_VER < 1300)) |
584 | // JDG [7/6/02 VC++ compatibility] |
585 | char_type buff[34]; |
586 | ss << _i64toa(static_cast<boost::int64_t>(val), buff, 10); |
587 | #else |
588 | ss << val; |
589 | #endif |
590 | return ss.str(); |
591 | } |
592 | |
593 | private: |
594 | string_type m_time_duration_format; |
595 | |
596 | }; |
597 | |
598 | template <class time_type, class CharT, class OutItrT> |
599 | std::locale::id time_facet<time_type, CharT, OutItrT>::id; |
600 | |
601 | template <class time_type, class CharT, class OutItrT> |
602 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
603 | time_facet<time_type, CharT, OutItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format; |
604 | |
605 | template <class time_type, class CharT, class OutItrT> |
606 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
607 | time_facet<time_type, CharT, OutItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format; |
608 | |
609 | template <class time_type, class CharT, class OutItrT> |
610 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
611 | time_facet<time_type, CharT, OutItrT>::seconds_with_fractional_seconds_format = |
612 | time_formats<CharT>::seconds_with_fractional_seconds_format; |
613 | |
614 | |
615 | template <class time_type, class CharT, class OutItrT> |
616 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
617 | time_facet<time_type, CharT, OutItrT>::zone_name_format = time_formats<CharT>::zone_name_format; |
618 | |
619 | template <class time_type, class CharT, class OutItrT> |
620 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
621 | time_facet<time_type, CharT, OutItrT>::zone_abbrev_format = time_formats<CharT>::zone_abbrev_format; |
622 | |
623 | template <class time_type, class CharT, class OutItrT> |
624 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
625 | time_facet<time_type, CharT, OutItrT>::zone_iso_extended_format =time_formats<CharT>::zone_iso_extended_format; |
626 | |
627 | template <class time_type, class CharT, class OutItrT> |
628 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
629 | time_facet<time_type, CharT, OutItrT>::posix_zone_string_format =time_formats<CharT>::posix_zone_string_format; |
630 | |
631 | template <class time_type, class CharT, class OutItrT> |
632 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
633 | time_facet<time_type, CharT, OutItrT>::zone_iso_format = time_formats<CharT>::zone_iso_format; |
634 | |
635 | template <class time_type, class CharT, class OutItrT> |
636 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
637 | time_facet<time_type, CharT, OutItrT>::seconds_format = time_formats<CharT>::seconds_format; |
638 | |
639 | template <class time_type, class CharT, class OutItrT> |
640 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
641 | time_facet<time_type, CharT, OutItrT>::hours_format = time_formats<CharT>::hours_format; |
642 | |
643 | template <class time_type, class CharT, class OutItrT> |
644 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
645 | time_facet<time_type, CharT, OutItrT>::unrestricted_hours_format = time_formats<CharT>::unrestricted_hours_format; |
646 | |
647 | template <class time_type, class CharT, class OutItrT> |
648 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
649 | time_facet<time_type, CharT, OutItrT>::standard_format = time_formats<CharT>::standard_format; |
650 | |
651 | template <class time_type, class CharT, class OutItrT> |
652 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
653 | time_facet<time_type, CharT, OutItrT>::duration_seperator = time_formats<CharT>::duration_seperator; |
654 | |
655 | template <class time_type, class CharT, class OutItrT> |
656 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
657 | time_facet<time_type, CharT, OutItrT>::negative_sign = time_formats<CharT>::negative_sign; |
658 | |
659 | template <class time_type, class CharT, class OutItrT> |
660 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
661 | time_facet<time_type, CharT, OutItrT>::positive_sign = time_formats<CharT>::positive_sign; |
662 | |
663 | template <class time_type, class CharT, class OutItrT> |
664 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
665 | time_facet<time_type, CharT, OutItrT>::duration_sign_negative_only = time_formats<CharT>::duration_sign_negative_only; |
666 | |
667 | template <class time_type, class CharT, class OutItrT> |
668 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
669 | time_facet<time_type, CharT, OutItrT>::duration_sign_always = time_formats<CharT>::duration_sign_always; |
670 | |
671 | template <class time_type, class CharT, class OutItrT> |
672 | const typename time_facet<time_type,CharT, OutItrT>::char_type* |
673 | time_facet<time_type,CharT, OutItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier; |
674 | |
675 | template <class time_type, class CharT, class OutItrT> |
676 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
677 | time_facet<time_type, CharT, OutItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier; |
678 | |
679 | template <class time_type, class CharT, class OutItrT> |
680 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
681 | time_facet<time_type, CharT, OutItrT>::default_time_format = |
682 | time_formats<CharT>::default_time_format; |
683 | |
684 | template <class time_type, class CharT, class OutItrT> |
685 | const typename time_facet<time_type, CharT, OutItrT>::char_type* |
686 | time_facet<time_type, CharT, OutItrT>::default_time_duration_format = |
687 | time_formats<CharT>::default_time_duration_format; |
688 | |
689 | |
690 | //! Facet for format-based input. |
691 | /*! |
692 | */ |
693 | template <class time_type, |
694 | class CharT, |
695 | class InItrT = std::istreambuf_iterator<CharT, std::char_traits<CharT> > > |
696 | class time_input_facet : |
697 | public boost::date_time::date_input_facet<typename time_type::date_type , CharT, InItrT> { |
698 | public: |
699 | typedef typename time_type::date_type date_type; |
700 | typedef typename time_type::time_duration_type time_duration_type; |
701 | typedef typename time_duration_type::fractional_seconds_type fracional_seconds_type; |
702 | typedef boost::date_time::period<time_type,time_duration_type> period_type; |
703 | typedef boost::date_time::date_input_facet<typename time_type::date_type, CharT, InItrT> base_type; |
704 | typedef typename base_type::duration_type date_duration_type; |
705 | typedef typename base_type::year_type year_type; |
706 | typedef typename base_type::month_type month_type; |
707 | typedef typename base_type::day_type day_type; |
708 | typedef typename base_type::string_type string_type; |
709 | typedef typename string_type::const_iterator const_itr; |
710 | typedef typename base_type::char_type char_type; |
711 | typedef typename base_type::format_date_parser_type format_date_parser_type; |
712 | typedef typename base_type::period_parser_type period_parser_type; |
713 | typedef typename base_type::special_values_parser_type special_values_parser_type; |
714 | typedef typename base_type::date_gen_parser_type date_gen_parser_type; |
715 | typedef typename base_type::special_values_parser_type::match_results match_results; |
716 | |
717 | static const char_type* fractional_seconds_format; // f |
718 | static const char_type* fractional_seconds_or_none_format; // F |
719 | static const char_type* seconds_with_fractional_seconds_format; // s |
720 | static const char_type* seconds_format; // S |
721 | static const char_type* standard_format; // x X |
722 | static const char_type* zone_abbrev_format; // z |
723 | static const char_type* zone_name_format; // Z |
724 | static const char_type* zone_iso_format; // q |
725 | static const char_type* zone_iso_extended_format; // Q |
726 | static const char_type* duration_seperator; |
727 | static const char_type* iso_time_format_specifier; |
728 | static const char_type* iso_time_format_extended_specifier; |
729 | static const char_type* default_time_input_format; |
730 | static const char_type* default_time_duration_format; |
731 | static std::locale::id id; |
732 | |
733 | //! Constructor that takes a format string for a ptime |
734 | explicit time_input_facet(const string_type& format, ::size_t ref_arg = 0) |
735 | : base_type(format, ref_arg), |
736 | m_time_duration_format(default_time_duration_format) |
737 | { } |
738 | |
739 | explicit time_input_facet(const string_type& format, |
740 | const format_date_parser_type& date_parser, |
741 | const special_values_parser_type& sv_parser, |
742 | const period_parser_type& per_parser, |
743 | const date_gen_parser_type& date_gen_parser, |
744 | ::size_t ref_arg = 0) |
745 | : base_type(format, |
746 | date_parser, |
747 | sv_parser, |
748 | per_parser, |
749 | date_gen_parser, |
750 | ref_arg), |
751 | m_time_duration_format(default_time_duration_format) |
752 | {} |
753 | |
754 | //! sets default formats for ptime, local_date_time, and time_duration |
755 | explicit time_input_facet(::size_t ref_arg = 0) |
756 | : base_type(default_time_input_format, ref_arg), |
757 | m_time_duration_format(default_time_duration_format) |
758 | { } |
759 | |
760 | //! Set the format for time_duration |
761 | void time_duration_format(const char_type* const format) { |
762 | m_time_duration_format = format; |
763 | } |
764 | virtual void set_iso_format() |
765 | { |
766 | this->m_format = iso_time_format_specifier; |
767 | } |
768 | virtual void set_iso_extended_format() |
769 | { |
770 | this->m_format = iso_time_format_extended_specifier; |
771 | } |
772 | |
773 | InItrT get(InItrT& sitr, |
774 | InItrT& stream_end, |
775 | std::ios_base& ios_arg, |
776 | period_type& p) const |
777 | { |
778 | p = this->m_period_parser.get_period(sitr, |
779 | stream_end, |
780 | ios_arg, |
781 | p, |
782 | time_duration_type::unit(), |
783 | *this); |
784 | return sitr; |
785 | } |
786 | |
787 | //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz] |
788 | //default time_duration format is %H:%M:%S%F HH:MM:SS[.fff...] |
789 | |
790 | InItrT get(InItrT& sitr, |
791 | InItrT& stream_end, |
792 | std::ios_base& ios_arg, |
793 | time_duration_type& td) const |
794 | { |
795 | // skip leading whitespace |
796 | while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; } |
797 | |
798 | bool use_current_char = false; |
799 | |
800 | // num_get will consume the +/-, we may need a copy if special_value |
801 | char_type c = '\0'; |
802 | if((sitr != stream_end) && (*sitr == '-' || *sitr == '+')) { |
803 | c = *sitr; |
804 | } |
805 | |
806 | typedef typename time_duration_type::hour_type hour_type; |
807 | typedef typename time_duration_type::min_type min_type; |
808 | typedef typename time_duration_type::sec_type sec_type; |
809 | |
810 | hour_type hour = 0; |
811 | min_type min = 0; |
812 | sec_type sec = 0; |
813 | typename time_duration_type::fractional_seconds_type frac(0); |
814 | |
815 | typedef std::num_get<CharT, InItrT> num_get; |
816 | if(!std::has_facet<num_get>(ios_arg.getloc())) { |
817 | num_get* ng = new num_get(); |
818 | std::locale loc = std::locale(ios_arg.getloc(), ng); |
819 | ios_arg.imbue(loc: loc); |
820 | } |
821 | |
822 | const_itr itr(m_time_duration_format.begin()); |
823 | while (itr != m_time_duration_format.end() && (sitr != stream_end)) { |
824 | if (*itr == '%') { |
825 | if (++itr == m_time_duration_format.end()) break; |
826 | if (*itr != '%') { |
827 | switch(*itr) { |
828 | case 'O': |
829 | { |
830 | // A period may span more than 24 hours. In that case the format |
831 | // string should be composed with the unrestricted hours specifier. |
832 | hour = var_string_to_int<hour_type, CharT>(sitr, stream_end, |
833 | std::numeric_limits<hour_type>::digits10 + 1); |
834 | if(hour == -1){ |
835 | return check_special_value(sitr, stream_end, td, c); |
836 | } |
837 | break; |
838 | } |
839 | case 'H': |
840 | { |
841 | match_results mr; |
842 | hour = fixed_string_to_int<hour_type, CharT>(sitr, stream_end, mr, 2); |
843 | if(hour == -1){ |
844 | return check_special_value(sitr, stream_end, td, c); |
845 | } |
846 | break; |
847 | } |
848 | case 'M': |
849 | { |
850 | match_results mr; |
851 | min = fixed_string_to_int<min_type, CharT>(sitr, stream_end, mr, 2); |
852 | if(min == -1){ |
853 | return check_special_value(sitr, stream_end, td, c); |
854 | } |
855 | break; |
856 | } |
857 | case 's': |
858 | case 'S': |
859 | { |
860 | match_results mr; |
861 | sec = fixed_string_to_int<sec_type, CharT>(sitr, stream_end, mr, 2); |
862 | if(sec == -1){ |
863 | return check_special_value(sitr, stream_end, td, c); |
864 | } |
865 | if (*itr == 'S') |
866 | break; |
867 | // %s is the same as %S%f so we drop through into %f |
868 | } |
869 | case 'f': |
870 | { |
871 | // check for decimal, check special_values if missing |
872 | if(*sitr == '.') { |
873 | ++sitr; |
874 | parse_frac_type(sitr, stream_end, frac); |
875 | // sitr will point to next expected char after this parsing |
876 | // is complete so no need to advance it |
877 | use_current_char = true; |
878 | } |
879 | else { |
880 | return check_special_value(sitr, stream_end, td, c); |
881 | } |
882 | break; |
883 | } |
884 | case 'F': |
885 | { |
886 | // check for decimal, skip if missing |
887 | if(*sitr == '.') { |
888 | ++sitr; |
889 | parse_frac_type(sitr, stream_end, frac); |
890 | // sitr will point to next expected char after this parsing |
891 | // is complete so no need to advance it |
892 | use_current_char = true; |
893 | } |
894 | else { |
895 | // nothing was parsed so we don't want to advance sitr |
896 | use_current_char = true; |
897 | } |
898 | break; |
899 | } |
900 | default: |
901 | {} // ignore what we don't understand? |
902 | }// switch |
903 | } |
904 | else { // itr == '%', second consecutive |
905 | ++sitr; |
906 | } |
907 | |
908 | ++itr; //advance past format specifier |
909 | } |
910 | else { //skip past chars in format and in buffer |
911 | ++itr; |
912 | // set use_current_char when sitr is already |
913 | // pointing at the next character to process |
914 | if (use_current_char) { |
915 | use_current_char = false; |
916 | } |
917 | else { |
918 | ++sitr; |
919 | } |
920 | } |
921 | } |
922 | |
923 | td = time_duration_type(hour, min, sec, frac); |
924 | return sitr; |
925 | } |
926 | |
927 | |
928 | //! Parses a time object from the input stream |
929 | InItrT get(InItrT& sitr, |
930 | InItrT& stream_end, |
931 | std::ios_base& ios_arg, |
932 | time_type& t) const |
933 | { |
934 | string_type tz_str; |
935 | return get(sitr, stream_end, ios_arg, t, tz_str, false); |
936 | } |
937 | //! Expects a time_zone in the input stream |
938 | InItrT get_local_time(InItrT& sitr, |
939 | InItrT& stream_end, |
940 | std::ios_base& ios_arg, |
941 | time_type& t, |
942 | string_type& tz_str) const |
943 | { |
944 | return get(sitr, stream_end, ios_arg, t, tz_str, true); |
945 | } |
946 | |
947 | protected: |
948 | |
949 | InItrT get(InItrT& sitr, |
950 | InItrT& stream_end, |
951 | std::ios_base& ios_arg, |
952 | time_type& t, |
953 | string_type& tz_str, |
954 | bool time_is_local) const |
955 | { |
956 | // skip leading whitespace |
957 | while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; } |
958 | |
959 | bool use_current_char = false; |
960 | bool use_current_format_char = false; // used whith two character flags |
961 | |
962 | // num_get will consume the +/-, we may need a copy if special_value |
963 | char_type c = '\0'; |
964 | if((sitr != stream_end) && (*sitr == '-' || *sitr == '+')) { |
965 | c = *sitr; |
966 | } |
967 | |
968 | typedef typename time_duration_type::hour_type hour_type; |
969 | typedef typename time_duration_type::min_type min_type; |
970 | typedef typename time_duration_type::sec_type sec_type; |
971 | |
972 | // time elements |
973 | hour_type hour = 0; |
974 | min_type min = 0; |
975 | sec_type sec = 0; |
976 | typename time_duration_type::fractional_seconds_type frac(0); |
977 | // date elements |
978 | short day_of_year(0); |
979 | /* Initialized the following to their minimum values. These intermediate |
980 | * objects are used so we get specific exceptions when part of the input |
981 | * is unparsable. |
982 | * Ex: "205-Jan-15" will throw a bad_year, "2005-Jsn-15"- bad_month, etc.*/ |
983 | year_type t_year(1400); |
984 | month_type t_month(1); |
985 | day_type t_day(1); |
986 | |
987 | typedef std::num_get<CharT, InItrT> num_get; |
988 | if(!std::has_facet<num_get>(ios_arg.getloc())) { |
989 | num_get* ng = new num_get(); |
990 | std::locale loc = std::locale(ios_arg.getloc(), ng); |
991 | ios_arg.imbue(loc: loc); |
992 | } |
993 | |
994 | const_itr itr(this->m_format.begin()); |
995 | while (itr != this->m_format.end() && (sitr != stream_end)) { |
996 | if (*itr == '%') { |
997 | if (++itr == this->m_format.end()) break; |
998 | if (*itr != '%') { |
999 | // the cases are grouped by date & time flags - not alphabetical order |
1000 | switch(*itr) { |
1001 | // date flags |
1002 | case 'Y': |
1003 | case 'y': |
1004 | { |
1005 | char_type cs[3] = { '%', *itr }; |
1006 | string_type s(cs); |
1007 | match_results mr; |
1008 | try { |
1009 | t_year = this->m_parser.parse_year(sitr, stream_end, s, mr); |
1010 | } |
1011 | catch(std::out_of_range&) { // base class for bad_year exception |
1012 | if(this->m_sv_parser.match(sitr, stream_end, mr)) { |
1013 | t = time_type(static_cast<special_values>(mr.current_match)); |
1014 | return sitr; |
1015 | } |
1016 | else { |
1017 | throw; // rethrow bad_year |
1018 | } |
1019 | } |
1020 | break; |
1021 | } |
1022 | case 'B': |
1023 | case 'b': |
1024 | case 'm': |
1025 | { |
1026 | char_type cs[3] = { '%', *itr }; |
1027 | string_type s(cs); |
1028 | match_results mr; |
1029 | try { |
1030 | t_month = this->m_parser.parse_month(sitr, stream_end, s, mr); |
1031 | } |
1032 | catch(std::out_of_range&) { // base class for bad_month exception |
1033 | if(this->m_sv_parser.match(sitr, stream_end, mr)) { |
1034 | t = time_type(static_cast<special_values>(mr.current_match)); |
1035 | return sitr; |
1036 | } |
1037 | else { |
1038 | throw; // rethrow bad_month |
1039 | } |
1040 | } |
1041 | // did m_parser already advance sitr to next char? |
1042 | if(mr.has_remaining()) { |
1043 | use_current_char = true; |
1044 | } |
1045 | break; |
1046 | } |
1047 | case 'a': |
1048 | case 'A': |
1049 | case 'w': |
1050 | { |
1051 | // weekday is not used in construction but we need to get it out of the stream |
1052 | char_type cs[3] = { '%', *itr }; |
1053 | string_type s(cs); |
1054 | match_results mr; |
1055 | typename date_type::day_of_week_type wd(0); |
1056 | try { |
1057 | wd = this->m_parser.parse_weekday(sitr, stream_end, s, mr); |
1058 | } |
1059 | catch(std::out_of_range&) { // base class for bad_weekday exception |
1060 | if(this->m_sv_parser.match(sitr, stream_end, mr)) { |
1061 | t = time_type(static_cast<special_values>(mr.current_match)); |
1062 | return sitr; |
1063 | } |
1064 | else { |
1065 | throw; // rethrow bad_weekday |
1066 | } |
1067 | } |
1068 | // did m_parser already advance sitr to next char? |
1069 | if(mr.has_remaining()) { |
1070 | use_current_char = true; |
1071 | } |
1072 | break; |
1073 | } |
1074 | case 'j': |
1075 | { |
1076 | // code that gets julian day (from format_date_parser) |
1077 | match_results mr; |
1078 | day_of_year = fixed_string_to_int<unsigned short, CharT>(sitr, stream_end, mr, 3); |
1079 | if(day_of_year == -1) { |
1080 | if(this->m_sv_parser.match(sitr, stream_end, mr)) { |
1081 | t = time_type(static_cast<special_values>(mr.current_match)); |
1082 | return sitr; |
1083 | } |
1084 | } |
1085 | // these next two lines are so we get an exception with bad input |
1086 | typedef typename time_type::date_type::day_of_year_type day_of_year_type; |
1087 | day_of_year_type t_day_of_year(day_of_year); |
1088 | break; |
1089 | } |
1090 | case 'd': |
1091 | { |
1092 | try { |
1093 | t_day = this->m_parser.parse_day_of_month(sitr, stream_end); |
1094 | } |
1095 | catch(std::out_of_range&) { // base class for exception bad_day_of_month |
1096 | match_results mr; |
1097 | if(this->m_sv_parser.match(sitr, stream_end, mr)) { |
1098 | t = time_type(static_cast<special_values>(mr.current_match)); |
1099 | return sitr; |
1100 | } |
1101 | else { |
1102 | throw; // rethrow bad_day_of_month |
1103 | } |
1104 | } |
1105 | break; |
1106 | } |
1107 | // time flags |
1108 | case 'H': |
1109 | { |
1110 | match_results mr; |
1111 | hour = fixed_string_to_int<hour_type, CharT>(sitr, stream_end, mr, 2); |
1112 | if(hour == -1){ |
1113 | return check_special_value(sitr, stream_end, t, c); |
1114 | } |
1115 | break; |
1116 | } |
1117 | case 'M': |
1118 | { |
1119 | match_results mr; |
1120 | min = fixed_string_to_int<min_type, CharT>(sitr, stream_end, mr, 2); |
1121 | if(min == -1){ |
1122 | return check_special_value(sitr, stream_end, t, c); |
1123 | } |
1124 | break; |
1125 | } |
1126 | case 's': |
1127 | case 'S': |
1128 | { |
1129 | match_results mr; |
1130 | sec = fixed_string_to_int<sec_type, CharT>(sitr, stream_end, mr, 2); |
1131 | if(sec == -1){ |
1132 | return check_special_value(sitr, stream_end, t, c); |
1133 | } |
1134 | if (*itr == 'S') |
1135 | break; |
1136 | // %s is the same as %S%f so we drop through into %f |
1137 | } |
1138 | case 'f': |
1139 | { |
1140 | // check for decimal, check SV if missing |
1141 | if(*sitr == '.') { |
1142 | ++sitr; |
1143 | parse_frac_type(sitr, stream_end, frac); |
1144 | // sitr will point to next expected char after this parsing |
1145 | // is complete so no need to advance it |
1146 | use_current_char = true; |
1147 | } |
1148 | else { |
1149 | return check_special_value(sitr, stream_end, t, c); |
1150 | } |
1151 | break; |
1152 | } |
1153 | case 'F': |
1154 | { |
1155 | // check for decimal, skip if missing |
1156 | if(*sitr == '.') { |
1157 | ++sitr; |
1158 | parse_frac_type(sitr, stream_end, frac); |
1159 | // sitr will point to next expected char after this parsing |
1160 | // is complete so no need to advance it |
1161 | use_current_char = true; |
1162 | } |
1163 | else { |
1164 | // nothing was parsed so we don't want to advance sitr |
1165 | use_current_char = true; |
1166 | } |
1167 | break; |
1168 | } |
1169 | // time_zone flags |
1170 | //case 'q': |
1171 | //case 'Q': |
1172 | //case 'z': |
1173 | case 'Z': |
1174 | { |
1175 | if(time_is_local) { // skip if 't' is a ptime |
1176 | ++itr; |
1177 | if(*itr == 'P') { |
1178 | // skip leading whitespace |
1179 | while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; } |
1180 | // parse zone |
1181 | while((sitr != stream_end) && (!std::isspace(*sitr))) { |
1182 | tz_str += *sitr; |
1183 | ++sitr; |
1184 | } |
1185 | } |
1186 | else { |
1187 | use_current_format_char = true; |
1188 | } |
1189 | |
1190 | } |
1191 | else { |
1192 | // nothing was parsed so we don't want to advance sitr |
1193 | use_current_char = true; |
1194 | } |
1195 | |
1196 | break; |
1197 | } |
1198 | default: |
1199 | {} // ignore what we don't understand? |
1200 | }// switch |
1201 | } |
1202 | else { // itr == '%', second consecutive |
1203 | ++sitr; |
1204 | } |
1205 | |
1206 | if(use_current_format_char) { |
1207 | use_current_format_char = false; |
1208 | } |
1209 | else { |
1210 | ++itr; //advance past format specifier |
1211 | } |
1212 | |
1213 | } |
1214 | else { //skip past chars in format and in buffer |
1215 | ++itr; |
1216 | // set use_current_char when sitr is already |
1217 | // pointing at the next character to process |
1218 | if (use_current_char) { |
1219 | use_current_char = false; |
1220 | } |
1221 | else { |
1222 | ++sitr; |
1223 | } |
1224 | } |
1225 | } |
1226 | |
1227 | date_type d(not_a_date_time); |
1228 | if (day_of_year > 0) { |
1229 | d = date_type(static_cast<unsigned short>(t_year-1),12,31) + date_duration_type(day_of_year); |
1230 | } |
1231 | else { |
1232 | d = date_type(t_year, t_month, t_day); |
1233 | } |
1234 | |
1235 | time_duration_type td(hour, min, sec, frac); |
1236 | t = time_type(d, td); |
1237 | return sitr; |
1238 | } |
1239 | |
1240 | //! Helper function to check for special_value |
1241 | /*! First character may have been consumed during original parse |
1242 | * attempt. Parameter 'c' should be a copy of that character. |
1243 | * Throws ios_base::failure if parse fails. */ |
1244 | template<class temporal_type> |
1245 | inline |
1246 | InItrT check_special_value(InItrT& sitr,InItrT& stream_end, temporal_type& tt, char_type c='\0') const |
1247 | { |
1248 | match_results mr; |
1249 | if((c == '-' || c == '+') && (*sitr != c)) { // was the first character consumed? |
1250 | mr.cache += c; |
1251 | } |
1252 | this->m_sv_parser.match(sitr, stream_end, mr); |
1253 | if(mr.current_match == match_results::PARSE_ERROR) { |
1254 | std::string tmp = convert_string_type<char_type, char>(mr.cache); |
1255 | boost::throw_exception(e: std::ios_base::failure("Parse failed. No match found for '" + tmp + "'" )); |
1256 | BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(return sitr); // should never reach |
1257 | } |
1258 | tt = temporal_type(static_cast<special_values>(mr.current_match)); |
1259 | return sitr; |
1260 | } |
1261 | |
1262 | //! Helper function for parsing a fractional second type from the stream |
1263 | void parse_frac_type(InItrT& sitr, |
1264 | InItrT& stream_end, |
1265 | fracional_seconds_type& frac) const |
1266 | { |
1267 | string_type cache; |
1268 | while((sitr != stream_end) && std::isdigit(*sitr)) { |
1269 | cache += *sitr; |
1270 | ++sitr; |
1271 | } |
1272 | if(cache.size() > 0) { |
1273 | unsigned short precision = time_duration_type::num_fractional_digits(); |
1274 | // input may be only the first few decimal places |
1275 | if(cache.size() < precision) { |
1276 | frac = lexical_cast<fracional_seconds_type>(cache); |
1277 | frac = decimal_adjust(frac, static_cast<unsigned short>(precision - cache.size())); |
1278 | } |
1279 | else { |
1280 | // if input has too many decimal places, drop excess digits |
1281 | frac = lexical_cast<fracional_seconds_type>(cache.substr(0, precision)); |
1282 | } |
1283 | } |
1284 | } |
1285 | |
1286 | private: |
1287 | string_type m_time_duration_format; |
1288 | |
1289 | //! Helper function to adjust trailing zeros when parsing fractional digits |
1290 | template<class int_type> |
1291 | inline |
1292 | int_type decimal_adjust(int_type val, const unsigned short places) const |
1293 | { |
1294 | unsigned long factor = 1; |
1295 | for(int i = 0; i < places; ++i){ |
1296 | factor *= 10; // shift decimal to the right |
1297 | } |
1298 | return val * factor; |
1299 | } |
1300 | |
1301 | }; |
1302 | |
1303 | template <class time_type, class CharT, class InItrT> |
1304 | std::locale::id time_input_facet<time_type, CharT, InItrT>::id; |
1305 | |
1306 | template <class time_type, class CharT, class InItrT> |
1307 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1308 | time_input_facet<time_type, CharT, InItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format; |
1309 | |
1310 | template <class time_type, class CharT, class InItrT> |
1311 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1312 | time_input_facet<time_type, CharT, InItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format; |
1313 | |
1314 | template <class time_type, class CharT, class InItrT> |
1315 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1316 | time_input_facet<time_type, CharT, InItrT>::seconds_with_fractional_seconds_format = time_formats<CharT>::seconds_with_fractional_seconds_format; |
1317 | |
1318 | template <class time_type, class CharT, class InItrT> |
1319 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1320 | time_input_facet<time_type, CharT, InItrT>::seconds_format = time_formats<CharT>::seconds_format; |
1321 | |
1322 | template <class time_type, class CharT, class InItrT> |
1323 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1324 | time_input_facet<time_type, CharT, InItrT>::standard_format = time_formats<CharT>::standard_format; |
1325 | |
1326 | template <class time_type, class CharT, class InItrT> |
1327 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1328 | time_input_facet<time_type, CharT, InItrT>::zone_abbrev_format = time_formats<CharT>::zone_abbrev_format; |
1329 | |
1330 | template <class time_type, class CharT, class InItrT> |
1331 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1332 | time_input_facet<time_type, CharT, InItrT>::zone_name_format = time_formats<CharT>::zone_name_format; |
1333 | |
1334 | template <class time_type, class CharT, class InItrT> |
1335 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1336 | time_input_facet<time_type, CharT, InItrT>::zone_iso_format = time_formats<CharT>::zone_iso_format; |
1337 | |
1338 | template <class time_type, class CharT, class InItrT> |
1339 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1340 | time_input_facet<time_type, CharT, InItrT>::zone_iso_extended_format = time_formats<CharT>::zone_iso_extended_format; |
1341 | |
1342 | template <class time_type, class CharT, class InItrT> |
1343 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1344 | time_input_facet<time_type, CharT, InItrT>::duration_seperator = time_formats<CharT>::duration_seperator; |
1345 | |
1346 | template <class time_type, class CharT, class InItrT> |
1347 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1348 | time_input_facet<time_type, CharT, InItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier; |
1349 | |
1350 | template <class time_type, class CharT, class InItrT> |
1351 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1352 | time_input_facet<time_type, CharT, InItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier; |
1353 | |
1354 | template <class time_type, class CharT, class InItrT> |
1355 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1356 | time_input_facet<time_type, CharT, InItrT>::default_time_input_format = time_formats<CharT>::default_time_input_format; |
1357 | |
1358 | template <class time_type, class CharT, class InItrT> |
1359 | const typename time_input_facet<time_type, CharT, InItrT>::char_type* |
1360 | time_input_facet<time_type, CharT, InItrT>::default_time_duration_format = time_formats<CharT>::default_time_duration_format; |
1361 | |
1362 | |
1363 | } } // namespaces |
1364 | |
1365 | |
1366 | #endif |
1367 | |
1368 | |