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 <exception>
15 #include <iomanip>
16 #include <iterator> // i/ostreambuf_iterator
17 #include <locale>
18 #include <limits>
19 #include <sstream>
20 #include <string>
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)
__get_id(void) const243       std::locale::id& __get_id (void) const { return id; }
244 #endif
245 
246     //! sets default formats for ptime, local_date_time, and time_duration
time_facet(::size_t ref_arg=0)247     explicit time_facet(::size_t ref_arg = 0)
248       : base_type(default_time_format, period_formatter_type(), special_values_formatter_type(), date_gen_formatter_type(), ref_arg),
249         m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format)
250     {}
251 
252     //! Construct the facet with an explicitly specified format
time_facet(const char_type * format_arg,period_formatter_type period_formatter_arg=period_formatter_type (),const special_values_formatter_type & special_value_formatter=special_values_formatter_type (),date_gen_formatter_type dg_formatter=date_gen_formatter_type (),::size_t ref_arg=0)253     explicit time_facet(const char_type* format_arg,
254                         period_formatter_type period_formatter_arg = period_formatter_type(),
255                         const special_values_formatter_type& special_value_formatter = special_values_formatter_type(),
256                         date_gen_formatter_type dg_formatter = date_gen_formatter_type(),
257                          ::size_t ref_arg = 0)
258       : base_type(format_arg,
259                   period_formatter_arg,
260                   special_value_formatter,
261                   dg_formatter,
262                   ref_arg),
263         m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format)
264     {}
265 
266     //! Changes format for time_duration
time_duration_format(const char_type * const format)267     void time_duration_format(const char_type* const format)
268     {
269       m_time_duration_format = format;
270     }
271 
set_iso_format()272     void set_iso_format() BOOST_OVERRIDE
273     {
274       this->m_format = iso_time_format_specifier;
275     }
set_iso_extended_format()276     void set_iso_extended_format() BOOST_OVERRIDE
277     {
278       this->m_format = iso_time_format_extended_specifier;
279     }
280 
put(OutItrT next_arg,std::ios_base & ios_arg,char_type fill_arg,const time_type & time_arg) const281     OutItrT put(OutItrT next_arg,
282                 std::ios_base& ios_arg,
283                 char_type fill_arg,
284                 const time_type& time_arg) const
285     {
286       if (time_arg.is_special()) {
287         return this->do_put_special(next_arg, ios_arg, fill_arg,
288                               time_arg.date().as_special());
289       }
290       string_type local_format(this->m_format);
291 
292       // %T and %R have to be replaced here since they are not standard
293       boost::algorithm::replace_all(local_format,
294         boost::as_literal(formats_type::full_24_hour_time_format),
295         boost::as_literal(formats_type::full_24_hour_time_expanded_format));
296       boost::algorithm::replace_all(local_format,
297         boost::as_literal(formats_type::short_24_hour_time_format),
298         boost::as_literal(formats_type::short_24_hour_time_expanded_format));
299 
300       string_type frac_str;
301       if (local_format.find(seconds_with_fractional_seconds_format) != string_type::npos) {
302         // replace %s with %S.nnn
303         frac_str =
304           fractional_seconds_as_string(time_arg.time_of_day(), false);
305         char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
306 
307         string_type replace_string(seconds_format);
308         replace_string += sep;
309         replace_string += frac_str;
310         boost::algorithm::replace_all(local_format,
311                                       seconds_with_fractional_seconds_format,
312                                       replace_string);
313       }
314       /* NOTE: replacing posix_zone_string_format must be done BEFORE
315        * zone_name_format: "%ZP" & "%Z", if Z is checked first it will
316        * incorrectly replace a zone_name where a posix_string should go */
317       if (local_format.find(posix_zone_string_format) != string_type::npos) {
318         if(time_arg.zone_abbrev().empty()) {
319           // if zone_abbrev() returns an empty string, we want to
320           // erase posix_zone_string_format from format
321           boost::algorithm::erase_all(local_format, posix_zone_string_format);
322         }
323         else{
324           boost::algorithm::replace_all(local_format,
325                                         posix_zone_string_format,
326                                         time_arg.zone_as_posix_string());
327         }
328       }
329       if (local_format.find(zone_name_format) != string_type::npos) {
330         if(time_arg.zone_name().empty()) {
331           /* TODO: this'll probably create problems if a user places
332            * the zone_*_format flag in the format with a ptime. This
333            * code removes the flag from the default formats */
334 
335           // if zone_name() returns an empty string, we want to
336           // erase zone_name_format & one preceeding space
337           std::basic_ostringstream<char_type> ss;
338           ss << ' ' << zone_name_format;
339           boost::algorithm::erase_all(local_format, ss.str());
340         }
341         else{
342           boost::algorithm::replace_all(local_format,
343                                         zone_name_format,
344                                         time_arg.zone_name());
345         }
346       }
347       if (local_format.find(zone_abbrev_format) != string_type::npos) {
348         if(time_arg.zone_abbrev(false).empty()) {
349           /* TODO: this'll probably create problems if a user places
350            * the zone_*_format flag in the format with a ptime. This
351            * code removes the flag from the default formats */
352 
353           // if zone_abbrev() returns an empty string, we want to
354           // erase zone_abbrev_format & one preceeding space
355           std::basic_ostringstream<char_type> ss;
356           ss << ' ' << zone_abbrev_format;
357           boost::algorithm::erase_all(local_format, ss.str());
358         }
359         else{
360           boost::algorithm::replace_all(local_format,
361                                         zone_abbrev_format,
362                                         time_arg.zone_abbrev(false));
363         }
364       }
365       if (local_format.find(zone_iso_extended_format) != string_type::npos) {
366         if(time_arg.zone_name(true).empty()) {
367           /* TODO: this'll probably create problems if a user places
368            * the zone_*_format flag in the format with a ptime. This
369            * code removes the flag from the default formats */
370 
371           // if zone_name() returns an empty string, we want to
372           // erase zone_iso_extended_format from format
373           boost::algorithm::erase_all(local_format, zone_iso_extended_format);
374         }
375         else{
376           boost::algorithm::replace_all(local_format,
377                                         zone_iso_extended_format,
378                                         time_arg.zone_name(true));
379         }
380       }
381 
382       if (local_format.find(zone_iso_format) != string_type::npos) {
383         if(time_arg.zone_abbrev(true).empty()) {
384           /* TODO: this'll probably create problems if a user places
385            * the zone_*_format flag in the format with a ptime. This
386            * code removes the flag from the default formats */
387 
388           // if zone_abbrev() returns an empty string, we want to
389           // erase zone_iso_format from format
390           boost::algorithm::erase_all(local_format, zone_iso_format);
391         }
392         else{
393           boost::algorithm::replace_all(local_format,
394                                         zone_iso_format,
395                                         time_arg.zone_abbrev(true));
396         }
397       }
398       if (local_format.find(fractional_seconds_format) != string_type::npos) {
399         // replace %f with nnnnnnn
400         if (frac_str.empty()) {
401           frac_str = fractional_seconds_as_string(time_arg.time_of_day(), false);
402         }
403         boost::algorithm::replace_all(local_format,
404                                       fractional_seconds_format,
405                                       frac_str);
406       }
407 
408       if (local_format.find(fractional_seconds_or_none_format) != string_type::npos) {
409         // replace %F with nnnnnnn or nothing if fs == 0
410         frac_str =
411           fractional_seconds_as_string(time_arg.time_of_day(), true);
412         if (!frac_str.empty()) {
413           char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
414           string_type replace_string;
415           replace_string += sep;
416           replace_string += frac_str;
417           boost::algorithm::replace_all(local_format,
418                                         fractional_seconds_or_none_format,
419                                         replace_string);
420         }
421         else {
422           boost::algorithm::erase_all(local_format,
423                                       fractional_seconds_or_none_format);
424         }
425       }
426 
427       return this->do_put_tm(next_arg, ios_arg, fill_arg,
428                        to_tm(time_arg), local_format);
429     }
430 
431     //! put function for time_duration
put(OutItrT next_arg,std::ios_base & ios_arg,char_type fill_arg,const time_duration_type & time_dur_arg) const432     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 
put(OutItrT next,std::ios_base & ios_arg,char_type fill,const period_type & p) const540     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
fractional_seconds_as_string(const time_duration_type & time_arg,bool null_when_zero)551     fractional_seconds_as_string(const time_duration_type& time_arg,
552                                  bool null_when_zero)
553     {
554       typename time_duration_type::fractional_seconds_type frac_sec =
555         time_arg.fractional_seconds();
556 
557       if (null_when_zero && (frac_sec == 0)) {
558         return string_type();
559       }
560 
561       //make sure there is no sign
562       return integral_as_string(
563         date_time::absolute_value(frac_sec),
564         time_duration_type::num_fractional_digits());
565     }
566 
567     static
568     string_type
hours_as_string(const time_duration_type & time_arg,int width=2)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
integral_as_string(IntT val,int width=2)577     integral_as_string(IntT val, int width = 2)
578     {
579       std::basic_ostringstream<char_type> ss;
580       ss.imbue(std::locale::classic()); // don't want any formatting
581       ss << std::setw(width)
582         << std::setfill(static_cast<char_type>('0'));
583 #if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
584       // JDG [7/6/02 VC++ compatibility]
585       char_type buff[34];
586       ss << _i64toa(static_cast<boost::int64_t>(val), buff, 10);
587 #else
588       ss << val;
589 #endif
590       return ss.str();
591     }
592 
593   private:
594     string_type m_time_duration_format;
595 
596   };
597 
598   template <class time_type, class CharT, class OutItrT>
599   std::locale::id time_facet<time_type, CharT, OutItrT>::id;
600 
601   template <class time_type, class CharT, class OutItrT>
602   const typename time_facet<time_type, CharT, OutItrT>::char_type*
603   time_facet<time_type, CharT, OutItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format;
604 
605   template <class time_type, class CharT, class OutItrT>
606   const typename time_facet<time_type, CharT, OutItrT>::char_type*
607   time_facet<time_type, CharT, OutItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format;
608 
609   template <class time_type, class CharT, class OutItrT>
610   const typename time_facet<time_type, CharT, OutItrT>::char_type*
611   time_facet<time_type, CharT, OutItrT>::seconds_with_fractional_seconds_format =
612     time_formats<CharT>::seconds_with_fractional_seconds_format;
613 
614 
615   template <class time_type, class CharT, class OutItrT>
616   const typename time_facet<time_type, CharT, OutItrT>::char_type*
617   time_facet<time_type, CharT, OutItrT>::zone_name_format =  time_formats<CharT>::zone_name_format;
618 
619   template <class time_type, class CharT, class OutItrT>
620   const typename time_facet<time_type, CharT, OutItrT>::char_type*
621   time_facet<time_type, CharT, OutItrT>::zone_abbrev_format =  time_formats<CharT>::zone_abbrev_format;
622 
623   template <class time_type, class CharT, class OutItrT>
624   const typename time_facet<time_type, CharT, OutItrT>::char_type*
625   time_facet<time_type, CharT, OutItrT>::zone_iso_extended_format =time_formats<CharT>::zone_iso_extended_format;
626 
627   template <class time_type, class CharT, class OutItrT>
628   const typename time_facet<time_type, CharT, OutItrT>::char_type*
629   time_facet<time_type, CharT, OutItrT>::posix_zone_string_format =time_formats<CharT>::posix_zone_string_format;
630 
631   template <class time_type, class CharT, class OutItrT>
632   const typename time_facet<time_type, CharT, OutItrT>::char_type*
633   time_facet<time_type, CharT, OutItrT>::zone_iso_format =  time_formats<CharT>::zone_iso_format;
634 
635   template <class time_type, class CharT, class OutItrT>
636   const typename time_facet<time_type, CharT, OutItrT>::char_type*
637   time_facet<time_type, CharT, OutItrT>::seconds_format =  time_formats<CharT>::seconds_format;
638 
639   template <class time_type, class CharT, class OutItrT>
640   const typename time_facet<time_type, CharT, OutItrT>::char_type*
641   time_facet<time_type, CharT, OutItrT>::hours_format =  time_formats<CharT>::hours_format;
642 
643   template <class time_type, class CharT, class OutItrT>
644   const typename time_facet<time_type, CharT, OutItrT>::char_type*
645   time_facet<time_type, CharT, OutItrT>::unrestricted_hours_format =  time_formats<CharT>::unrestricted_hours_format;
646 
647   template <class time_type, class CharT, class OutItrT>
648   const typename time_facet<time_type, CharT, OutItrT>::char_type*
649   time_facet<time_type, CharT, OutItrT>::standard_format =  time_formats<CharT>::standard_format;
650 
651   template <class time_type, class CharT, class OutItrT>
652   const typename time_facet<time_type, CharT, OutItrT>::char_type*
653   time_facet<time_type, CharT, OutItrT>::duration_seperator =  time_formats<CharT>::duration_seperator;
654 
655   template <class time_type, class CharT, class OutItrT>
656   const typename time_facet<time_type, CharT, OutItrT>::char_type*
657   time_facet<time_type, CharT, OutItrT>::negative_sign =  time_formats<CharT>::negative_sign;
658 
659   template <class time_type, class CharT, class OutItrT>
660   const typename time_facet<time_type, CharT, OutItrT>::char_type*
661   time_facet<time_type, CharT, OutItrT>::positive_sign =  time_formats<CharT>::positive_sign;
662 
663   template <class time_type, class CharT, class OutItrT>
664   const typename time_facet<time_type, CharT, OutItrT>::char_type*
665   time_facet<time_type, CharT, OutItrT>::duration_sign_negative_only =  time_formats<CharT>::duration_sign_negative_only;
666 
667   template <class time_type, class CharT, class OutItrT>
668   const typename time_facet<time_type, CharT, OutItrT>::char_type*
669   time_facet<time_type, CharT, OutItrT>::duration_sign_always =  time_formats<CharT>::duration_sign_always;
670 
671   template <class time_type, class CharT, class OutItrT>
672   const typename time_facet<time_type,CharT, OutItrT>::char_type*
673   time_facet<time_type,CharT, OutItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier;
674 
675   template <class time_type, class CharT, class OutItrT>
676   const typename time_facet<time_type, CharT, OutItrT>::char_type*
677   time_facet<time_type, CharT, OutItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier;
678 
679   template <class time_type, class CharT, class OutItrT>
680   const typename time_facet<time_type, CharT, OutItrT>::char_type*
681   time_facet<time_type, CharT, OutItrT>::default_time_format =
682     time_formats<CharT>::default_time_format;
683 
684   template <class time_type, class CharT, class OutItrT>
685   const typename time_facet<time_type, CharT, OutItrT>::char_type*
686   time_facet<time_type, CharT, OutItrT>::default_time_duration_format =
687     time_formats<CharT>::default_time_duration_format;
688 
689 
690   //! Facet for format-based input.
691   /*!
692    */
693   template <class time_type,
694             class CharT,
695             class InItrT = std::istreambuf_iterator<CharT, std::char_traits<CharT> > >
696   class 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
time_input_facet(const string_type & format,::size_t ref_arg=0)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 
time_input_facet(const string_type & format,const format_date_parser_type & date_parser,const special_values_parser_type & sv_parser,const period_parser_type & per_parser,const date_gen_parser_type & date_gen_parser,::size_t ref_arg=0)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
time_input_facet(::size_t ref_arg=0)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
time_duration_format(const char_type * const format)761       void time_duration_format(const char_type* const format) {
762         m_time_duration_format = format;
763       }
set_iso_format()764       virtual void set_iso_format()
765       {
766         this->m_format = iso_time_format_specifier;
767       }
set_iso_extended_format()768       virtual void set_iso_extended_format()
769       {
770         this->m_format = iso_time_format_extended_specifier;
771       }
772 
get(InItrT & sitr,InItrT & stream_end,std::ios_base & ios_arg,period_type & p) const773       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 
get(InItrT & sitr,InItrT & stream_end,std::ios_base & ios_arg,time_duration_type & td) const790       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
get(InItrT & sitr,InItrT & stream_end,std::ios_base & ios_arg,time_type & t) const930       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
get_local_time(InItrT & sitr,InItrT & stream_end,std::ios_base & ios_arg,time_type & t,string_type & tz_str) const939       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 
get(InItrT & sitr,InItrT & stream_end,std::ios_base & ios_arg,time_type & t,string_type & tz_str,bool time_is_local) const950       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 with 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
check_special_value(InItrT & sitr,InItrT & stream_end,temporal_type & tt,char_type c='\\0') const1252       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
parse_frac_type(InItrT & sitr,InItrT & stream_end,fracional_seconds_type & frac) const1269       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
decimal_adjust(int_type val,const unsigned short places) const1298       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 } } // namespaces
1369 
1370 #endif
1371