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.txt or http://www.boost.org/LICENSE_1_0.txt)
9 * Author: Martin Andrian, Jeff Garland, Bart Garst
19 #include <iterator> // i/ostreambuf_iterator
21 #include <boost/assert.hpp>
22 #include <boost/lexical_cast.hpp>
23 #include <boost/throw_exception.hpp>
24 #include <boost/algorithm/string/erase.hpp>
25 #include <boost/algorithm/string/replace.hpp>
26 #include <boost/date_time/compiler_config.hpp>
27 #include <boost/date_time/date_facet.hpp>
28 #include <boost/date_time/string_convert.hpp>
29 #include <boost/date_time/special_defs.hpp>
34 template <class CharT
>
37 typedef CharT char_type
;
38 static const char_type fractional_seconds_format
[3]; // f
39 static const char_type fractional_seconds_or_none_format
[3]; // F
40 static const char_type seconds_with_fractional_seconds_format
[3]; // s
41 static const char_type seconds_format
[3]; // S
42 static const char_type hours_format
[3]; // H
43 static const char_type unrestricted_hours_format
[3]; // O
44 static const char_type standard_format
[9]; // x X
45 static const char_type zone_abbrev_format
[3]; // z
46 static const char_type zone_name_format
[3]; // Z
47 static const char_type zone_iso_format
[3]; // q
48 static const char_type zone_iso_extended_format
[3]; // Q
49 static const char_type posix_zone_string_format
[4]; // ZP
50 static const char_type duration_sign_negative_only
[3]; // -
51 static const char_type duration_sign_always
[3]; // +
52 static const char_type duration_seperator
[2];
53 static const char_type negative_sign
[2]; //-
54 static const char_type positive_sign
[2]; //+
55 static const char_type iso_time_format_specifier
[18];
56 static const char_type iso_time_format_extended_specifier
[22];
57 //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
58 static const char_type default_time_format
[23];
59 // default_time_input_format uses a posix_time_zone_string instead of a time zone abbrev
60 static const char_type default_time_input_format
[24];
61 //default time_duration format is HH:MM:SS[.fff...]
62 static const char_type default_time_duration_format
[11];
65 template <class CharT
>
66 const typename time_formats
<CharT
>::char_type
67 time_formats
<CharT
>::fractional_seconds_format
[3] = {'%','f'};
69 template <class CharT
>
70 const typename time_formats
<CharT
>::char_type
71 time_formats
<CharT
>::fractional_seconds_or_none_format
[3] = {'%','F'};
73 template <class CharT
>
74 const typename time_formats
<CharT
>::char_type
75 time_formats
<CharT
>::seconds_with_fractional_seconds_format
[3] =
78 template <class CharT
>
79 const typename time_formats
<CharT
>::char_type
80 time_formats
<CharT
>::seconds_format
[3] = {'%','S'};
82 template <class CharT
>
83 const typename time_formats
<CharT
>::char_type
84 time_formats
<CharT
>::hours_format
[3] = {'%','H'};
86 template <class CharT
>
87 const typename time_formats
<CharT
>::char_type
88 time_formats
<CharT
>::unrestricted_hours_format
[3] = {'%','O'};
90 template <class CharT
>
91 const typename time_formats
<CharT
>::char_type
92 //time_formats<CharT>::standard_format[5] = {'%','c',' ','%','z'};
93 time_formats
<CharT
>::standard_format
[9] = {'%','x',' ','%','X',' ','%','z'};
95 template <class CharT
>
96 const typename time_formats
<CharT
>::char_type
97 time_formats
<CharT
>::zone_abbrev_format
[3] = {'%','z'};
99 template <class CharT
>
100 const typename time_formats
<CharT
>::char_type
101 time_formats
<CharT
>::zone_name_format
[3] = {'%','Z'};
103 template <class CharT
>
104 const typename time_formats
<CharT
>::char_type
105 time_formats
<CharT
>::zone_iso_format
[3] = {'%','q'};
107 template <class CharT
>
108 const typename time_formats
<CharT
>::char_type
109 time_formats
<CharT
>::zone_iso_extended_format
[3] ={'%','Q'};
111 template <class CharT
>
112 const typename time_formats
<CharT
>::char_type
113 time_formats
<CharT
>::posix_zone_string_format
[4] ={'%','Z','P'};
115 template <class CharT
>
116 const typename time_formats
<CharT
>::char_type
117 time_formats
<CharT
>::duration_seperator
[2] = {':'};
119 template <class CharT
>
120 const typename time_formats
<CharT
>::char_type
121 time_formats
<CharT
>::negative_sign
[2] = {'-'};
123 template <class CharT
>
124 const typename time_formats
<CharT
>::char_type
125 time_formats
<CharT
>::positive_sign
[2] = {'+'};
127 template <class CharT
>
128 const typename time_formats
<CharT
>::char_type
129 time_formats
<CharT
>::duration_sign_negative_only
[3] ={'%','-'};
131 template <class CharT
>
132 const typename time_formats
<CharT
>::char_type
133 time_formats
<CharT
>::duration_sign_always
[3] ={'%','+'};
135 template <class CharT
>
136 const typename time_formats
<CharT
>::char_type
137 time_formats
<CharT
>::iso_time_format_specifier
[18] =
138 {'%', 'Y', '%', 'm', '%', 'd', 'T',
139 '%', 'H', '%', 'M', '%', 'S', '%', 'F', '%','q' };
141 template <class CharT
>
142 const typename time_formats
<CharT
>::char_type
143 time_formats
<CharT
>::iso_time_format_extended_specifier
[22] =
144 {'%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ',
145 '%', 'H', ':', '%', 'M', ':', '%', 'S', '%', 'F','%','Q'};
147 template <class CharT
>
148 const typename time_formats
<CharT
>::char_type
149 time_formats
<CharT
>::default_time_format
[23] =
150 {'%','Y','-','%','b','-','%','d',' ',
151 '%','H',':','%','M',':','%','S','%','F',' ','%','z'};
153 template <class CharT
>
154 const typename time_formats
<CharT
>::char_type
155 time_formats
<CharT
>::default_time_input_format
[24] =
156 {'%','Y','-','%','b','-','%','d',' ',
157 '%','H',':','%','M',':','%','S','%','F',' ','%','Z','P'};
159 template <class CharT
>
160 const typename time_formats
<CharT
>::char_type
161 time_formats
<CharT
>::default_time_duration_format
[11] =
162 {'%','H',':','%','M',':','%','S','%','F'};
166 /*! Facet used for format-based output of time types
167 * This class provides for the use of format strings to output times. In addition
168 * to the flags for formatting date elements, the following are the allowed format flags:
169 * - %x %X => default format - enables addition of more flags to default (ie. "%x %X %z")
170 * - %f => fractional seconds ".123456"
171 * - %F => fractional seconds or none: like frac sec but empty if frac sec == 0
172 * - %s => seconds w/ fractional sec "02.123" (this is the same as "%S%f)
173 * - %S => seconds "02"
174 * - %z => abbreviated time zone "EDT"
175 * - %Z => full time zone name "Eastern Daylight Time"
177 template <class time_type
,
179 class OutItrT
= std::ostreambuf_iterator
<CharT
, std::char_traits
<CharT
> > >
181 public boost::date_time::date_facet
<typename
time_type::date_type
, CharT
, OutItrT
> {
183 typedef typename
time_type::date_type date_type
;
184 typedef typename
time_type::time_duration_type time_duration_type
;
185 typedef boost::date_time::period
<time_type
,time_duration_type
> period_type
;
186 typedef boost::date_time::date_facet
<typename
time_type::date_type
, CharT
, OutItrT
> base_type
;
187 typedef typename
base_type::string_type string_type
;
188 typedef typename
base_type::char_type char_type
;
189 typedef typename
base_type::period_formatter_type period_formatter_type
;
190 typedef typename
base_type::special_values_formatter_type special_values_formatter_type
;
191 typedef typename
base_type::date_gen_formatter_type date_gen_formatter_type
;
192 static const char_type
* fractional_seconds_format
; // %f
193 static const char_type
* fractional_seconds_or_none_format
; // %F
194 static const char_type
* seconds_with_fractional_seconds_format
; // %s
195 static const char_type
* seconds_format
; // %S
196 static const char_type
* hours_format
; // %H
197 static const char_type
* unrestricted_hours_format
; // %O
198 static const char_type
* standard_format
; // %x X
199 static const char_type
* zone_abbrev_format
; // %z
200 static const char_type
* zone_name_format
; // %Z
201 static const char_type
* zone_iso_format
; // %q
202 static const char_type
* zone_iso_extended_format
; // %Q
203 static const char_type
* posix_zone_string_format
; // %ZP
204 static const char_type
* duration_seperator
;
205 static const char_type
* duration_sign_always
; // %+
206 static const char_type
* duration_sign_negative_only
; // %-
207 static const char_type
* negative_sign
; //-
208 static const char_type
* positive_sign
; //+
209 static const char_type
* iso_time_format_specifier
;
210 static const char_type
* iso_time_format_extended_specifier
;
212 //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
213 static const char_type
* default_time_format
;
214 //default time_duration format is HH:MM:SS[.fff...]
215 static const char_type
* default_time_duration_format
;
216 static std::locale::id id
;
218 #if defined (__SUNPRO_CC) && defined (_RWSTD_VER)
219 std::locale::id
& __get_id (void) const { return id
; }
222 //! sets default formats for ptime, local_date_time, and time_duration
223 explicit time_facet(::size_t a_ref
= 0)
224 : base_type(default_time_format
, period_formatter_type(), special_values_formatter_type(), date_gen_formatter_type(), a_ref
),
225 m_time_duration_format(string_type(duration_sign_negative_only
) + default_time_duration_format
)
228 //! Construct the facet with an explicitly specified format
229 explicit time_facet(const char_type
* a_format
,
230 period_formatter_type period_formatter
= period_formatter_type(),
231 const special_values_formatter_type
& special_value_formatter
= special_values_formatter_type(),
232 date_gen_formatter_type dg_formatter
= date_gen_formatter_type(),
234 : base_type(a_format
,
236 special_value_formatter
,
239 m_time_duration_format(string_type(duration_sign_negative_only
) + default_time_duration_format
)
242 //! Changes format for time_duration
243 void time_duration_format(const char_type
* const format
)
245 m_time_duration_format
= format
;
248 virtual void set_iso_format()
250 this->m_format
= iso_time_format_specifier
;
252 virtual void set_iso_extended_format()
254 this->m_format
= iso_time_format_extended_specifier
;
257 OutItrT
put(OutItrT a_next
,
258 std::ios_base
& a_ios
,
260 const time_type
& a_time
) const
262 if (a_time
.is_special()) {
263 return this->do_put_special(a_next
, a_ios
, a_fill
,
264 a_time
.date().as_special());
266 string_type
format(this->m_format
);
268 string_type frac_str
;
269 if (format
.find(seconds_with_fractional_seconds_format
) != string_type::npos
) {
270 // replace %s with %S.nnn
272 fractional_seconds_as_string(a_time
.time_of_day(), false);
273 char_type sep
= std::use_facet
<std::numpunct
<char_type
> >(a_ios
.getloc()).decimal_point();
275 string_type
replace_string(seconds_format
);
276 replace_string
+= sep
;
277 replace_string
+= frac_str
;
278 boost::algorithm::replace_all(format
,
279 seconds_with_fractional_seconds_format
,
282 /* NOTE: replacing posix_zone_string_format must be done BEFORE
283 * zone_name_format: "%ZP" & "%Z", if Z is checked first it will
284 * incorrectly replace a zone_name where a posix_string should go */
285 if (format
.find(posix_zone_string_format
) != string_type::npos
) {
286 if(a_time
.zone_abbrev().empty()) {
287 // if zone_abbrev() returns an empty string, we want to
288 // erase posix_zone_string_format from format
289 boost::algorithm::erase_all(format
, posix_zone_string_format
);
292 boost::algorithm::replace_all(format
,
293 posix_zone_string_format
,
294 a_time
.zone_as_posix_string());
297 if (format
.find(zone_name_format
) != string_type::npos
) {
298 if(a_time
.zone_name().empty()) {
299 /* TODO: this'll probably create problems if a user places
300 * the zone_*_format flag in the format with a ptime. This
301 * code removes the flag from the default formats */
303 // if zone_name() returns an empty string, we want to
304 // erase zone_name_format & one preceeding space
305 std::basic_ostringstream
<char_type
> ss
;
306 ss
<< ' ' << zone_name_format
;
307 boost::algorithm::erase_all(format
, ss
.str());
310 boost::algorithm::replace_all(format
,
315 if (format
.find(zone_abbrev_format
) != string_type::npos
) {
316 if(a_time
.zone_abbrev(false).empty()) {
317 /* TODO: this'll probably create problems if a user places
318 * the zone_*_format flag in the format with a ptime. This
319 * code removes the flag from the default formats */
321 // if zone_abbrev() returns an empty string, we want to
322 // erase zone_abbrev_format & one preceeding space
323 std::basic_ostringstream
<char_type
> ss
;
324 ss
<< ' ' << zone_abbrev_format
;
325 boost::algorithm::erase_all(format
, ss
.str());
328 boost::algorithm::replace_all(format
,
330 a_time
.zone_abbrev(false));
333 if (format
.find(zone_iso_extended_format
) != string_type::npos
) {
334 if(a_time
.zone_name(true).empty()) {
335 /* TODO: this'll probably create problems if a user places
336 * the zone_*_format flag in the format with a ptime. This
337 * code removes the flag from the default formats */
339 // if zone_name() returns an empty string, we want to
340 // erase zone_iso_extended_format from format
341 boost::algorithm::erase_all(format
, zone_iso_extended_format
);
344 boost::algorithm::replace_all(format
,
345 zone_iso_extended_format
,
346 a_time
.zone_name(true));
350 if (format
.find(zone_iso_format
) != string_type::npos
) {
351 if(a_time
.zone_abbrev(true).empty()) {
352 /* TODO: this'll probably create problems if a user places
353 * the zone_*_format flag in the format with a ptime. This
354 * code removes the flag from the default formats */
356 // if zone_abbrev() returns an empty string, we want to
357 // erase zone_iso_format from format
358 boost::algorithm::erase_all(format
, zone_iso_format
);
361 boost::algorithm::replace_all(format
,
363 a_time
.zone_abbrev(true));
366 if (format
.find(fractional_seconds_format
) != string_type::npos
) {
367 // replace %f with nnnnnnn
368 if (!frac_str
.size()) {
369 frac_str
= fractional_seconds_as_string(a_time
.time_of_day(), false);
371 boost::algorithm::replace_all(format
,
372 fractional_seconds_format
,
376 if (format
.find(fractional_seconds_or_none_format
) != string_type::npos
) {
377 // replace %F with nnnnnnn or nothing if fs == 0
379 fractional_seconds_as_string(a_time
.time_of_day(), true);
380 if (frac_str
.size()) {
381 char_type sep
= std::use_facet
<std::numpunct
<char_type
> >(a_ios
.getloc()).decimal_point();
382 string_type replace_string
;
383 replace_string
+= sep
;
384 replace_string
+= frac_str
;
385 boost::algorithm::replace_all(format
,
386 fractional_seconds_or_none_format
,
390 boost::algorithm::erase_all(format
,
391 fractional_seconds_or_none_format
);
395 return this->do_put_tm(a_next
, a_ios
, a_fill
,
396 to_tm(a_time
), format
);
399 //! put function for time_duration
400 OutItrT
put(OutItrT a_next
,
401 std::ios_base
& a_ios
,
403 const time_duration_type
& a_time_dur
) const
405 if (a_time_dur
.is_special()) {
406 return this->do_put_special(a_next
, a_ios
, a_fill
,
407 a_time_dur
.get_rep().as_special());
410 string_type
format(m_time_duration_format
);
411 if (a_time_dur
.is_negative()) {
412 // replace %- with minus sign. Should we use the numpunct facet?
413 boost::algorithm::replace_all(format
,
414 duration_sign_negative_only
,
416 // remove all the %+ in the string with '-'
417 boost::algorithm::replace_all(format
,
418 duration_sign_always
,
421 else { //duration is positive
422 // remove all the %- combos from the string
423 boost::algorithm::erase_all(format
, duration_sign_negative_only
);
424 // remove all the %+ in the string with '+'
425 boost::algorithm::replace_all(format
,
426 duration_sign_always
,
431 * It is possible for a time duration to span more then 24 hours.
432 * Standard time_put::put is obliged to behave the same as strftime
433 * (See ISO 14882-2003 22.2.5.3.1 par. 1) and strftime's behavior is
434 * unspecified for the case when tm_hour field is outside 0-23 range
435 * (See ISO 9899-1999 7.23.3.5 par. 3). So we must output %H and %O
438 string_type hours_str
;
439 if (format
.find(unrestricted_hours_format
) != string_type::npos
) {
440 hours_str
= hours_as_string(a_time_dur
);
441 boost::algorithm::replace_all(format
, unrestricted_hours_format
, hours_str
);
443 // We still have to process restricted hours format specifier. In order to
444 // support parseability of durations in ISO format (%H%M%S), we'll have to
445 // restrict the stringified hours length to 2 characters.
446 if (format
.find(hours_format
) != string_type::npos
) {
447 if (hours_str
.empty())
448 hours_str
= hours_as_string(a_time_dur
);
449 BOOST_ASSERT(hours_str
.length() <= 2);
450 boost::algorithm::replace_all(format
, hours_format
, hours_str
);
453 string_type frac_str
;
454 if (format
.find(seconds_with_fractional_seconds_format
) != string_type::npos
) {
455 // replace %s with %S.nnn
457 fractional_seconds_as_string(a_time_dur
, false);
458 char_type sep
= std::use_facet
<std::numpunct
<char_type
> >(a_ios
.getloc()).decimal_point();
460 string_type
replace_string(seconds_format
);
461 replace_string
+= sep
;
462 replace_string
+= frac_str
;
463 boost::algorithm::replace_all(format
,
464 seconds_with_fractional_seconds_format
,
467 if (format
.find(fractional_seconds_format
) != string_type::npos
) {
468 // replace %f with nnnnnnn
469 if (!frac_str
.size()) {
470 frac_str
= fractional_seconds_as_string(a_time_dur
, false);
472 boost::algorithm::replace_all(format
,
473 fractional_seconds_format
,
477 if (format
.find(fractional_seconds_or_none_format
) != string_type::npos
) {
478 // replace %F with nnnnnnn or nothing if fs == 0
480 fractional_seconds_as_string(a_time_dur
, true);
481 if (frac_str
.size()) {
482 char_type sep
= std::use_facet
<std::numpunct
<char_type
> >(a_ios
.getloc()).decimal_point();
483 string_type replace_string
;
484 replace_string
+= sep
;
485 replace_string
+= frac_str
;
486 boost::algorithm::replace_all(format
,
487 fractional_seconds_or_none_format
,
491 boost::algorithm::erase_all(format
,
492 fractional_seconds_or_none_format
);
496 return this->do_put_tm(a_next
, a_ios
, a_fill
,
497 to_tm(a_time_dur
), format
);
500 OutItrT
put(OutItrT next
, std::ios_base
& a_ios
,
501 char_type fill
, const period_type
& p
) const
503 return this->m_period_formatter
.put_period(next
, a_ios
, fill
,p
,*this);
511 fractional_seconds_as_string(const time_duration_type
& a_time
,
514 typename
time_duration_type::fractional_seconds_type frac_sec
=
515 a_time
.fractional_seconds();
517 if (null_when_zero
&& (frac_sec
== 0)) {
518 return string_type();
521 //make sure there is no sign
522 return integral_as_string(
523 date_time::absolute_value(frac_sec
),
524 time_duration_type::num_fractional_digits());
529 hours_as_string(const time_duration_type
& a_time
, int width
= 2)
531 return integral_as_string(date_time::absolute_value(a_time
.hours()), width
);
534 template< typename IntT
>
537 integral_as_string(IntT val
, int width
= 2)
539 std::basic_ostringstream
<char_type
> ss
;
540 ss
.imbue(std::locale::classic()); // don't want any formatting
541 ss
<< std::setw(width
)
542 << std::setfill(static_cast<char_type
>('0'));
543 #if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
544 // JDG [7/6/02 VC++ compatibility]
546 ss
<< _i64toa(static_cast<boost::int64_t>(val
), buff
, 10);
554 string_type m_time_duration_format
;
558 template <class time_type
, class CharT
, class OutItrT
>
559 std::locale::id time_facet
<time_type
, CharT
, OutItrT
>::id
;
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
>::fractional_seconds_format
= time_formats
<CharT
>::fractional_seconds_format
;
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
>::fractional_seconds_or_none_format
= time_formats
<CharT
>::fractional_seconds_or_none_format
;
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
>::seconds_with_fractional_seconds_format
=
572 time_formats
<CharT
>::seconds_with_fractional_seconds_format
;
575 template <class time_type
, class CharT
, class OutItrT
>
576 const typename time_facet
<time_type
, CharT
, OutItrT
>::char_type
*
577 time_facet
<time_type
, CharT
, OutItrT
>::zone_name_format
= time_formats
<CharT
>::zone_name_format
;
579 template <class time_type
, class CharT
, class OutItrT
>
580 const typename time_facet
<time_type
, CharT
, OutItrT
>::char_type
*
581 time_facet
<time_type
, CharT
, OutItrT
>::zone_abbrev_format
= time_formats
<CharT
>::zone_abbrev_format
;
583 template <class time_type
, class CharT
, class OutItrT
>
584 const typename time_facet
<time_type
, CharT
, OutItrT
>::char_type
*
585 time_facet
<time_type
, CharT
, OutItrT
>::zone_iso_extended_format
=time_formats
<CharT
>::zone_iso_extended_format
;
587 template <class time_type
, class CharT
, class OutItrT
>
588 const typename time_facet
<time_type
, CharT
, OutItrT
>::char_type
*
589 time_facet
<time_type
, CharT
, OutItrT
>::posix_zone_string_format
=time_formats
<CharT
>::posix_zone_string_format
;
591 template <class time_type
, class CharT
, class OutItrT
>
592 const typename time_facet
<time_type
, CharT
, OutItrT
>::char_type
*
593 time_facet
<time_type
, CharT
, OutItrT
>::zone_iso_format
= time_formats
<CharT
>::zone_iso_format
;
595 template <class time_type
, class CharT
, class OutItrT
>
596 const typename time_facet
<time_type
, CharT
, OutItrT
>::char_type
*
597 time_facet
<time_type
, CharT
, OutItrT
>::seconds_format
= time_formats
<CharT
>::seconds_format
;
599 template <class time_type
, class CharT
, class OutItrT
>
600 const typename time_facet
<time_type
, CharT
, OutItrT
>::char_type
*
601 time_facet
<time_type
, CharT
, OutItrT
>::hours_format
= time_formats
<CharT
>::hours_format
;
603 template <class time_type
, class CharT
, class OutItrT
>
604 const typename time_facet
<time_type
, CharT
, OutItrT
>::char_type
*
605 time_facet
<time_type
, CharT
, OutItrT
>::unrestricted_hours_format
= time_formats
<CharT
>::unrestricted_hours_format
;
607 template <class time_type
, class CharT
, class OutItrT
>
608 const typename time_facet
<time_type
, CharT
, OutItrT
>::char_type
*
609 time_facet
<time_type
, CharT
, OutItrT
>::standard_format
= time_formats
<CharT
>::standard_format
;
611 template <class time_type
, class CharT
, class OutItrT
>
612 const typename time_facet
<time_type
, CharT
, OutItrT
>::char_type
*
613 time_facet
<time_type
, CharT
, OutItrT
>::duration_seperator
= time_formats
<CharT
>::duration_seperator
;
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
>::negative_sign
= time_formats
<CharT
>::negative_sign
;
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
>::positive_sign
= time_formats
<CharT
>::positive_sign
;
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
>::duration_sign_negative_only
= time_formats
<CharT
>::duration_sign_negative_only
;
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
>::duration_sign_always
= time_formats
<CharT
>::duration_sign_always
;
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
>::iso_time_format_specifier
= time_formats
<CharT
>::iso_time_format_specifier
;
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
>::iso_time_format_extended_specifier
= time_formats
<CharT
>::iso_time_format_extended_specifier
;
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
>::default_time_format
=
642 time_formats
<CharT
>::default_time_format
;
644 template <class time_type
, class CharT
, class OutItrT
>
645 const typename time_facet
<time_type
, CharT
, OutItrT
>::char_type
*
646 time_facet
<time_type
, CharT
, OutItrT
>::default_time_duration_format
=
647 time_formats
<CharT
>::default_time_duration_format
;
650 //! Facet for format-based input.
653 template <class time_type
,
655 class InItrT
= std::istreambuf_iterator
<CharT
, std::char_traits
<CharT
> > >
656 class time_input_facet
:
657 public boost::date_time::date_input_facet
<typename
time_type::date_type
, CharT
, InItrT
> {
659 typedef typename
time_type::date_type date_type
;
660 typedef typename
time_type::time_duration_type time_duration_type
;
661 typedef typename
time_duration_type::fractional_seconds_type fracional_seconds_type
;
662 typedef boost::date_time::period
<time_type
,time_duration_type
> period_type
;
663 typedef boost::date_time::date_input_facet
<typename
time_type::date_type
, CharT
, InItrT
> base_type
;
664 typedef typename
base_type::duration_type date_duration_type
;
665 typedef typename
base_type::year_type year_type
;
666 typedef typename
base_type::month_type month_type
;
667 typedef typename
base_type::day_type day_type
;
668 typedef typename
base_type::string_type string_type
;
669 typedef typename
string_type::const_iterator const_itr
;
670 typedef typename
base_type::char_type char_type
;
671 typedef typename
base_type::format_date_parser_type format_date_parser_type
;
672 typedef typename
base_type::period_parser_type period_parser_type
;
673 typedef typename
base_type::special_values_parser_type special_values_parser_type
;
674 typedef typename
base_type::date_gen_parser_type date_gen_parser_type
;
675 typedef typename
base_type::special_values_parser_type::match_results match_results
;
677 static const char_type
* fractional_seconds_format
; // f
678 static const char_type
* fractional_seconds_or_none_format
; // F
679 static const char_type
* seconds_with_fractional_seconds_format
; // s
680 static const char_type
* seconds_format
; // S
681 static const char_type
* standard_format
; // x X
682 static const char_type
* zone_abbrev_format
; // z
683 static const char_type
* zone_name_format
; // Z
684 static const char_type
* zone_iso_format
; // q
685 static const char_type
* zone_iso_extended_format
; // Q
686 static const char_type
* duration_seperator
;
687 static const char_type
* iso_time_format_specifier
;
688 static const char_type
* iso_time_format_extended_specifier
;
689 static const char_type
* default_time_input_format
;
690 static const char_type
* default_time_duration_format
;
691 static std::locale::id id
;
693 //! Constructor that takes a format string for a ptime
694 explicit time_input_facet(const string_type
& format
, ::size_t a_ref
= 0)
695 : base_type(format
, a_ref
),
696 m_time_duration_format(default_time_duration_format
)
699 explicit time_input_facet(const string_type
& format
,
700 const format_date_parser_type
& date_parser
,
701 const special_values_parser_type
& sv_parser
,
702 const period_parser_type
& per_parser
,
703 const date_gen_parser_type
& date_gen_parser
,
711 m_time_duration_format(default_time_duration_format
)
714 //! sets default formats for ptime, local_date_time, and time_duration
715 explicit time_input_facet(::size_t a_ref
= 0)
716 : base_type(default_time_input_format
, a_ref
),
717 m_time_duration_format(default_time_duration_format
)
720 //! Set the format for time_duration
721 void time_duration_format(const char_type
* const format
) {
722 m_time_duration_format
= format
;
724 virtual void set_iso_format()
726 this->m_format
= iso_time_format_specifier
;
728 virtual void set_iso_extended_format()
730 this->m_format
= iso_time_format_extended_specifier
;
733 InItrT
get(InItrT
& sitr
,
735 std::ios_base
& a_ios
,
736 period_type
& p
) const
738 p
= this->m_period_parser
.get_period(sitr
,
742 time_duration_type::unit(),
747 //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
748 //default time_duration format is %H:%M:%S%F HH:MM:SS[.fff...]
750 InItrT
get(InItrT
& sitr
,
752 std::ios_base
& a_ios
,
753 time_duration_type
& td
) const
755 // skip leading whitespace
756 while((sitr
!= stream_end
) && std::isspace(*sitr
)) { ++sitr
; }
758 bool use_current_char
= false;
760 // num_get will consume the +/-, we may need a copy if special_value
762 if((sitr
!= stream_end
) && (*sitr
== '-' || *sitr
== '+')) {
766 typedef typename
time_duration_type::hour_type hour_type
;
767 typedef typename
time_duration_type::min_type min_type
;
768 typedef typename
time_duration_type::sec_type sec_type
;
773 typename
time_duration_type::fractional_seconds_type
frac(0);
775 typedef std::num_get
<CharT
, InItrT
> num_get
;
776 if(!std::has_facet
<num_get
>(a_ios
.getloc())) {
777 num_get
* ng
= new num_get();
778 std::locale loc
= std::locale(a_ios
.getloc(), ng
);
782 const_itr
itr(m_time_duration_format
.begin());
783 while (itr
!= m_time_duration_format
.end() && (sitr
!= stream_end
)) {
790 // A period may span more than 24 hours. In that case the format
791 // string should be composed with the unrestricted hours specifier.
792 hour
= var_string_to_int
<hour_type
, CharT
>(sitr
, stream_end
,
793 std::numeric_limits
<hour_type
>::digits10
+ 1);
795 return check_special_value(sitr
, stream_end
, td
, c
);
802 hour
= fixed_string_to_int
<hour_type
, CharT
>(sitr
, stream_end
, mr
, 2);
804 return check_special_value(sitr
, stream_end
, td
, c
);
811 min
= fixed_string_to_int
<min_type
, CharT
>(sitr
, stream_end
, mr
, 2);
813 return check_special_value(sitr
, stream_end
, td
, c
);
821 sec
= fixed_string_to_int
<sec_type
, CharT
>(sitr
, stream_end
, mr
, 2);
823 return check_special_value(sitr
, stream_end
, td
, c
);
827 // %s is the same as %S%f so we drop through into %f
831 // check for decimal, check special_values if missing
834 parse_frac_type(sitr
, stream_end
, frac
);
835 // sitr will point to next expected char after this parsing
836 // is complete so no need to advance it
837 use_current_char
= true;
840 return check_special_value(sitr
, stream_end
, td
, c
);
846 // check for decimal, skip if missing
849 parse_frac_type(sitr
, stream_end
, frac
);
850 // sitr will point to next expected char after this parsing
851 // is complete so no need to advance it
852 use_current_char
= true;
855 // nothing was parsed so we don't want to advance sitr
856 use_current_char
= true;
861 {} // ignore what we don't understand?
864 else { // itr == '%', second consecutive
868 ++itr
; //advance past format specifier
870 else { //skip past chars in format and in buffer
872 // set use_current_char when sitr is already
873 // pointing at the next character to process
874 if (use_current_char
) {
875 use_current_char
= false;
883 td
= time_duration_type(hour
, min
, sec
, frac
);
888 //! Parses a time object from the input stream
889 InItrT
get(InItrT
& sitr
,
891 std::ios_base
& a_ios
,
895 return get(sitr
, stream_end
, a_ios
, t
, tz_str
, false);
897 //! Expects a time_zone in the input stream
898 InItrT
get_local_time(InItrT
& sitr
,
900 std::ios_base
& a_ios
,
902 string_type
& tz_str
) const
904 return get(sitr
, stream_end
, a_ios
, t
, tz_str
, true);
909 InItrT
get(InItrT
& sitr
,
911 std::ios_base
& a_ios
,
914 bool time_is_local
) const
916 // skip leading whitespace
917 while((sitr
!= stream_end
) && std::isspace(*sitr
)) { ++sitr
; }
919 bool use_current_char
= false;
920 bool use_current_format_char
= false; // used whith two character flags
922 // num_get will consume the +/-, we may need a copy if special_value
924 if((sitr
!= stream_end
) && (*sitr
== '-' || *sitr
== '+')) {
928 typedef typename
time_duration_type::hour_type hour_type
;
929 typedef typename
time_duration_type::min_type min_type
;
930 typedef typename
time_duration_type::sec_type sec_type
;
936 typename
time_duration_type::fractional_seconds_type
frac(0);
938 short day_of_year(0);
939 /* Initialized the following to their minimum values. These intermediate
940 * objects are used so we get specific exceptions when part of the input
942 * Ex: "205-Jan-15" will throw a bad_year, "2005-Jsn-15"- bad_month, etc.*/
943 year_type
t_year(1400);
944 month_type
t_month(1);
947 typedef std::num_get
<CharT
, InItrT
> num_get
;
948 if(!std::has_facet
<num_get
>(a_ios
.getloc())) {
949 num_get
* ng
= new num_get();
950 std::locale loc
= std::locale(a_ios
.getloc(), ng
);
954 const_itr
itr(this->m_format
.begin());
955 while (itr
!= this->m_format
.end() && (sitr
!= stream_end
)) {
959 // the cases are grouped by date & time flags - not alphabetical order
965 char_type cs
[3] = { '%', *itr
};
969 t_year
= this->m_parser
.parse_year(sitr
, stream_end
, s
, mr
);
971 catch(std::out_of_range
&) { // base class for bad_year exception
972 if(this->m_sv_parser
.match(sitr
, stream_end
, mr
)) {
973 t
= time_type(static_cast<special_values
>(mr
.current_match
));
977 throw; // rethrow bad_year
986 char_type cs
[3] = { '%', *itr
};
990 t_month
= this->m_parser
.parse_month(sitr
, stream_end
, s
, mr
);
992 catch(std::out_of_range
&) { // base class for bad_month exception
993 if(this->m_sv_parser
.match(sitr
, stream_end
, mr
)) {
994 t
= time_type(static_cast<special_values
>(mr
.current_match
));
998 throw; // rethrow bad_month
1001 // did m_parser already advance sitr to next char?
1002 if(mr
.has_remaining()) {
1003 use_current_char
= true;
1011 // weekday is not used in construction but we need to get it out of the stream
1012 char_type cs
[3] = { '%', *itr
};
1015 typename
date_type::day_of_week_type
wd(0);
1017 wd
= this->m_parser
.parse_weekday(sitr
, stream_end
, s
, mr
);
1019 catch(std::out_of_range
&) { // base class for bad_weekday exception
1020 if(this->m_sv_parser
.match(sitr
, stream_end
, mr
)) {
1021 t
= time_type(static_cast<special_values
>(mr
.current_match
));
1025 throw; // rethrow bad_weekday
1028 // did m_parser already advance sitr to next char?
1029 if(mr
.has_remaining()) {
1030 use_current_char
= true;
1036 // code that gets julian day (from format_date_parser)
1038 day_of_year
= fixed_string_to_int
<unsigned short, CharT
>(sitr
, stream_end
, mr
, 3);
1039 if(day_of_year
== -1) {
1040 if(this->m_sv_parser
.match(sitr
, stream_end
, mr
)) {
1041 t
= time_type(static_cast<special_values
>(mr
.current_match
));
1045 // these next two lines are so we get an exception with bad input
1046 typedef typename
time_type::date_type::day_of_year_type day_of_year_type
;
1047 day_of_year_type
t_day_of_year(day_of_year
);
1053 t_day
= this->m_parser
.parse_day_of_month(sitr
, stream_end
);
1055 catch(std::out_of_range
&) { // base class for exception bad_day_of_month
1057 if(this->m_sv_parser
.match(sitr
, stream_end
, mr
)) {
1058 t
= time_type(static_cast<special_values
>(mr
.current_match
));
1062 throw; // rethrow bad_day_of_month
1071 hour
= fixed_string_to_int
<hour_type
, CharT
>(sitr
, stream_end
, mr
, 2);
1073 return check_special_value(sitr
, stream_end
, t
, c
);
1080 min
= fixed_string_to_int
<min_type
, CharT
>(sitr
, stream_end
, mr
, 2);
1082 return check_special_value(sitr
, stream_end
, t
, c
);
1090 sec
= fixed_string_to_int
<sec_type
, CharT
>(sitr
, stream_end
, mr
, 2);
1092 return check_special_value(sitr
, stream_end
, t
, c
);
1096 // %s is the same as %S%f so we drop through into %f
1100 // check for decimal, check SV if missing
1103 parse_frac_type(sitr
, stream_end
, frac
);
1104 // sitr will point to next expected char after this parsing
1105 // is complete so no need to advance it
1106 use_current_char
= true;
1109 return check_special_value(sitr
, stream_end
, t
, c
);
1115 // check for decimal, skip if missing
1118 parse_frac_type(sitr
, stream_end
, frac
);
1119 // sitr will point to next expected char after this parsing
1120 // is complete so no need to advance it
1121 use_current_char
= true;
1124 // nothing was parsed so we don't want to advance sitr
1125 use_current_char
= true;
1135 if(time_is_local
) { // skip if 't' is a ptime
1138 // skip leading whitespace
1139 while((sitr
!= stream_end
) && std::isspace(*sitr
)) { ++sitr
; }
1141 while((sitr
!= stream_end
) && (!std::isspace(*sitr
))) {
1147 use_current_format_char
= true;
1152 // nothing was parsed so we don't want to advance sitr
1153 use_current_char
= true;
1159 {} // ignore what we don't understand?
1162 else { // itr == '%', second consecutive
1166 if(use_current_format_char
) {
1167 use_current_format_char
= false;
1170 ++itr
; //advance past format specifier
1174 else { //skip past chars in format and in buffer
1176 // set use_current_char when sitr is already
1177 // pointing at the next character to process
1178 if (use_current_char
) {
1179 use_current_char
= false;
1187 date_type
d(not_a_date_time
);
1188 if (day_of_year
> 0) {
1189 d
= date_type(static_cast<unsigned short>(t_year
-1),12,31) + date_duration_type(day_of_year
);
1192 d
= date_type(t_year
, t_month
, t_day
);
1195 time_duration_type
td(hour
, min
, sec
, frac
);
1196 t
= time_type(d
, td
);
1200 //! Helper function to check for special_value
1201 /*! First character may have been consumed during original parse
1202 * attempt. Parameter 'c' should be a copy of that character.
1203 * Throws ios_base::failure if parse fails. */
1204 template<class temporal_type
>
1206 InItrT
check_special_value(InItrT
& sitr
,InItrT
& stream_end
, temporal_type
& tt
, char_type c
='\0') const
1209 if((c
== '-' || c
== '+') && (*sitr
!= c
)) { // was the first character consumed?
1212 this->m_sv_parser
.match(sitr
, stream_end
, mr
);
1213 if(mr
.current_match
== match_results::PARSE_ERROR
) {
1214 std::string tmp
= convert_string_type
<char_type
, char>(mr
.cache
);
1215 boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + tmp
+ "'"));
1216 BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(return sitr
); // should never reach
1218 tt
= temporal_type(static_cast<special_values
>(mr
.current_match
));
1222 //! Helper function for parsing a fractional second type from the stream
1223 void parse_frac_type(InItrT
& sitr
,
1225 fracional_seconds_type
& frac
) const
1228 while((sitr
!= stream_end
) && std::isdigit(*sitr
)) {
1232 if(cache
.size() > 0) {
1233 unsigned short precision
= time_duration_type::num_fractional_digits();
1234 // input may be only the first few decimal places
1235 if(cache
.size() < precision
) {
1236 frac
= lexical_cast
<fracional_seconds_type
>(cache
);
1237 frac
= decimal_adjust(frac
, static_cast<unsigned short>(precision
- cache
.size()));
1240 // if input has too many decimal places, drop excess digits
1241 frac
= lexical_cast
<fracional_seconds_type
>(cache
.substr(0, precision
));
1247 string_type m_time_duration_format
;
1249 //! Helper function to adjust trailing zeros when parsing fractional digits
1250 template<class int_type
>
1252 int_type
decimal_adjust(int_type val
, const unsigned short places
) const
1254 unsigned long factor
= 1;
1255 for(int i
= 0; i
< places
; ++i
){
1256 factor
*= 10; // shift decimal to the right
1258 return val
* factor
;
1263 template <class time_type
, class CharT
, class InItrT
>
1264 std::locale::id time_input_facet
<time_type
, CharT
, InItrT
>::id
;
1266 template <class time_type
, class CharT
, class InItrT
>
1267 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1268 time_input_facet
<time_type
, CharT
, InItrT
>::fractional_seconds_format
= time_formats
<CharT
>::fractional_seconds_format
;
1270 template <class time_type
, class CharT
, class InItrT
>
1271 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1272 time_input_facet
<time_type
, CharT
, InItrT
>::fractional_seconds_or_none_format
= time_formats
<CharT
>::fractional_seconds_or_none_format
;
1274 template <class time_type
, class CharT
, class InItrT
>
1275 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1276 time_input_facet
<time_type
, CharT
, InItrT
>::seconds_with_fractional_seconds_format
= time_formats
<CharT
>::seconds_with_fractional_seconds_format
;
1278 template <class time_type
, class CharT
, class InItrT
>
1279 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1280 time_input_facet
<time_type
, CharT
, InItrT
>::seconds_format
= time_formats
<CharT
>::seconds_format
;
1282 template <class time_type
, class CharT
, class InItrT
>
1283 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1284 time_input_facet
<time_type
, CharT
, InItrT
>::standard_format
= time_formats
<CharT
>::standard_format
;
1286 template <class time_type
, class CharT
, class InItrT
>
1287 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1288 time_input_facet
<time_type
, CharT
, InItrT
>::zone_abbrev_format
= time_formats
<CharT
>::zone_abbrev_format
;
1290 template <class time_type
, class CharT
, class InItrT
>
1291 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1292 time_input_facet
<time_type
, CharT
, InItrT
>::zone_name_format
= time_formats
<CharT
>::zone_name_format
;
1294 template <class time_type
, class CharT
, class InItrT
>
1295 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1296 time_input_facet
<time_type
, CharT
, InItrT
>::zone_iso_format
= time_formats
<CharT
>::zone_iso_format
;
1298 template <class time_type
, class CharT
, class InItrT
>
1299 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1300 time_input_facet
<time_type
, CharT
, InItrT
>::zone_iso_extended_format
= time_formats
<CharT
>::zone_iso_extended_format
;
1302 template <class time_type
, class CharT
, class InItrT
>
1303 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1304 time_input_facet
<time_type
, CharT
, InItrT
>::duration_seperator
= time_formats
<CharT
>::duration_seperator
;
1306 template <class time_type
, class CharT
, class InItrT
>
1307 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1308 time_input_facet
<time_type
, CharT
, InItrT
>::iso_time_format_specifier
= time_formats
<CharT
>::iso_time_format_specifier
;
1310 template <class time_type
, class CharT
, class InItrT
>
1311 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1312 time_input_facet
<time_type
, CharT
, InItrT
>::iso_time_format_extended_specifier
= time_formats
<CharT
>::iso_time_format_extended_specifier
;
1314 template <class time_type
, class CharT
, class InItrT
>
1315 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1316 time_input_facet
<time_type
, CharT
, InItrT
>::default_time_input_format
= time_formats
<CharT
>::default_time_input_format
;
1318 template <class time_type
, class CharT
, class InItrT
>
1319 const typename time_input_facet
<time_type
, CharT
, InItrT
>::char_type
*
1320 time_input_facet
<time_type
, CharT
, InItrT
>::default_time_duration_format
= time_formats
<CharT
>::default_time_duration_format
;