Line data Source code
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 BOOST_SYMBOL_VISIBLE 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 0 : 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 0 : m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format)
250 0 : {}
251 :
252 : //! Construct the facet with an explicitly specified format
253 0 : 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 0 : m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format)
264 0 : {}
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 0 : virtual void set_iso_format()
273 : {
274 0 : this->m_format = iso_time_format_specifier;
275 0 : }
276 0 : virtual void set_iso_extended_format()
277 : {
278 0 : this->m_format = iso_time_format_extended_specifier;
279 0 : }
280 :
281 0 : 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 0 : if (time_arg.is_special()) {
287 : return this->do_put_special(next_arg, ios_arg, fill_arg,
288 0 : time_arg.date().as_special());
289 : }
290 0 : string_type local_format(this->m_format);
291 :
292 : // %T and %R have to be replaced here since they are not standard
293 0 : boost::algorithm::replace_all(local_format,
294 0 : boost::as_literal(formats_type::full_24_hour_time_format),
295 0 : boost::as_literal(formats_type::full_24_hour_time_expanded_format));
296 0 : boost::algorithm::replace_all(local_format,
297 0 : boost::as_literal(formats_type::short_24_hour_time_format),
298 0 : boost::as_literal(formats_type::short_24_hour_time_expanded_format));
299 :
300 0 : string_type frac_str;
301 0 : if (local_format.find(seconds_with_fractional_seconds_format) != string_type::npos) {
302 : // replace %s with %S.nnn
303 0 : frac_str =
304 : fractional_seconds_as_string(time_arg.time_of_day(), false);
305 0 : char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
306 :
307 0 : string_type replace_string(seconds_format);
308 0 : replace_string += sep;
309 0 : replace_string += frac_str;
310 0 : 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 0 : if (local_format.find(posix_zone_string_format) != string_type::npos) {
318 0 : 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 0 : boost::algorithm::erase_all(local_format, posix_zone_string_format);
322 : }
323 : else{
324 0 : boost::algorithm::replace_all(local_format,
325 : posix_zone_string_format,
326 : time_arg.zone_as_posix_string());
327 : }
328 : }
329 0 : if (local_format.find(zone_name_format) != string_type::npos) {
330 0 : 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 0 : std::basic_ostringstream<char_type> ss;
338 0 : ss << ' ' << zone_name_format;
339 0 : boost::algorithm::erase_all(local_format, ss.str());
340 : }
341 : else{
342 0 : boost::algorithm::replace_all(local_format,
343 : zone_name_format,
344 : time_arg.zone_name());
345 : }
346 : }
347 0 : if (local_format.find(zone_abbrev_format) != string_type::npos) {
348 0 : 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 0 : std::basic_ostringstream<char_type> ss;
356 0 : ss << ' ' << zone_abbrev_format;
357 0 : boost::algorithm::erase_all(local_format, ss.str());
358 : }
359 : else{
360 0 : boost::algorithm::replace_all(local_format,
361 : zone_abbrev_format,
362 : time_arg.zone_abbrev(false));
363 : }
364 : }
365 0 : if (local_format.find(zone_iso_extended_format) != string_type::npos) {
366 0 : 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 0 : boost::algorithm::erase_all(local_format, zone_iso_extended_format);
374 : }
375 : else{
376 0 : boost::algorithm::replace_all(local_format,
377 : zone_iso_extended_format,
378 : time_arg.zone_name(true));
379 : }
380 : }
381 :
382 0 : if (local_format.find(zone_iso_format) != string_type::npos) {
383 0 : 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 0 : boost::algorithm::erase_all(local_format, zone_iso_format);
391 : }
392 : else{
393 0 : boost::algorithm::replace_all(local_format,
394 : zone_iso_format,
395 : time_arg.zone_abbrev(true));
396 : }
397 : }
398 0 : if (local_format.find(fractional_seconds_format) != string_type::npos) {
399 : // replace %f with nnnnnnn
400 0 : if (frac_str.empty()) {
401 0 : frac_str = fractional_seconds_as_string(time_arg.time_of_day(), false);
402 : }
403 0 : boost::algorithm::replace_all(local_format,
404 : fractional_seconds_format,
405 : frac_str);
406 : }
407 :
408 0 : if (local_format.find(fractional_seconds_or_none_format) != string_type::npos) {
409 : // replace %F with nnnnnnn or nothing if fs == 0
410 0 : frac_str =
411 : fractional_seconds_as_string(time_arg.time_of_day(), true);
412 0 : if (frac_str.size()) {
413 0 : char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
414 0 : string_type replace_string;
415 0 : replace_string += sep;
416 0 : replace_string += frac_str;
417 0 : boost::algorithm::replace_all(local_format,
418 : fractional_seconds_or_none_format,
419 : replace_string);
420 : }
421 : else {
422 0 : 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 0 : 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_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_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_dur_arg, 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_dur_arg, 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_dur_arg, 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 0 : fractional_seconds_as_string(const time_duration_type& time_arg,
552 : bool null_when_zero)
553 : {
554 0 : typename time_duration_type::fractional_seconds_type frac_sec =
555 : time_arg.fractional_seconds();
556 :
557 0 : if (null_when_zero && (frac_sec == 0)) {
558 0 : 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 0 : 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 0 : integral_as_string(IntT val, int width = 2)
578 : {
579 0 : std::basic_ostringstream<char_type> ss;
580 0 : ss.imbue(std::locale::classic()); // don't want any formatting
581 : ss << std::setw(width)
582 0 : << 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 0 : ss << val;
589 : #endif
590 0 : 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 BOOST_SYMBOL_VISIBLE 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);
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 : /* Falls through. */
870 : case 'f':
871 : {
872 : // check for decimal, check special_values if missing
873 : if(*sitr == '.') {
874 : ++sitr;
875 : parse_frac_type(sitr, stream_end, frac);
876 : // sitr will point to next expected char after this parsing
877 : // is complete so no need to advance it
878 : use_current_char = true;
879 : }
880 : else {
881 : return check_special_value(sitr, stream_end, td, c);
882 : }
883 : break;
884 : }
885 : case 'F':
886 : {
887 : // check for decimal, skip if missing
888 : if(*sitr == '.') {
889 : ++sitr;
890 : parse_frac_type(sitr, stream_end, frac);
891 : // sitr will point to next expected char after this parsing
892 : // is complete so no need to advance it
893 : use_current_char = true;
894 : }
895 : else {
896 : // nothing was parsed so we don't want to advance sitr
897 : use_current_char = true;
898 : }
899 : break;
900 : }
901 : default:
902 : {} // ignore what we don't understand?
903 : }// switch
904 : }
905 : else { // itr == '%', second consecutive
906 : ++sitr;
907 : }
908 :
909 : ++itr; //advance past format specifier
910 : }
911 : else { //skip past chars in format and in buffer
912 : ++itr;
913 : // set use_current_char when sitr is already
914 : // pointing at the next character to process
915 : if (use_current_char) {
916 : use_current_char = false;
917 : }
918 : else {
919 : ++sitr;
920 : }
921 : }
922 : }
923 :
924 : td = time_duration_type(hour, min, sec, frac);
925 : return sitr;
926 : }
927 :
928 :
929 : //! Parses a time object from the input stream
930 : InItrT get(InItrT& sitr,
931 : InItrT& stream_end,
932 : std::ios_base& ios_arg,
933 : time_type& t) const
934 : {
935 : string_type tz_str;
936 : return get(sitr, stream_end, ios_arg, t, tz_str, false);
937 : }
938 : //! Expects a time_zone in the input stream
939 : InItrT get_local_time(InItrT& sitr,
940 : InItrT& stream_end,
941 : std::ios_base& ios_arg,
942 : time_type& t,
943 : string_type& tz_str) const
944 : {
945 : return get(sitr, stream_end, ios_arg, t, tz_str, true);
946 : }
947 :
948 : protected:
949 :
950 : InItrT get(InItrT& sitr,
951 : InItrT& stream_end,
952 : std::ios_base& ios_arg,
953 : time_type& t,
954 : string_type& tz_str,
955 : bool time_is_local) const
956 : {
957 : // skip leading whitespace
958 : while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; }
959 :
960 : bool use_current_char = false;
961 : bool use_current_format_char = false; // used whith two character flags
962 :
963 : // num_get will consume the +/-, we may need a copy if special_value
964 : char_type c = '\0';
965 : if((sitr != stream_end) && (*sitr == '-' || *sitr == '+')) {
966 : c = *sitr;
967 : }
968 :
969 : typedef typename time_duration_type::hour_type hour_type;
970 : typedef typename time_duration_type::min_type min_type;
971 : typedef typename time_duration_type::sec_type sec_type;
972 :
973 : // time elements
974 : hour_type hour = 0;
975 : min_type min = 0;
976 : sec_type sec = 0;
977 : typename time_duration_type::fractional_seconds_type frac(0);
978 : // date elements
979 : short day_of_year(0);
980 : /* Initialized the following to their minimum values. These intermediate
981 : * objects are used so we get specific exceptions when part of the input
982 : * is unparsable.
983 : * Ex: "205-Jan-15" will throw a bad_year, "2005-Jsn-15"- bad_month, etc.*/
984 : year_type t_year(1400);
985 : month_type t_month(1);
986 : day_type t_day(1);
987 :
988 : typedef std::num_get<CharT, InItrT> num_get;
989 : if(!std::has_facet<num_get>(ios_arg.getloc())) {
990 : num_get* ng = new num_get();
991 : std::locale loc = std::locale(ios_arg.getloc(), ng);
992 : ios_arg.imbue(loc);
993 : }
994 :
995 : const_itr itr(this->m_format.begin());
996 : while (itr != this->m_format.end() && (sitr != stream_end)) {
997 : if (*itr == '%') {
998 : if (++itr == this->m_format.end()) break;
999 : if (*itr != '%') {
1000 : // the cases are grouped by date & time flags - not alphabetical order
1001 : switch(*itr) {
1002 : // date flags
1003 : case 'Y':
1004 : case 'y':
1005 : {
1006 : char_type cs[3] = { '%', *itr };
1007 : string_type s(cs);
1008 : match_results mr;
1009 : try {
1010 : t_year = this->m_parser.parse_year(sitr, stream_end, s, mr);
1011 : }
1012 : catch(std::out_of_range&) { // base class for bad_year exception
1013 : if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1014 : t = time_type(static_cast<special_values>(mr.current_match));
1015 : return sitr;
1016 : }
1017 : else {
1018 : throw; // rethrow bad_year
1019 : }
1020 : }
1021 : break;
1022 : }
1023 : case 'B':
1024 : case 'b':
1025 : case 'm':
1026 : {
1027 : char_type cs[3] = { '%', *itr };
1028 : string_type s(cs);
1029 : match_results mr;
1030 : try {
1031 : t_month = this->m_parser.parse_month(sitr, stream_end, s, mr);
1032 : }
1033 : catch(std::out_of_range&) { // base class for bad_month exception
1034 : if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1035 : t = time_type(static_cast<special_values>(mr.current_match));
1036 : return sitr;
1037 : }
1038 : else {
1039 : throw; // rethrow bad_month
1040 : }
1041 : }
1042 : // did m_parser already advance sitr to next char?
1043 : if(mr.has_remaining()) {
1044 : use_current_char = true;
1045 : }
1046 : break;
1047 : }
1048 : case 'a':
1049 : case 'A':
1050 : case 'w':
1051 : {
1052 : // weekday is not used in construction but we need to get it out of the stream
1053 : char_type cs[3] = { '%', *itr };
1054 : string_type s(cs);
1055 : match_results mr;
1056 : typename date_type::day_of_week_type wd(0);
1057 : try {
1058 : wd = this->m_parser.parse_weekday(sitr, stream_end, s, mr);
1059 : }
1060 : catch(std::out_of_range&) { // base class for bad_weekday exception
1061 : if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1062 : t = time_type(static_cast<special_values>(mr.current_match));
1063 : return sitr;
1064 : }
1065 : else {
1066 : throw; // rethrow bad_weekday
1067 : }
1068 : }
1069 : // did m_parser already advance sitr to next char?
1070 : if(mr.has_remaining()) {
1071 : use_current_char = true;
1072 : }
1073 : break;
1074 : }
1075 : case 'j':
1076 : {
1077 : // code that gets julian day (from format_date_parser)
1078 : match_results mr;
1079 : day_of_year = fixed_string_to_int<unsigned short, CharT>(sitr, stream_end, mr, 3);
1080 : if(day_of_year == -1) {
1081 : if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1082 : t = time_type(static_cast<special_values>(mr.current_match));
1083 : return sitr;
1084 : }
1085 : }
1086 : // these next two lines are so we get an exception with bad input
1087 : typedef typename time_type::date_type::day_of_year_type day_of_year_type;
1088 : day_of_year_type t_day_of_year(day_of_year);
1089 : break;
1090 : }
1091 : case 'd':
1092 : case 'e':
1093 : {
1094 : try {
1095 : t_day = (*itr == 'd') ?
1096 : this->m_parser.parse_day_of_month(sitr, stream_end) :
1097 : this->m_parser.parse_var_day_of_month(sitr, stream_end);
1098 : }
1099 : catch(std::out_of_range&) { // base class for exception bad_day_of_month
1100 : match_results mr;
1101 : if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1102 : t = time_type(static_cast<special_values>(mr.current_match));
1103 : return sitr;
1104 : }
1105 : else {
1106 : throw; // rethrow bad_day_of_month
1107 : }
1108 : }
1109 : break;
1110 : }
1111 : // time flags
1112 : case 'H':
1113 : {
1114 : match_results mr;
1115 : hour = fixed_string_to_int<hour_type, CharT>(sitr, stream_end, mr, 2);
1116 : if(hour == -1){
1117 : return check_special_value(sitr, stream_end, t, c);
1118 : }
1119 : break;
1120 : }
1121 : case 'M':
1122 : {
1123 : match_results mr;
1124 : min = fixed_string_to_int<min_type, CharT>(sitr, stream_end, mr, 2);
1125 : if(min == -1){
1126 : return check_special_value(sitr, stream_end, t, c);
1127 : }
1128 : break;
1129 : }
1130 : case 's':
1131 : case 'S':
1132 : {
1133 : match_results mr;
1134 : sec = fixed_string_to_int<sec_type, CharT>(sitr, stream_end, mr, 2);
1135 : if(sec == -1){
1136 : return check_special_value(sitr, stream_end, t, c);
1137 : }
1138 : if (*itr == 'S' || sitr == stream_end)
1139 : break;
1140 : // %s is the same as %S%f so we drop through into %f if we are
1141 : // not at the end of the stream
1142 : }
1143 : /* Falls through. */
1144 : case 'f':
1145 : {
1146 : // check for decimal, check SV if missing
1147 : if(*sitr == '.') {
1148 : ++sitr;
1149 : parse_frac_type(sitr, stream_end, frac);
1150 : // sitr will point to next expected char after this parsing
1151 : // is complete so no need to advance it
1152 : use_current_char = true;
1153 : }
1154 : else {
1155 : return check_special_value(sitr, stream_end, t, c);
1156 : }
1157 : break;
1158 : }
1159 : case 'F':
1160 : {
1161 : // check for decimal, skip if missing
1162 : if(*sitr == '.') {
1163 : ++sitr;
1164 : parse_frac_type(sitr, stream_end, frac);
1165 : // sitr will point to next expected char after this parsing
1166 : // is complete so no need to advance it
1167 : use_current_char = true;
1168 : }
1169 : else {
1170 : // nothing was parsed so we don't want to advance sitr
1171 : use_current_char = true;
1172 : }
1173 : break;
1174 : }
1175 : // time_zone flags
1176 : //case 'q':
1177 : //case 'Q':
1178 : //case 'z':
1179 : case 'Z':
1180 : {
1181 : if(time_is_local) { // skip if 't' is a ptime
1182 : ++itr;
1183 : if(*itr == 'P') {
1184 : // skip leading whitespace
1185 : while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; }
1186 : // parse zone
1187 : while((sitr != stream_end) && (!std::isspace(*sitr))) {
1188 : tz_str += *sitr;
1189 : ++sitr;
1190 : }
1191 : }
1192 : else {
1193 : use_current_format_char = true;
1194 : }
1195 :
1196 : }
1197 : else {
1198 : // nothing was parsed so we don't want to advance sitr
1199 : use_current_char = true;
1200 : }
1201 :
1202 : break;
1203 : }
1204 : default:
1205 : {} // ignore what we don't understand?
1206 : }// switch
1207 : }
1208 : else { // itr == '%', second consecutive
1209 : ++sitr;
1210 : }
1211 :
1212 : if(use_current_format_char) {
1213 : use_current_format_char = false;
1214 : }
1215 : else {
1216 : ++itr; //advance past format specifier
1217 : }
1218 :
1219 : }
1220 : else { //skip past chars in format and in buffer
1221 : ++itr;
1222 : // set use_current_char when sitr is already
1223 : // pointing at the next character to process
1224 : if (use_current_char) {
1225 : use_current_char = false;
1226 : }
1227 : else {
1228 : ++sitr;
1229 : }
1230 : }
1231 : }
1232 :
1233 : date_type d(not_a_date_time);
1234 : if (day_of_year > 0) {
1235 : d = date_type(static_cast<unsigned short>(t_year),1,1) + date_duration_type(day_of_year-1);
1236 : }
1237 : else {
1238 : d = date_type(t_year, t_month, t_day);
1239 : }
1240 :
1241 : time_duration_type td(hour, min, sec, frac);
1242 : t = time_type(d, td);
1243 : return sitr;
1244 : }
1245 :
1246 : //! Helper function to check for special_value
1247 : /*! First character may have been consumed during original parse
1248 : * attempt. Parameter 'c' should be a copy of that character.
1249 : * Throws ios_base::failure if parse fails. */
1250 : template<class temporal_type>
1251 : inline
1252 : InItrT check_special_value(InItrT& sitr,InItrT& stream_end, temporal_type& tt, char_type c='\0') const
1253 : {
1254 : match_results mr;
1255 : if((c == '-' || c == '+') && (*sitr != c)) { // was the first character consumed?
1256 : mr.cache += c;
1257 : }
1258 : (void)this->m_sv_parser.match(sitr, stream_end, mr);
1259 : if(mr.current_match == match_results::PARSE_ERROR) {
1260 : std::string tmp = convert_string_type<char_type, char>(mr.cache);
1261 : boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + tmp + "'"));
1262 : BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(return sitr); // should never reach
1263 : }
1264 : tt = temporal_type(static_cast<special_values>(mr.current_match));
1265 : return sitr;
1266 : }
1267 :
1268 : //! Helper function for parsing a fractional second type from the stream
1269 : void parse_frac_type(InItrT& sitr,
1270 : InItrT& stream_end,
1271 : fracional_seconds_type& frac) const
1272 : {
1273 : string_type cache;
1274 : while((sitr != stream_end) && std::isdigit(*sitr)) {
1275 : cache += *sitr;
1276 : ++sitr;
1277 : }
1278 : if(cache.size() > 0) {
1279 : unsigned short precision = time_duration_type::num_fractional_digits();
1280 : // input may be only the first few decimal places
1281 : if(cache.size() < precision) {
1282 : frac = lexical_cast<fracional_seconds_type>(cache);
1283 : frac = decimal_adjust(frac, static_cast<unsigned short>(precision - cache.size()));
1284 : }
1285 : else {
1286 : // if input has too many decimal places, drop excess digits
1287 : frac = lexical_cast<fracional_seconds_type>(cache.substr(0, precision));
1288 : }
1289 : }
1290 : }
1291 :
1292 : private:
1293 : string_type m_time_duration_format;
1294 :
1295 : //! Helper function to adjust trailing zeros when parsing fractional digits
1296 : template<class int_type>
1297 : inline
1298 : int_type decimal_adjust(int_type val, const unsigned short places) const
1299 : {
1300 : unsigned long factor = 1;
1301 : for(int i = 0; i < places; ++i){
1302 : factor *= 10; // shift decimal to the right
1303 : }
1304 : return val * factor;
1305 : }
1306 :
1307 : };
1308 :
1309 : template <class time_type, class CharT, class InItrT>
1310 : std::locale::id time_input_facet<time_type, CharT, InItrT>::id;
1311 :
1312 : template <class time_type, class CharT, class InItrT>
1313 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1314 : time_input_facet<time_type, CharT, InItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format;
1315 :
1316 : template <class time_type, class CharT, class InItrT>
1317 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1318 : time_input_facet<time_type, CharT, InItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format;
1319 :
1320 : template <class time_type, class CharT, class InItrT>
1321 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1322 : time_input_facet<time_type, CharT, InItrT>::seconds_with_fractional_seconds_format = time_formats<CharT>::seconds_with_fractional_seconds_format;
1323 :
1324 : template <class time_type, class CharT, class InItrT>
1325 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1326 : time_input_facet<time_type, CharT, InItrT>::seconds_format = time_formats<CharT>::seconds_format;
1327 :
1328 : template <class time_type, class CharT, class InItrT>
1329 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1330 : time_input_facet<time_type, CharT, InItrT>::standard_format = time_formats<CharT>::standard_format;
1331 :
1332 : template <class time_type, class CharT, class InItrT>
1333 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1334 : time_input_facet<time_type, CharT, InItrT>::zone_abbrev_format = time_formats<CharT>::zone_abbrev_format;
1335 :
1336 : template <class time_type, class CharT, class InItrT>
1337 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1338 : time_input_facet<time_type, CharT, InItrT>::zone_name_format = time_formats<CharT>::zone_name_format;
1339 :
1340 : template <class time_type, class CharT, class InItrT>
1341 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1342 : time_input_facet<time_type, CharT, InItrT>::zone_iso_format = time_formats<CharT>::zone_iso_format;
1343 :
1344 : template <class time_type, class CharT, class InItrT>
1345 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1346 : time_input_facet<time_type, CharT, InItrT>::zone_iso_extended_format = time_formats<CharT>::zone_iso_extended_format;
1347 :
1348 : template <class time_type, class CharT, class InItrT>
1349 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1350 : time_input_facet<time_type, CharT, InItrT>::duration_seperator = time_formats<CharT>::duration_seperator;
1351 :
1352 : template <class time_type, class CharT, class InItrT>
1353 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1354 : time_input_facet<time_type, CharT, InItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier;
1355 :
1356 : template <class time_type, class CharT, class InItrT>
1357 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1358 : time_input_facet<time_type, CharT, InItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier;
1359 :
1360 : template <class time_type, class CharT, class InItrT>
1361 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1362 : time_input_facet<time_type, CharT, InItrT>::default_time_input_format = time_formats<CharT>::default_time_input_format;
1363 :
1364 : template <class time_type, class CharT, class InItrT>
1365 : const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1366 : time_input_facet<time_type, CharT, InItrT>::default_time_duration_format = time_formats<CharT>::default_time_duration_format;
1367 :
1368 :
1369 : } } // namespaces
1370 :
1371 :
1372 : #endif
1373 :
|