Update contrib.
2 #ifndef _DATE_TIME_FACET__HPP__
3 #define _DATE_TIME_FACET__HPP__
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 or http://www.boost.org/LICENSE-1.0)
9 * Author: Martin Andrian, Jeff Garland, Bart Garst
10 * $Date: 2006/02/18 20:58:01 $
13 #include "boost/date_time/date_facet.hpp"
14 #include "boost/date_time/string_convert.hpp"
15 #include "boost/algorithm/string/erase.hpp"
23 template <class CharT>
26 typedef CharT char_type;
27 static const char_type fractional_seconds_format[3]; // f
28 static const char_type fractional_seconds_or_none_format[3]; // F
29 static const char_type seconds_with_fractional_seconds_format[3]; // s
30 static const char_type seconds_format[3]; // S
31 static const char_type standard_format[9]; // x X
32 static const char_type zone_abbrev_format[3]; // z
33 static const char_type zone_name_format[3]; // Z
34 static const char_type zone_iso_format[3]; // q
35 static const char_type zone_iso_extended_format[3]; // Q
36 static const char_type posix_zone_string_format[4]; // ZP
37 static const char_type duration_sign_negative_only[3]; // -
38 static const char_type duration_sign_always[3]; // +
39 static const char_type duration_seperator[2];
40 static const char_type negative_sign[2]; //-
41 static const char_type positive_sign[2]; //+
42 static const char_type iso_time_format_specifier[18];
43 static const char_type iso_time_format_extended_specifier[22];
44 //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
45 static const char_type default_time_format[23];
46 // default_time_input_format uses a posix_time_zone_string instead of a time zone abbrev
47 static const char_type default_time_input_format[24];
48 //default time_duration format is HH:MM:SS[.fff...]
49 static const char_type default_time_duration_format[11];
52 template <class CharT>
53 const typename time_formats<CharT>::char_type
54 time_formats<CharT>::fractional_seconds_format[3] = {'%','f'};
56 template <class CharT>
57 const typename time_formats<CharT>::char_type
58 time_formats<CharT>::fractional_seconds_or_none_format[3] = {'%','F'};
60 template <class CharT>
61 const typename time_formats<CharT>::char_type
62 time_formats<CharT>::seconds_with_fractional_seconds_format[3] =
65 template <class CharT>
66 const typename time_formats<CharT>::char_type
67 time_formats<CharT>::seconds_format[3] = {'%','S'};
69 template <class CharT>
70 const typename time_formats<CharT>::char_type
71 //time_formats<CharT>::standard_format[5] = {'%','c',' ','%','z'};
72 time_formats<CharT>::standard_format[9] = {'%','x',' ','%','X',' ','%','z'};
74 template <class CharT>
75 const typename time_formats<CharT>::char_type
76 time_formats<CharT>::zone_abbrev_format[3] = {'%','z'};
78 template <class CharT>
79 const typename time_formats<CharT>::char_type
80 time_formats<CharT>::zone_name_format[3] = {'%','Z'};
82 template <class CharT>
83 const typename time_formats<CharT>::char_type
84 time_formats<CharT>::zone_iso_format[3] = {'%','q'};
86 template <class CharT>
87 const typename time_formats<CharT>::char_type
88 time_formats<CharT>::zone_iso_extended_format[3] ={'%','Q'};
90 template <class CharT>
91 const typename time_formats<CharT>::char_type
92 time_formats<CharT>::posix_zone_string_format[4] ={'%','Z','P'};
94 template <class CharT>
95 const typename time_formats<CharT>::char_type
96 time_formats<CharT>::duration_seperator[2] = {':'};
98 template <class CharT>
99 const typename time_formats<CharT>::char_type
100 time_formats<CharT>::negative_sign[2] = {'-'};
102 template <class CharT>
103 const typename time_formats<CharT>::char_type
104 time_formats<CharT>::positive_sign[2] = {'+'};
106 template <class CharT>
107 const typename time_formats<CharT>::char_type
108 time_formats<CharT>::duration_sign_negative_only[3] ={'%','-'};
110 template <class CharT>
111 const typename time_formats<CharT>::char_type
112 time_formats<CharT>::duration_sign_always[3] ={'%','+'};
114 template <class CharT>
115 const typename time_formats<CharT>::char_type
116 time_formats<CharT>::iso_time_format_specifier[18] =
117 {'%', 'Y', '%', 'm', '%', 'd', 'T',
118 '%', 'H', '%', 'M', '%', 'S', '%', 'F', '%','q' };
120 template <class CharT>
121 const typename time_formats<CharT>::char_type
122 time_formats<CharT>::iso_time_format_extended_specifier[22] =
123 {'%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ',
124 '%', 'H', ':', '%', 'M', ':', '%', 'S', '%', 'F','%','Q'};
126 template <class CharT>
127 const typename time_formats<CharT>::char_type
128 time_formats<CharT>::default_time_format[23] =
129 {'%','Y','-','%','b','-','%','d',' ',
130 '%','H',':','%','M',':','%','S','%','F',' ','%','z'};
132 template <class CharT>
133 const typename time_formats<CharT>::char_type
134 time_formats<CharT>::default_time_input_format[24] =
135 {'%','Y','-','%','b','-','%','d',' ',
136 '%','H',':','%','M',':','%','S','%','F',' ','%','Z','P'};
138 template <class CharT>
139 const typename time_formats<CharT>::char_type
140 time_formats<CharT>::default_time_duration_format[11] =
141 {'%','H',':','%','M',':','%','S','%','F'};
145 /*! Facet used for format-based output of time types
146 * This class provides for the use of format strings to output times. In addition
147 * to the flags for formatting date elements, the following are the allowed format flags:
148 * - %x %X => default format - enables addition of more flags to default (ie. "%x %X %z")
149 * - %f => fractional seconds ".123456"
150 * - %F => fractional seconds or none: like frac sec but empty if frac sec == 0
151 * - %s => seconds w/ fractional sec "02.123" (this is the same as "%S%f)
152 * - %S => seconds "02"
153 * - %z => abbreviated time zone "EDT"
154 * - %Z => full time zone name "Eastern Daylight Time"
156 template <class time_type,
158 class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > >
160 public boost::date_time::date_facet<typename time_type::date_type , CharT, OutItrT> {
162 typedef typename time_type::date_type date_type;
163 typedef typename time_type::time_duration_type time_duration_type;
164 typedef boost::date_time::period<time_type,time_duration_type> period_type;
165 typedef boost::date_time::date_facet<typename time_type::date_type, CharT, OutItrT> base_type;
166 typedef typename base_type::string_type string_type;
167 typedef typename base_type::char_type char_type;
168 typedef typename base_type::period_formatter_type period_formatter_type;
169 typedef typename base_type::special_values_formatter_type special_values_formatter_type;
170 typedef typename base_type::date_gen_formatter_type date_gen_formatter_type;
171 static const char_type* fractional_seconds_format; // %f
172 static const char_type* fractional_seconds_or_none_format; // %F
173 static const char_type* seconds_with_fractional_seconds_format; // %s
174 static const char_type* seconds_format; // %S
175 static const char_type* standard_format; // %x X
176 static const char_type* zone_abbrev_format; // %z
177 static const char_type* zone_name_format; // %Z
178 static const char_type* zone_iso_format; // %q
179 static const char_type* zone_iso_extended_format; // %Q
180 static const char_type* posix_zone_string_format; // %ZP
181 static const char_type* duration_seperator;
182 static const char_type* duration_sign_always; // %+
183 static const char_type* duration_sign_negative_only; // %-
184 static const char_type* negative_sign; //-
185 static const char_type* positive_sign; //+
186 static const char_type* iso_time_format_specifier;
187 static const char_type* iso_time_format_extended_specifier;
189 //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
190 static const char_type* default_time_format;
191 //default time_duration format is HH:MM:SS[.fff...]
192 static const char_type* default_time_duration_format;
193 static std::locale::id id;
195 #if defined (__SUNPRO_CC) && defined (_RWSTD_VER)
196 std::locale::id& __get_id (void) const { return id; }
199 //! sets default formats for ptime, local_date_time, and time_duration
200 explicit time_facet(::size_t a_ref = 0)
201 //: base_type(standard_format),
202 : base_type(default_time_format),
203 m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format)
206 //! Construct the facet with an explicitly specified format
207 explicit time_facet(const char_type* a_format,
208 period_formatter_type period_formatter = period_formatter_type(),
209 const special_values_formatter_type& special_value_formatter = special_values_formatter_type(),
210 date_gen_formatter_type dg_formatter = date_gen_formatter_type(),
212 : base_type(a_format,
214 special_value_formatter,
217 m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format)
220 //! Changes format for time_duration
221 void time_duration_format(const char_type* const format)
223 m_time_duration_format = format;
226 virtual void set_iso_format()
228 this->m_format = iso_time_format_specifier;
230 virtual void set_iso_extended_format()
232 this->m_format = iso_time_format_extended_specifier;
235 OutItrT put(OutItrT a_next,
236 std::ios_base& a_ios,
238 const time_type& a_time) const
240 if (a_time.is_special()) {
241 return this->do_put_special(a_next, a_ios, a_fill,
242 a_time.date().as_special());
244 string_type format(this->m_format);
245 string_type frac_str;
246 if (format.find(seconds_with_fractional_seconds_format) != string_type::npos) {
247 // replace %s with %S.nnn
249 fractional_seconds_as_string(a_time.time_of_day(), false);
250 char_type sep = std::use_facet<std::numpunct<char_type> >(a_ios.getloc()).decimal_point();
252 string_type replace_string(seconds_format);
253 replace_string += sep;
254 replace_string += frac_str;
255 boost::algorithm::replace_all(format,
256 seconds_with_fractional_seconds_format,
259 /* NOTE: replacing posix_zone_string_format must be done BEFORE
260 * zone_name_format: "%ZP" & "%Z", if Z is checked first it will
261 * incorrectly replace a zone_name where a posix_string should go */
262 if (format.find(posix_zone_string_format) != string_type::npos) {
263 if(a_time.zone_abbrev().empty()) {
264 // if zone_abbrev() returns an empty string, we want to
265 // erase posix_zone_string_format from format
266 boost::algorithm::replace_all(format,
267 posix_zone_string_format,
271 boost::algorithm::replace_all(format,
272 posix_zone_string_format,
273 a_time.zone_as_posix_string());
276 if (format.find(zone_name_format) != string_type::npos) {
277 if(a_time.zone_name().empty()) {
278 /* TODO: this'll probably create problems if a user places
279 * the zone_*_format flag in the format with a ptime. This
280 * code removes the flag from the default formats */
282 // if zone_name() returns an empty string, we want to
283 // erase zone_name_format & one preceeding space
284 std::basic_ostringstream<char_type> ss;
285 ss << ' ' << zone_name_format;
286 boost::algorithm::replace_all(format,
291 boost::algorithm::replace_all(format,
296 if (format.find(zone_abbrev_format) != string_type::npos) {
297 if(a_time.zone_abbrev(false).empty()) {
298 /* TODO: this'll probably create problems if a user places
299 * the zone_*_format flag in the format with a ptime. This
300 * code removes the flag from the default formats */
302 // if zone_abbrev() returns an empty string, we want to
303 // erase zone_abbrev_format & one preceeding space
304 std::basic_ostringstream<char_type> ss;
305 ss << ' ' << zone_abbrev_format;
306 boost::algorithm::replace_all(format,
311 boost::algorithm::replace_all(format,
313 a_time.zone_abbrev(false));
316 if (format.find(zone_iso_extended_format) != string_type::npos) {
317 if(a_time.zone_name(true).empty()) {
318 /* TODO: this'll probably create problems if a user places
319 * the zone_*_format flag in the format with a ptime. This
320 * code removes the flag from the default formats */
322 // if zone_name() returns an empty string, we want to
323 // erase zone_iso_extended_format from format
324 boost::algorithm::replace_all(format,
325 zone_iso_extended_format,
329 boost::algorithm::replace_all(format,
330 zone_iso_extended_format,
331 a_time.zone_name(true));
335 if (format.find(zone_iso_format) != string_type::npos) {
336 if(a_time.zone_abbrev(true).empty()) {
337 /* TODO: this'll probably create problems if a user places
338 * the zone_*_format flag in the format with a ptime. This
339 * code removes the flag from the default formats */
341 // if zone_abbrev() returns an empty string, we want to
342 // erase zone_iso_format from format
343 boost::algorithm::replace_all(format,
348 boost::algorithm::replace_all(format,
350 a_time.zone_abbrev(true));
353 if (format.find(fractional_seconds_format) != string_type::npos) {
354 // replace %f with nnnnnnn
355 if (!frac_str.size()) {
356 frac_str = fractional_seconds_as_string(a_time.time_of_day(), false);
358 boost::algorithm::replace_all(format,
359 fractional_seconds_format,
363 if (format.find(fractional_seconds_or_none_format) != string_type::npos) {
364 // replace %F with nnnnnnn or nothing if fs == 0
366 fractional_seconds_as_string(a_time.time_of_day(), true);
367 if (frac_str.size()) {
368 char_type sep = std::use_facet<std::numpunct<char_type> >(a_ios.getloc()).decimal_point();
369 string_type replace_string;
370 replace_string += sep;
371 replace_string += frac_str;
372 boost::algorithm::replace_all(format,
373 fractional_seconds_or_none_format,
377 boost::algorithm::erase_all(format,
378 fractional_seconds_or_none_format);
382 return this->do_put_tm(a_next, a_ios, a_fill,
383 to_tm(a_time), format);
386 //! put function for time_duration
387 OutItrT put(OutItrT a_next,
388 std::ios_base& a_ios,
390 const time_duration_type& a_time_dur) const
392 if (a_time_dur.is_special()) {
393 return this->do_put_special(a_next, a_ios, a_fill,
394 a_time_dur.get_rep().as_special());
397 string_type format(m_time_duration_format);
398 if (a_time_dur.is_negative()) {
399 // replace %- with minus sign. Should we use the numpunct facet?
400 boost::algorithm::replace_all(format,
401 duration_sign_negative_only,
403 // remove all the %+ in the string with '-'
404 boost::algorithm::replace_all(format,
405 duration_sign_always,
408 else { //duration is positive
409 // remove all the %- combos from the string
410 boost::algorithm::replace_all(format,
411 duration_sign_negative_only,
413 // remove all the %+ in the string with '+'
414 boost::algorithm::replace_all(format,
415 duration_sign_always,
419 string_type frac_str;
420 if (format.find(seconds_with_fractional_seconds_format) != string_type::npos) {
421 // replace %s with %S.nnn
423 fractional_seconds_as_string(a_time_dur, false);
424 char_type sep = std::use_facet<std::numpunct<char_type> >(a_ios.getloc()).decimal_point();
426 string_type replace_string(seconds_format);
427 replace_string += sep;
428 replace_string += frac_str;
429 boost::algorithm::replace_all(format,
430 seconds_with_fractional_seconds_format,
433 if (format.find(fractional_seconds_format) != string_type::npos) {
434 // replace %f with nnnnnnn
435 if (!frac_str.size()) {
436 frac_str = fractional_seconds_as_string(a_time_dur, false);
438 boost::algorithm::replace_all(format,
439 fractional_seconds_format,
443 if (format.find(fractional_seconds_or_none_format) != string_type::npos) {
444 // replace %F with nnnnnnn or nothing if fs == 0
446 fractional_seconds_as_string(a_time_dur, true);
447 if (frac_str.size()) {
448 char_type sep = std::use_facet<std::numpunct<char_type> >(a_ios.getloc()).decimal_point();
449 string_type replace_string;
450 replace_string += sep;
451 replace_string += frac_str;
452 boost::algorithm::replace_all(format,
453 fractional_seconds_or_none_format,
457 boost::algorithm::erase_all(format,
458 fractional_seconds_or_none_format);
462 return this->do_put_tm(a_next, a_ios, a_fill,
463 to_tm(a_time_dur), format);
466 OutItrT put(OutItrT next, std::ios_base& a_ios,
467 char_type fill, const period_type& p) const
469 return this->m_period_formatter.put_period(next, a_ios, fill,p,*this);
477 fractional_seconds_as_string(const time_duration_type& a_time,
480 typename time_duration_type::fractional_seconds_type frac_sec =
481 a_time.fractional_seconds();
483 if (null_when_zero && (frac_sec == 0)) {
484 return string_type();
487 //make sure there is no sign
488 frac_sec = date_time::absolute_value(frac_sec);
489 std::basic_ostringstream<char_type> ss;
490 ss.imbue(std::locale::classic()); // don't want any formatting
491 ss << std::setw(time_duration_type::num_fractional_digits())
492 << std::setfill(static_cast<char_type>('0'));
493 #if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
494 // JDG [7/6/02 VC++ compatibility]
496 ss << _i64toa(static_cast<boost::int64_t>(frac_sec), buff, 10);
504 string_type m_time_duration_format;
508 template <class time_type, class CharT, class OutItrT>
509 std::locale::id time_facet<time_type, CharT, OutItrT>::id;
511 template <class time_type, class CharT, class OutItrT>
512 const typename time_facet<time_type, CharT, OutItrT>::char_type*
513 time_facet<time_type, CharT, OutItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format;
515 template <class time_type, class CharT, class OutItrT>
516 const typename time_facet<time_type, CharT, OutItrT>::char_type*
517 time_facet<time_type, CharT, OutItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format;
519 template <class time_type, class CharT, class OutItrT>
520 const typename time_facet<time_type, CharT, OutItrT>::char_type*
521 time_facet<time_type, CharT, OutItrT>::seconds_with_fractional_seconds_format =
522 time_formats<CharT>::seconds_with_fractional_seconds_format;
525 template <class time_type, class CharT, class OutItrT>
526 const typename time_facet<time_type, CharT, OutItrT>::char_type*
527 time_facet<time_type, CharT, OutItrT>::zone_name_format = time_formats<CharT>::zone_name_format;
529 template <class time_type, class CharT, class OutItrT>
530 const typename time_facet<time_type, CharT, OutItrT>::char_type*
531 time_facet<time_type, CharT, OutItrT>::zone_abbrev_format = time_formats<CharT>::zone_abbrev_format;
533 template <class time_type, class CharT, class OutItrT>
534 const typename time_facet<time_type, CharT, OutItrT>::char_type*
535 time_facet<time_type, CharT, OutItrT>::zone_iso_extended_format =time_formats<CharT>::zone_iso_extended_format;
537 template <class time_type, class CharT, class OutItrT>
538 const typename time_facet<time_type, CharT, OutItrT>::char_type*
539 time_facet<time_type, CharT, OutItrT>::posix_zone_string_format =time_formats<CharT>::posix_zone_string_format;
541 template <class time_type, class CharT, class OutItrT>
542 const typename time_facet<time_type, CharT, OutItrT>::char_type*
543 time_facet<time_type, CharT, OutItrT>::zone_iso_format = time_formats<CharT>::zone_iso_format;
545 template <class time_type, class CharT, class OutItrT>
546 const typename time_facet<time_type, CharT, OutItrT>::char_type*
547 time_facet<time_type, CharT, OutItrT>::seconds_format = time_formats<CharT>::seconds_format;
549 template <class time_type, class CharT, class OutItrT>
550 const typename time_facet<time_type, CharT, OutItrT>::char_type*
551 time_facet<time_type, CharT, OutItrT>::standard_format = time_formats<CharT>::standard_format;
553 template <class time_type, class CharT, class OutItrT>
554 const typename time_facet<time_type, CharT, OutItrT>::char_type*
555 time_facet<time_type, CharT, OutItrT>::duration_seperator = time_formats<CharT>::duration_seperator;
557 template <class time_type, class CharT, class OutItrT>
558 const typename time_facet<time_type, CharT, OutItrT>::char_type*
559 time_facet<time_type, CharT, OutItrT>::negative_sign = time_formats<CharT>::negative_sign;
561 template <class time_type, class CharT, class OutItrT>
562 const typename time_facet<time_type, CharT, OutItrT>::char_type*
563 time_facet<time_type, CharT, OutItrT>::positive_sign = time_formats<CharT>::positive_sign;
565 template <class time_type, class CharT, class OutItrT>
566 const typename time_facet<time_type, CharT, OutItrT>::char_type*
567 time_facet<time_type, CharT, OutItrT>::duration_sign_negative_only = time_formats<CharT>::duration_sign_negative_only;
569 template <class time_type, class CharT, class OutItrT>
570 const typename time_facet<time_type, CharT, OutItrT>::char_type*
571 time_facet<time_type, CharT, OutItrT>::duration_sign_always = time_formats<CharT>::duration_sign_always;
573 template <class time_type, class CharT, class OutItrT>
574 const typename time_facet<time_type,CharT, OutItrT>::char_type*
575 time_facet<time_type,CharT, OutItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier;
577 template <class time_type, class CharT, class OutItrT>
578 const typename time_facet<time_type, CharT, OutItrT>::char_type*
579 time_facet<time_type, CharT, OutItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier;
581 template <class time_type, class CharT, class OutItrT>
582 const typename time_facet<time_type, CharT, OutItrT>::char_type*
583 time_facet<time_type, CharT, OutItrT>::default_time_format =
584 time_formats<CharT>::default_time_format;
586 template <class time_type, class CharT, class OutItrT>
587 const typename time_facet<time_type, CharT, OutItrT>::char_type*
588 time_facet<time_type, CharT, OutItrT>::default_time_duration_format =
589 time_formats<CharT>::default_time_duration_format;
592 //! Facet for format-based input.
595 template <class time_type,
597 class InItrT = std::istreambuf_iterator<CharT, std::char_traits<CharT> > >
598 class time_input_facet :
599 public boost::date_time::date_input_facet<typename time_type::date_type , CharT, InItrT> {
601 typedef typename time_type::date_type date_type;
602 typedef typename time_type::time_duration_type time_duration_type;
603 typedef typename time_duration_type::fractional_seconds_type fracional_seconds_type;
604 typedef boost::date_time::period<time_type,time_duration_type> period_type;
605 typedef boost::date_time::date_input_facet<typename time_type::date_type, CharT, InItrT> base_type;
606 typedef typename base_type::duration_type date_duration_type;
607 typedef typename base_type::year_type year_type;
608 typedef typename base_type::month_type month_type;
609 typedef typename base_type::day_type day_type;
610 typedef typename base_type::string_type string_type;
611 typedef typename string_type::const_iterator const_itr;
612 typedef typename base_type::char_type char_type;
613 typedef typename base_type::format_date_parser_type format_date_parser_type;
614 typedef typename base_type::period_parser_type period_parser_type;
615 typedef typename base_type::special_values_parser_type special_values_parser_type;
616 typedef typename base_type::date_gen_parser_type date_gen_parser_type;
617 typedef typename base_type::special_values_parser_type::match_results match_results;
619 static const char_type* fractional_seconds_format; // f
620 static const char_type* fractional_seconds_or_none_format; // F
621 static const char_type* seconds_with_fractional_seconds_format; // s
622 static const char_type* seconds_format; // S
623 static const char_type* standard_format; // x X
624 static const char_type* zone_abbrev_format; // z
625 static const char_type* zone_name_format; // Z
626 static const char_type* zone_iso_format; // q
627 static const char_type* zone_iso_extended_format; // Q
628 static const char_type* duration_seperator;
629 static const char_type* iso_time_format_specifier;
630 static const char_type* iso_time_format_extended_specifier;
631 static const char_type* default_time_input_format;
632 static const char_type* default_time_duration_format;
633 static std::locale::id id;
635 //! Constructor that takes a format string for a ptime
636 explicit time_input_facet(const string_type& format, ::size_t a_ref = 0)
637 : base_type(format, a_ref),
638 m_time_duration_format(default_time_duration_format)
641 explicit time_input_facet(const string_type& format,
642 const format_date_parser_type& date_parser,
643 const special_values_parser_type& sv_parser,
644 const period_parser_type& per_parser,
645 const date_gen_parser_type& date_gen_parser,
653 m_time_duration_format(default_time_duration_format)
656 //! sets default formats for ptime, local_date_time, and time_duration
657 explicit time_input_facet(::size_t a_ref = 0)
658 : base_type(default_time_input_format, a_ref),
659 m_time_duration_format(default_time_duration_format)
662 //! Set the format for time_duration
663 void time_duration_format(const char_type* const format) {
664 m_time_duration_format = format;
666 virtual void set_iso_format()
668 this->m_format = iso_time_format_specifier;
670 virtual void set_iso_extended_format()
672 this->m_format = iso_time_format_extended_specifier;
675 InItrT get(InItrT& sitr,
677 std::ios_base& a_ios,
678 period_type& p) const
680 p = this->m_period_parser.get_period(sitr,
684 time_duration_type::unit(),
689 //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
690 //default time_duration format is %H:%M:%S%F HH:MM:SS[.fff...]
692 InItrT get(InItrT& sitr,
694 std::ios_base& a_ios,
695 time_duration_type& td) const
697 // skip leading whitespace
698 while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; }
700 bool use_current_char = false;
702 // num_get will consume the +/-, we may need a copy if special_value
704 if((sitr != stream_end) && (*sitr == '-' || *sitr == '+')) {
711 typename time_duration_type::fractional_seconds_type frac(0);
713 typedef std::num_get<CharT, InItrT> num_get;
714 if(!std::has_facet<num_get>(a_ios.getloc())) {
715 num_get* ng = new num_get();
716 std::locale loc = std::locale(a_ios.getloc(), ng);
720 const_itr itr(m_time_duration_format.begin());
721 while (itr != m_time_duration_format.end() && (sitr != stream_end)) {
729 hour = fixed_string_to_int<short, CharT>(sitr, stream_end, mr, 2);
731 return check_special_value(sitr, stream_end, td, c);
738 min = fixed_string_to_int<short, CharT>(sitr, stream_end, mr, 2);
740 return check_special_value(sitr, stream_end, td, c);
747 sec = fixed_string_to_int<short, CharT>(sitr, stream_end, mr, 2);
749 return check_special_value(sitr, stream_end, td, c);
756 sec = fixed_string_to_int<short, CharT>(sitr, stream_end, mr, 2);
758 return check_special_value(sitr, stream_end, td, c);
760 // %s is the same as %S%f so we drop through into %f
765 // check for decimal, check special_values if missing
768 parse_frac_type(sitr, stream_end, frac);
769 // sitr will point to next expected char after this parsing
770 // is complete so no need to advance it
771 use_current_char = true;
774 return check_special_value(sitr, stream_end, td, c);
780 // check for decimal, skip if missing
783 parse_frac_type(sitr, stream_end, frac);
784 // sitr will point to next expected char after this parsing
785 // is complete so no need to advance it
786 use_current_char = true;
789 // nothing was parsed so we don't want to advance sitr
790 use_current_char = true;
795 {} // ignore what we don't understand?
798 else { // itr == '%', second consecutive
802 itr++; //advance past format specifier
804 else { //skip past chars in format and in buffer
806 // set use_current_char when sitr is already
807 // pointing at the next character to process
808 if (use_current_char) {
809 use_current_char = false;
817 td = time_duration_type(hour, min, sec, frac);
822 //! Parses a time object from the input stream
823 InItrT get(InItrT& sitr,
825 std::ios_base& a_ios,
829 return get(sitr, stream_end, a_ios, t, tz_str, false);
831 //! Expects a time_zone in the input stream
832 InItrT get_local_time(InItrT& sitr,
834 std::ios_base& a_ios,
836 string_type& tz_str) const
838 return get(sitr, stream_end, a_ios, t, tz_str, true);
843 InItrT get(InItrT& sitr,
845 std::ios_base& a_ios,
848 bool time_is_local) const
850 // skip leading whitespace
851 while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; }
853 bool use_current_char = false;
854 bool use_current_format_char = false; // used whith two character flags
856 // num_get will consume the +/-, we may need a copy if special_value
858 if((sitr != stream_end) && (*sitr == '-' || *sitr == '+')) {
866 typename time_duration_type::fractional_seconds_type frac(0);
868 short day_of_year(0);
869 /* Initialized the following to their minimum values. These intermediate
870 * objects are used so we get specific exceptions when part of the input
872 * Ex: "205-Jan-15" will throw a bad_year, "2005-Jsn-15"- bad_month, etc.*/
873 year_type t_year(1400);
874 month_type t_month(1);
877 typedef std::num_get<CharT, InItrT> num_get;
878 if(!std::has_facet<num_get>(a_ios.getloc())) {
879 num_get* ng = new num_get();
880 std::locale loc = std::locale(a_ios.getloc(), ng);
884 const_itr itr(this->m_format.begin());
885 while (itr != this->m_format.end() && (sitr != stream_end)) {
889 // the cases are grouped by date & time flags - not alphabetical order
895 char_type cs[3] = { '%', *itr };
899 t_year = this->m_parser.parse_year(sitr, stream_end, s, mr);
901 catch(std::out_of_range bad_year) { // base class for bad_year exception
902 if(this->m_sv_parser.match(sitr, stream_end, mr)) {
903 t = time_type(static_cast<special_values>(mr.current_match));
907 throw; // rethrow bad_year
916 char_type cs[3] = { '%', *itr };
920 t_month = this->m_parser.parse_month(sitr, stream_end, s, mr);
922 catch(std::out_of_range bad_month) { // base class for bad_month exception
923 if(this->m_sv_parser.match(sitr, stream_end, mr)) {
924 t = time_type(static_cast<special_values>(mr.current_match));
928 throw; // rethrow bad_year
931 // did m_parser already advance sitr to next char?
932 if(mr.has_remaining()) {
933 use_current_char = true;
941 // weekday is not used in construction but we need to get it out of the stream
942 char_type cs[3] = { '%', *itr };
945 typename date_type::day_of_week_type wd(0);
947 wd = this->m_parser.parse_weekday(sitr, stream_end, s, mr);
949 catch(std::out_of_range bad_weekday) { // base class for bad_weekday exception
950 if(this->m_sv_parser.match(sitr, stream_end, mr)) {
951 t = time_type(static_cast<special_values>(mr.current_match));
955 throw; // rethrow bad_weekday
958 // did m_parser already advance sitr to next char?
959 if(mr.has_remaining()) {
960 use_current_char = true;
966 // code that gets julian day (from format_date_parser)
968 day_of_year = fixed_string_to_int<unsigned short, CharT>(sitr, stream_end, mr, 3);
969 if(day_of_year == -1) {
970 if(this->m_sv_parser.match(sitr, stream_end, mr)) {
971 t = time_type(static_cast<special_values>(mr.current_match));
975 // these next two lines are so we get an exception with bad input
976 typedef typename time_type::date_type::day_of_year_type day_of_year_type;
977 day_of_year_type t_day_of_year(day_of_year);
983 t_day = this->m_parser.parse_day_of_month(sitr, stream_end);
985 catch(std::out_of_range bad_day_of_month) { // base class for exception
987 if(this->m_sv_parser.match(sitr, stream_end, mr)) {
988 t = time_type(static_cast<special_values>(mr.current_match));
992 throw; // rethrow bad_year
1001 hour = fixed_string_to_int<short, CharT>(sitr, stream_end, mr, 2);
1003 return check_special_value(sitr, stream_end, t, c);
1010 min = fixed_string_to_int<short, CharT>(sitr, stream_end, mr, 2);
1012 return check_special_value(sitr, stream_end, t, c);
1019 sec = fixed_string_to_int<short, CharT>(sitr, stream_end, mr, 2);
1021 return check_special_value(sitr, stream_end, t, c);
1028 sec = fixed_string_to_int<short, CharT>(sitr, stream_end, mr, 2);
1030 return check_special_value(sitr, stream_end, t, c);
1032 // %s is the same as %S%f so we drop through into %f
1037 // check for decimal, check SV if missing
1040 parse_frac_type(sitr, stream_end, frac);
1041 // sitr will point to next expected char after this parsing
1042 // is complete so no need to advance it
1043 use_current_char = true;
1046 return check_special_value(sitr, stream_end, t, c);
1052 // check for decimal, skip if missing
1055 parse_frac_type(sitr, stream_end, frac);
1056 // sitr will point to next expected char after this parsing
1057 // is complete so no need to advance it
1058 use_current_char = true;
1061 // nothing was parsed so we don't want to advance sitr
1062 use_current_char = true;
1072 if(time_is_local) { // skip if 't' is a ptime
1075 // skip leading whitespace
1076 while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; }
1078 while((sitr != stream_end) && (!std::isspace(*sitr))) {
1084 use_current_format_char = true;
1089 // nothing was parsed so we don't want to advance sitr
1090 use_current_char = true;
1096 {} // ignore what we don't understand?
1099 else { // itr == '%', second consecutive
1103 if(use_current_format_char) {
1104 use_current_format_char = false;
1107 itr++; //advance past format specifier
1111 else { //skip past chars in format and in buffer
1113 // set use_current_char when sitr is already
1114 // pointing at the next character to process
1115 if (use_current_char) {
1116 use_current_char = false;
1124 date_type d(not_a_date_time);
1125 if (day_of_year > 0) {
1126 d = date_type(static_cast<unsigned short>(t_year-1),12,31) + date_duration_type(day_of_year);
1129 d = date_type(t_year, t_month, t_day);
1132 time_duration_type td(hour, min, sec, frac);
1133 t = time_type(d, td);
1137 //! Helper function to check for special_value
1138 /*! First character may have been consumed during original parse
1139 * attempt. Parameter 'c' should be a copy of that character.
1140 * Throws ios_base::failure if parse fails. */
1141 template<class temporal_type>
1143 InItrT check_special_value(InItrT& sitr,InItrT& stream_end, temporal_type& tt, char_type c='\0') const
1146 if((c == '-' || c == '+') && (*sitr != c)) { // was the first character consumed?
1149 this->m_sv_parser.match(sitr, stream_end, mr);
1150 if(mr.current_match == match_results::PARSE_ERROR) {
1151 std::string tmp = convert_string_type<char_type, char>(mr.cache);
1152 throw std::ios_base::failure("Parse failed. No match found for '" + tmp + "'");
1154 tt = temporal_type(static_cast<special_values>(mr.current_match));
1158 //! Helper function for parsing a fractional second type from the stream
1159 void parse_frac_type(InItrT& sitr,
1161 fracional_seconds_type& frac) const
1164 while((sitr != stream_end) && std::isdigit(*sitr)) {
1168 if(cache.size() > 0) {
1169 unsigned short precision = time_duration_type::num_fractional_digits();
1170 // input may be only the first few decimal places
1171 if(cache.size() < precision) {
1172 frac = lexical_cast<fracional_seconds_type>(cache);
1173 frac = decimal_adjust(frac, static_cast<unsigned short>(precision - cache.size()));
1176 // if input has too many decimal places, drop excess digits
1177 frac = lexical_cast<fracional_seconds_type>(cache.substr(0, precision));
1183 string_type m_time_duration_format;
1185 //! Helper function to adjust trailing zeros when parsing fractional digits
1186 template<class int_type>
1188 int_type decimal_adjust(int_type val, const unsigned short places) const
1190 unsigned long factor = 1;
1191 for(int i = 0; i < places; ++i){
1192 factor *= 10; // shift decimal to the right
1194 return val * factor;
1199 template <class time_type, class CharT, class InItrT>
1200 std::locale::id time_input_facet<time_type, CharT, InItrT>::id;
1202 template <class time_type, class CharT, class InItrT>
1203 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1204 time_input_facet<time_type, CharT, InItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format;
1206 template <class time_type, class CharT, class InItrT>
1207 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1208 time_input_facet<time_type, CharT, InItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format;
1210 template <class time_type, class CharT, class InItrT>
1211 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1212 time_input_facet<time_type, CharT, InItrT>::seconds_with_fractional_seconds_format = time_formats<CharT>::seconds_with_fractional_seconds_format;
1214 template <class time_type, class CharT, class InItrT>
1215 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1216 time_input_facet<time_type, CharT, InItrT>::seconds_format = time_formats<CharT>::seconds_format;
1218 template <class time_type, class CharT, class InItrT>
1219 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1220 time_input_facet<time_type, CharT, InItrT>::standard_format = time_formats<CharT>::standard_format;
1222 template <class time_type, class CharT, class InItrT>
1223 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1224 time_input_facet<time_type, CharT, InItrT>::zone_abbrev_format = time_formats<CharT>::zone_abbrev_format;
1226 template <class time_type, class CharT, class InItrT>
1227 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1228 time_input_facet<time_type, CharT, InItrT>::zone_name_format = time_formats<CharT>::zone_name_format;
1230 template <class time_type, class CharT, class InItrT>
1231 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1232 time_input_facet<time_type, CharT, InItrT>::zone_iso_format = time_formats<CharT>::zone_iso_format;
1234 template <class time_type, class CharT, class InItrT>
1235 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1236 time_input_facet<time_type, CharT, InItrT>::zone_iso_extended_format = time_formats<CharT>::zone_iso_extended_format;
1238 template <class time_type, class CharT, class InItrT>
1239 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1240 time_input_facet<time_type, CharT, InItrT>::duration_seperator = time_formats<CharT>::duration_seperator;
1242 template <class time_type, class CharT, class InItrT>
1243 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1244 time_input_facet<time_type, CharT, InItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier;
1246 template <class time_type, class CharT, class InItrT>
1247 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1248 time_input_facet<time_type, CharT, InItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier;
1250 template <class time_type, class CharT, class InItrT>
1251 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1252 time_input_facet<time_type, CharT, InItrT>::default_time_input_format = time_formats<CharT>::default_time_input_format;
1254 template <class time_type, class CharT, class InItrT>
1255 const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1256 time_input_facet<time_type, CharT, InItrT>::default_time_duration_format = time_formats<CharT>::default_time_duration_format;