Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:39

0001 
0002 #ifndef _DATE_TIME_FACET__HPP__
0003 #define _DATE_TIME_FACET__HPP__
0004 
0005 /* Copyright (c) 2004-2005 CrystalClear Software, Inc.
0006  * Use, modification and distribution is subject to the
0007  * Boost Software License, Version 1.0. (See accompanying
0008  * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
0009  * Author:  Martin Andrian, Jeff Garland, Bart Garst
0010  * $Date$
0011  */
0012 
0013 #include <cctype>
0014 #include <exception>
0015 #include <iomanip>
0016 #include <iterator> // i/ostreambuf_iterator
0017 #include <locale>
0018 #include <limits>
0019 #include <sstream>
0020 #include <string>
0021 #include <boost/assert.hpp>
0022 #include <boost/lexical_cast.hpp>
0023 #include <boost/throw_exception.hpp>
0024 #include <boost/range/as_literal.hpp>
0025 #include <boost/algorithm/string/erase.hpp>
0026 #include <boost/algorithm/string/replace.hpp>
0027 #include <boost/date_time/compiler_config.hpp>
0028 #include <boost/date_time/date_facet.hpp>
0029 #include <boost/date_time/string_convert.hpp>
0030 #include <boost/date_time/special_defs.hpp>
0031 #include <boost/date_time/time_resolution_traits.hpp> // absolute_value
0032 
0033 namespace boost {
0034 namespace date_time {
0035 
0036   template <class CharT>
0037   struct time_formats {
0038     public:
0039       typedef CharT char_type;
0040       static const char_type fractional_seconds_format[3];               // f
0041       static const char_type fractional_seconds_or_none_format[3];       // F
0042       static const char_type seconds_with_fractional_seconds_format[3];  // s
0043       static const char_type seconds_format[3];                          // S
0044       static const char_type hours_format[3];                            // H
0045       static const char_type unrestricted_hours_format[3];               // O
0046       static const char_type full_24_hour_time_format[3];                // T
0047       static const char_type full_24_hour_time_expanded_format[9];       // HH:MM:SS
0048       static const char_type short_24_hour_time_format[3];               // R
0049       static const char_type short_24_hour_time_expanded_format[6];      // HH:MM
0050       static const char_type standard_format[9];                         // x X
0051       static const char_type zone_abbrev_format[3];                      // z
0052       static const char_type zone_name_format[3];                        // Z
0053       static const char_type zone_iso_format[3];                         // q
0054       static const char_type zone_iso_extended_format[3];                // Q
0055       static const char_type posix_zone_string_format[4];                // ZP
0056       static const char_type duration_sign_negative_only[3];             // -
0057       static const char_type duration_sign_always[3];                    // +
0058       static const char_type duration_seperator[2];
0059       static const char_type negative_sign[2];                           //-
0060       static const char_type positive_sign[2];                           //+
0061       static const char_type iso_time_format_specifier[18];
0062       static const char_type iso_time_format_extended_specifier[22];
0063       //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
0064       static const char_type default_time_format[23];
0065       // default_time_input_format uses a posix_time_zone_string instead of a time zone abbrev
0066       static const char_type default_time_input_format[24];
0067       //default time_duration format is HH:MM:SS[.fff...]
0068       static const char_type default_time_duration_format[11];
0069   };
0070 
0071   template <class CharT>
0072   const typename time_formats<CharT>::char_type
0073   time_formats<CharT>::fractional_seconds_format[3] = {'%','f'};
0074 
0075   template <class CharT>
0076   const typename time_formats<CharT>::char_type
0077   time_formats<CharT>::fractional_seconds_or_none_format[3] = {'%','F'};
0078 
0079   template <class CharT>
0080   const typename time_formats<CharT>::char_type
0081   time_formats<CharT>::seconds_with_fractional_seconds_format[3] = {'%','s'};
0082 
0083   template <class CharT>
0084   const typename time_formats<CharT>::char_type
0085   time_formats<CharT>::seconds_format[3] =  {'%','S'};
0086 
0087   template <class CharT>
0088   const typename time_formats<CharT>::char_type
0089   time_formats<CharT>::hours_format[3] =  {'%','H'};
0090 
0091   template <class CharT>
0092   const typename time_formats<CharT>::char_type
0093   time_formats<CharT>::unrestricted_hours_format[3] =  {'%','O'};
0094 
0095   template <class CharT>
0096   const typename time_formats<CharT>::char_type
0097   time_formats<CharT>::full_24_hour_time_format[3] =  {'%','T'};
0098 
0099   template <class CharT>
0100   const typename time_formats<CharT>::char_type
0101   time_formats<CharT>::full_24_hour_time_expanded_format[9] =
0102   {'%','H',':','%','M',':','%','S'};
0103 
0104   template <class CharT>
0105   const typename time_formats<CharT>::char_type
0106   time_formats<CharT>::short_24_hour_time_format[3] =  {'%','R'};
0107 
0108   template <class CharT>
0109   const typename time_formats<CharT>::char_type
0110   time_formats<CharT>::short_24_hour_time_expanded_format[6] =
0111   {'%','H',':','%','M'};
0112 
0113   template <class CharT>
0114   const typename time_formats<CharT>::char_type
0115   //time_formats<CharT>::standard_format[5] =  {'%','c',' ','%','z'};
0116   time_formats<CharT>::standard_format[9] =  {'%','x',' ','%','X',' ','%','z'};
0117 
0118   template <class CharT>
0119   const typename time_formats<CharT>::char_type
0120   time_formats<CharT>::zone_abbrev_format[3] =  {'%','z'};
0121 
0122   template <class CharT>
0123   const typename time_formats<CharT>::char_type
0124   time_formats<CharT>::zone_name_format[3] =  {'%','Z'};
0125 
0126   template <class CharT>
0127   const typename time_formats<CharT>::char_type
0128   time_formats<CharT>::zone_iso_format[3] =  {'%','q'};
0129 
0130   template <class CharT>
0131   const typename time_formats<CharT>::char_type
0132   time_formats<CharT>::zone_iso_extended_format[3] ={'%','Q'};
0133 
0134   template <class CharT>
0135   const typename time_formats<CharT>::char_type
0136   time_formats<CharT>::posix_zone_string_format[4] ={'%','Z','P'};
0137 
0138   template <class CharT>
0139   const typename time_formats<CharT>::char_type
0140   time_formats<CharT>::duration_seperator[2] =  {':'};
0141 
0142   template <class CharT>
0143   const typename time_formats<CharT>::char_type
0144   time_formats<CharT>::negative_sign[2] =  {'-'};
0145 
0146   template <class CharT>
0147   const typename time_formats<CharT>::char_type
0148   time_formats<CharT>::positive_sign[2] =  {'+'};
0149 
0150   template <class CharT>
0151   const typename time_formats<CharT>::char_type
0152   time_formats<CharT>::duration_sign_negative_only[3] ={'%','-'};
0153 
0154   template <class CharT>
0155   const typename time_formats<CharT>::char_type
0156   time_formats<CharT>::duration_sign_always[3] ={'%','+'};
0157 
0158   template <class CharT>
0159   const typename time_formats<CharT>::char_type
0160   time_formats<CharT>::iso_time_format_specifier[18] =
0161     {'%', 'Y', '%', 'm', '%', 'd', 'T',
0162      '%', 'H', '%', 'M', '%', 'S', '%', 'F', '%','q' };
0163 
0164   template <class CharT>
0165   const typename time_formats<CharT>::char_type
0166   time_formats<CharT>::iso_time_format_extended_specifier[22] =
0167     {'%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ',
0168      '%', 'H', ':', '%', 'M', ':', '%', 'S', '%', 'F','%','Q'};
0169 
0170   template <class CharT>
0171   const typename time_formats<CharT>::char_type
0172   time_formats<CharT>::default_time_format[23] =
0173     {'%','Y','-','%','b','-','%','d',' ',
0174       '%','H',':','%','M',':','%','S','%','F',' ','%','z'};
0175 
0176   template <class CharT>
0177   const typename time_formats<CharT>::char_type
0178   time_formats<CharT>::default_time_input_format[24] =
0179     {'%','Y','-','%','b','-','%','d',' ',
0180       '%','H',':','%','M',':','%','S','%','F',' ','%','Z','P'};
0181 
0182   template <class CharT>
0183   const typename time_formats<CharT>::char_type
0184   time_formats<CharT>::default_time_duration_format[11] =
0185     {'%','O',':','%','M',':','%','S','%','F'};
0186 
0187 
0188 
0189   /*! Facet used for format-based output of time types
0190    * This class provides for the use of format strings to output times.  In addition
0191    * to the flags for formatting date elements, the following are the allowed format flags:
0192    *  - %x %X => default format - enables addition of more flags to default (ie. "%x %X %z")
0193    *  - %f => fractional seconds ".123456"
0194    *  - %F => fractional seconds or none: like frac sec but empty if frac sec == 0
0195    *  - %s => seconds w/ fractional sec "02.123" (this is the same as "%S%f)
0196    *  - %S => seconds "02"
0197    *  - %z => abbreviated time zone "EDT"
0198    *  - %Z => full time zone name "Eastern Daylight Time"
0199    */
0200   template <class time_type,
0201             class CharT,
0202             class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > >
0203   class BOOST_SYMBOL_VISIBLE time_facet :
0204     public boost::date_time::date_facet<typename time_type::date_type , CharT, OutItrT> {
0205     typedef time_formats< CharT > formats_type;
0206    public:
0207     typedef typename time_type::date_type date_type;
0208     typedef typename time_type::time_duration_type time_duration_type;
0209     typedef boost::date_time::period<time_type,time_duration_type> period_type;
0210     typedef boost::date_time::date_facet<typename time_type::date_type, CharT, OutItrT> base_type;
0211     typedef typename base_type::string_type string_type;
0212     typedef typename base_type::char_type   char_type;
0213     typedef typename base_type::period_formatter_type period_formatter_type;
0214     typedef typename base_type::special_values_formatter_type special_values_formatter_type;
0215     typedef typename base_type::date_gen_formatter_type date_gen_formatter_type;
0216     static const char_type* fractional_seconds_format;                // %f
0217     static const char_type* fractional_seconds_or_none_format;        // %F
0218     static const char_type* seconds_with_fractional_seconds_format;   // %s
0219     static const char_type* seconds_format;                           // %S
0220     static const char_type* hours_format;                             // %H
0221     static const char_type* unrestricted_hours_format;                // %O
0222     static const char_type* standard_format;                          // %x X
0223     static const char_type* zone_abbrev_format;                       // %z
0224     static const char_type* zone_name_format;                         // %Z
0225     static const char_type* zone_iso_format;                          // %q
0226     static const char_type* zone_iso_extended_format;                 // %Q
0227     static const char_type* posix_zone_string_format;                 // %ZP
0228     static const char_type* duration_seperator;
0229     static const char_type* duration_sign_always;                     // %+
0230     static const char_type* duration_sign_negative_only;              // %-
0231     static const char_type* negative_sign;                            //-
0232     static const char_type* positive_sign;                            //+
0233     static const char_type* iso_time_format_specifier;
0234     static const char_type* iso_time_format_extended_specifier;
0235 
0236     //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
0237     static const char_type* default_time_format;
0238     //default time_duration format is HH:MM:SS[.fff...]
0239     static const char_type* default_time_duration_format;
0240     static std::locale::id id;
0241 
0242 #if defined (__SUNPRO_CC) && defined (_RWSTD_VER)
0243       std::locale::id& __get_id (void) const { return id; }
0244 #endif
0245 
0246     //! sets default formats for ptime, local_date_time, and time_duration
0247     explicit time_facet(::size_t ref_arg = 0)
0248       : base_type(default_time_format, period_formatter_type(), special_values_formatter_type(), date_gen_formatter_type(), ref_arg),
0249         m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format)
0250     {}
0251 
0252     //! Construct the facet with an explicitly specified format
0253     explicit time_facet(const char_type* format_arg,
0254                         period_formatter_type period_formatter_arg = period_formatter_type(),
0255                         const special_values_formatter_type& special_value_formatter = special_values_formatter_type(),
0256                         date_gen_formatter_type dg_formatter = date_gen_formatter_type(),
0257                          ::size_t ref_arg = 0)
0258       : base_type(format_arg,
0259                   period_formatter_arg,
0260                   special_value_formatter,
0261                   dg_formatter,
0262                   ref_arg),
0263         m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format)
0264     {}
0265 
0266     //! Changes format for time_duration
0267     void time_duration_format(const char_type* const format)
0268     {
0269       m_time_duration_format = format;
0270     }
0271 
0272     void set_iso_format() BOOST_OVERRIDE
0273     {
0274       this->m_format = iso_time_format_specifier;
0275     }
0276     void set_iso_extended_format() BOOST_OVERRIDE
0277     {
0278       this->m_format = iso_time_format_extended_specifier;
0279     }
0280 
0281     OutItrT put(OutItrT next_arg,
0282                 std::ios_base& ios_arg,
0283                 char_type fill_arg,
0284                 const time_type& time_arg) const
0285     {
0286       if (time_arg.is_special()) {
0287         return this->do_put_special(next_arg, ios_arg, fill_arg,
0288                               time_arg.date().as_special());
0289       }
0290       string_type local_format(this->m_format);
0291 
0292       // %T and %R have to be replaced here since they are not standard
0293       boost::algorithm::replace_all(local_format,
0294         boost::as_literal(formats_type::full_24_hour_time_format),
0295         boost::as_literal(formats_type::full_24_hour_time_expanded_format));
0296       boost::algorithm::replace_all(local_format,
0297         boost::as_literal(formats_type::short_24_hour_time_format),
0298         boost::as_literal(formats_type::short_24_hour_time_expanded_format));
0299 
0300       string_type frac_str;
0301       if (local_format.find(seconds_with_fractional_seconds_format) != string_type::npos) {
0302         // replace %s with %S.nnn
0303         frac_str =
0304           fractional_seconds_as_string(time_arg.time_of_day(), false);
0305         char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
0306 
0307         string_type replace_string(seconds_format);
0308         replace_string += sep;
0309         replace_string += frac_str;
0310         boost::algorithm::replace_all(local_format,
0311                                       seconds_with_fractional_seconds_format,
0312                                       replace_string);
0313       }
0314       /* NOTE: replacing posix_zone_string_format must be done BEFORE
0315        * zone_name_format: "%ZP" & "%Z", if Z is checked first it will
0316        * incorrectly replace a zone_name where a posix_string should go */
0317       if (local_format.find(posix_zone_string_format) != string_type::npos) {
0318         if(time_arg.zone_abbrev().empty()) {
0319           // if zone_abbrev() returns an empty string, we want to
0320           // erase posix_zone_string_format from format
0321           boost::algorithm::erase_all(local_format, posix_zone_string_format);
0322         }
0323         else{
0324           boost::algorithm::replace_all(local_format,
0325                                         posix_zone_string_format,
0326                                         time_arg.zone_as_posix_string());
0327         }
0328       }
0329       if (local_format.find(zone_name_format) != string_type::npos) {
0330         if(time_arg.zone_name().empty()) {
0331           /* TODO: this'll probably create problems if a user places
0332            * the zone_*_format flag in the format with a ptime. This
0333            * code removes the flag from the default formats */
0334 
0335           // if zone_name() returns an empty string, we want to
0336           // erase zone_name_format & one preceeding space
0337           std::basic_ostringstream<char_type> ss;
0338           ss << ' ' << zone_name_format;
0339           boost::algorithm::erase_all(local_format, ss.str());
0340         }
0341         else{
0342           boost::algorithm::replace_all(local_format,
0343                                         zone_name_format,
0344                                         time_arg.zone_name());
0345         }
0346       }
0347       if (local_format.find(zone_abbrev_format) != string_type::npos) {
0348         if(time_arg.zone_abbrev(false).empty()) {
0349           /* TODO: this'll probably create problems if a user places
0350            * the zone_*_format flag in the format with a ptime. This
0351            * code removes the flag from the default formats */
0352 
0353           // if zone_abbrev() returns an empty string, we want to
0354           // erase zone_abbrev_format & one preceeding space
0355           std::basic_ostringstream<char_type> ss;
0356           ss << ' ' << zone_abbrev_format;
0357           boost::algorithm::erase_all(local_format, ss.str());
0358         }
0359         else{
0360           boost::algorithm::replace_all(local_format,
0361                                         zone_abbrev_format,
0362                                         time_arg.zone_abbrev(false));
0363         }
0364       }
0365       if (local_format.find(zone_iso_extended_format) != string_type::npos) {
0366         if(time_arg.zone_name(true).empty()) {
0367           /* TODO: this'll probably create problems if a user places
0368            * the zone_*_format flag in the format with a ptime. This
0369            * code removes the flag from the default formats */
0370 
0371           // if zone_name() returns an empty string, we want to
0372           // erase zone_iso_extended_format from format
0373           boost::algorithm::erase_all(local_format, zone_iso_extended_format);
0374         }
0375         else{
0376           boost::algorithm::replace_all(local_format,
0377                                         zone_iso_extended_format,
0378                                         time_arg.zone_name(true));
0379         }
0380       }
0381 
0382       if (local_format.find(zone_iso_format) != string_type::npos) {
0383         if(time_arg.zone_abbrev(true).empty()) {
0384           /* TODO: this'll probably create problems if a user places
0385            * the zone_*_format flag in the format with a ptime. This
0386            * code removes the flag from the default formats */
0387 
0388           // if zone_abbrev() returns an empty string, we want to
0389           // erase zone_iso_format from format
0390           boost::algorithm::erase_all(local_format, zone_iso_format);
0391         }
0392         else{
0393           boost::algorithm::replace_all(local_format,
0394                                         zone_iso_format,
0395                                         time_arg.zone_abbrev(true));
0396         }
0397       }
0398       if (local_format.find(fractional_seconds_format) != string_type::npos) {
0399         // replace %f with nnnnnnn
0400         if (frac_str.empty()) {
0401           frac_str = fractional_seconds_as_string(time_arg.time_of_day(), false);
0402         }
0403         boost::algorithm::replace_all(local_format,
0404                                       fractional_seconds_format,
0405                                       frac_str);
0406       }
0407 
0408       if (local_format.find(fractional_seconds_or_none_format) != string_type::npos) {
0409         // replace %F with nnnnnnn or nothing if fs == 0
0410         frac_str =
0411           fractional_seconds_as_string(time_arg.time_of_day(), true);
0412         if (!frac_str.empty()) {
0413           char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
0414           string_type replace_string;
0415           replace_string += sep;
0416           replace_string += frac_str;
0417           boost::algorithm::replace_all(local_format,
0418                                         fractional_seconds_or_none_format,
0419                                         replace_string);
0420         }
0421         else {
0422           boost::algorithm::erase_all(local_format,
0423                                       fractional_seconds_or_none_format);
0424         }
0425       }
0426 
0427       return this->do_put_tm(next_arg, ios_arg, fill_arg,
0428                        to_tm(time_arg), local_format);
0429     }
0430 
0431     //! put function for time_duration
0432     OutItrT put(OutItrT next_arg,
0433                 std::ios_base& ios_arg,
0434                 char_type fill_arg,
0435                 const time_duration_type& time_dur_arg) const
0436     {
0437       if (time_dur_arg.is_special()) {
0438         return this->do_put_special(next_arg, ios_arg, fill_arg,
0439                               time_dur_arg.get_rep().as_special());
0440       }
0441 
0442       string_type format(m_time_duration_format);
0443       if (time_dur_arg.is_negative()) {
0444         // replace %- with minus sign.  Should we use the numpunct facet?
0445         boost::algorithm::replace_all(format,
0446                                       duration_sign_negative_only,
0447                                       negative_sign);
0448           // remove all the %+ in the string with '-'
0449         boost::algorithm::replace_all(format,
0450                                       duration_sign_always,
0451                                       negative_sign);
0452       }
0453       else { //duration is positive
0454         // remove all the %- combos from the string
0455         boost::algorithm::erase_all(format, duration_sign_negative_only);
0456         // remove all the %+ in the string with '+'
0457         boost::algorithm::replace_all(format,
0458                                       duration_sign_always,
0459                                       positive_sign);
0460       }
0461 
0462       // %T and %R have to be replaced here since they are not standard
0463       boost::algorithm::replace_all(format,
0464         boost::as_literal(formats_type::full_24_hour_time_format),
0465         boost::as_literal(formats_type::full_24_hour_time_expanded_format));
0466       boost::algorithm::replace_all(format,
0467         boost::as_literal(formats_type::short_24_hour_time_format),
0468         boost::as_literal(formats_type::short_24_hour_time_expanded_format));
0469 
0470       /*
0471        * It is possible for a time duration to span more then 24 hours.
0472        * Standard time_put::put is obliged to behave the same as strftime
0473        * (See ISO 14882-2003 22.2.5.3.1 par. 1) and strftime's behavior is
0474        * unspecified for the case when tm_hour field is outside 0-23 range
0475        * (See ISO 9899-1999 7.23.3.5 par. 3). So we must output %H and %O
0476        * here ourself.
0477        */
0478       string_type hours_str;
0479       if (format.find(unrestricted_hours_format) != string_type::npos) {
0480         hours_str = hours_as_string(time_dur_arg);
0481         boost::algorithm::replace_all(format, unrestricted_hours_format, hours_str);
0482       }
0483       // We still have to process restricted hours format specifier. In order to
0484       // support parseability of durations in ISO 8601 format (%H%M%S), we'll have to
0485       // restrict the stringified hours length to 2 characters.
0486       if (format.find(hours_format) != string_type::npos) {
0487         if (hours_str.empty())
0488           hours_str = hours_as_string(time_dur_arg);
0489         BOOST_ASSERT(hours_str.length() <= 2);
0490         boost::algorithm::replace_all(format, hours_format, hours_str);
0491       }
0492 
0493       string_type frac_str;
0494       if (format.find(seconds_with_fractional_seconds_format) != string_type::npos) {
0495         // replace %s with %S.nnn
0496         frac_str =
0497           fractional_seconds_as_string(time_dur_arg, false);
0498         char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
0499 
0500         string_type replace_string(seconds_format);
0501         replace_string += sep;
0502         replace_string += frac_str;
0503         boost::algorithm::replace_all(format,
0504                                       seconds_with_fractional_seconds_format,
0505                                       replace_string);
0506       }
0507       if (format.find(fractional_seconds_format) != string_type::npos) {
0508         // replace %f with nnnnnnn
0509         if (!frac_str.size()) {
0510           frac_str = fractional_seconds_as_string(time_dur_arg, false);
0511         }
0512         boost::algorithm::replace_all(format,
0513                                       fractional_seconds_format,
0514                                       frac_str);
0515       }
0516 
0517       if (format.find(fractional_seconds_or_none_format) != string_type::npos) {
0518         // replace %F with nnnnnnn or nothing if fs == 0
0519         frac_str =
0520           fractional_seconds_as_string(time_dur_arg, true);
0521         if (frac_str.size()) {
0522           char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
0523           string_type replace_string;
0524           replace_string += sep;
0525           replace_string += frac_str;
0526           boost::algorithm::replace_all(format,
0527                                         fractional_seconds_or_none_format,
0528                                         replace_string);
0529         }
0530         else {
0531           boost::algorithm::erase_all(format,
0532                                       fractional_seconds_or_none_format);
0533         }
0534       }
0535 
0536       return this->do_put_tm(next_arg, ios_arg, fill_arg,
0537                        to_tm(time_dur_arg), format);
0538     }
0539 
0540     OutItrT put(OutItrT next, std::ios_base& ios_arg,
0541                 char_type fill, const period_type& p) const
0542     {
0543       return this->m_period_formatter.put_period(next, ios_arg, fill,p,*this);
0544     }
0545 
0546 
0547   protected:
0548 
0549     static
0550     string_type
0551     fractional_seconds_as_string(const time_duration_type& time_arg,
0552                                  bool null_when_zero)
0553     {
0554       typename time_duration_type::fractional_seconds_type frac_sec =
0555         time_arg.fractional_seconds();
0556 
0557       if (null_when_zero && (frac_sec == 0)) {
0558         return string_type();
0559       }
0560 
0561       //make sure there is no sign
0562       return integral_as_string(
0563         date_time::absolute_value(frac_sec),
0564         time_duration_type::num_fractional_digits());
0565     }
0566 
0567     static
0568     string_type
0569     hours_as_string(const time_duration_type& time_arg, int width = 2)
0570     {
0571       return integral_as_string(date_time::absolute_value(time_arg.hours()), width);
0572     }
0573 
0574     template< typename IntT >
0575     static
0576     string_type
0577     integral_as_string(IntT val, int width = 2)
0578     {
0579       std::basic_ostringstream<char_type> ss;
0580       ss.imbue(std::locale::classic()); // don't want any formatting
0581       ss << std::setw(width)
0582         << std::setfill(static_cast<char_type>('0'));
0583 #if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
0584       // JDG [7/6/02 VC++ compatibility]
0585       char_type buff[34];
0586       ss << _i64toa(static_cast<boost::int64_t>(val), buff, 10);
0587 #else
0588       ss << val;
0589 #endif
0590       return ss.str();
0591     }
0592 
0593   private:
0594     string_type m_time_duration_format;
0595 
0596   };
0597 
0598   template <class time_type, class CharT, class OutItrT>
0599   std::locale::id time_facet<time_type, CharT, OutItrT>::id;
0600 
0601   template <class time_type, class CharT, class OutItrT>
0602   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0603   time_facet<time_type, CharT, OutItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format;
0604 
0605   template <class time_type, class CharT, class OutItrT>
0606   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0607   time_facet<time_type, CharT, OutItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format;
0608 
0609   template <class time_type, class CharT, class OutItrT>
0610   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0611   time_facet<time_type, CharT, OutItrT>::seconds_with_fractional_seconds_format =
0612     time_formats<CharT>::seconds_with_fractional_seconds_format;
0613 
0614 
0615   template <class time_type, class CharT, class OutItrT>
0616   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0617   time_facet<time_type, CharT, OutItrT>::zone_name_format =  time_formats<CharT>::zone_name_format;
0618 
0619   template <class time_type, class CharT, class OutItrT>
0620   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0621   time_facet<time_type, CharT, OutItrT>::zone_abbrev_format =  time_formats<CharT>::zone_abbrev_format;
0622 
0623   template <class time_type, class CharT, class OutItrT>
0624   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0625   time_facet<time_type, CharT, OutItrT>::zone_iso_extended_format =time_formats<CharT>::zone_iso_extended_format;
0626 
0627   template <class time_type, class CharT, class OutItrT>
0628   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0629   time_facet<time_type, CharT, OutItrT>::posix_zone_string_format =time_formats<CharT>::posix_zone_string_format;
0630 
0631   template <class time_type, class CharT, class OutItrT>
0632   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0633   time_facet<time_type, CharT, OutItrT>::zone_iso_format =  time_formats<CharT>::zone_iso_format;
0634 
0635   template <class time_type, class CharT, class OutItrT>
0636   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0637   time_facet<time_type, CharT, OutItrT>::seconds_format =  time_formats<CharT>::seconds_format;
0638 
0639   template <class time_type, class CharT, class OutItrT>
0640   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0641   time_facet<time_type, CharT, OutItrT>::hours_format =  time_formats<CharT>::hours_format;
0642 
0643   template <class time_type, class CharT, class OutItrT>
0644   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0645   time_facet<time_type, CharT, OutItrT>::unrestricted_hours_format =  time_formats<CharT>::unrestricted_hours_format;
0646 
0647   template <class time_type, class CharT, class OutItrT>
0648   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0649   time_facet<time_type, CharT, OutItrT>::standard_format =  time_formats<CharT>::standard_format;
0650 
0651   template <class time_type, class CharT, class OutItrT>
0652   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0653   time_facet<time_type, CharT, OutItrT>::duration_seperator =  time_formats<CharT>::duration_seperator;
0654 
0655   template <class time_type, class CharT, class OutItrT>
0656   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0657   time_facet<time_type, CharT, OutItrT>::negative_sign =  time_formats<CharT>::negative_sign;
0658 
0659   template <class time_type, class CharT, class OutItrT>
0660   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0661   time_facet<time_type, CharT, OutItrT>::positive_sign =  time_formats<CharT>::positive_sign;
0662 
0663   template <class time_type, class CharT, class OutItrT>
0664   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0665   time_facet<time_type, CharT, OutItrT>::duration_sign_negative_only =  time_formats<CharT>::duration_sign_negative_only;
0666 
0667   template <class time_type, class CharT, class OutItrT>
0668   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0669   time_facet<time_type, CharT, OutItrT>::duration_sign_always =  time_formats<CharT>::duration_sign_always;
0670 
0671   template <class time_type, class CharT, class OutItrT>
0672   const typename time_facet<time_type,CharT, OutItrT>::char_type*
0673   time_facet<time_type,CharT, OutItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier;
0674 
0675   template <class time_type, class CharT, class OutItrT>
0676   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0677   time_facet<time_type, CharT, OutItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier;
0678 
0679   template <class time_type, class CharT, class OutItrT>
0680   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0681   time_facet<time_type, CharT, OutItrT>::default_time_format =
0682     time_formats<CharT>::default_time_format;
0683 
0684   template <class time_type, class CharT, class OutItrT>
0685   const typename time_facet<time_type, CharT, OutItrT>::char_type*
0686   time_facet<time_type, CharT, OutItrT>::default_time_duration_format =
0687     time_formats<CharT>::default_time_duration_format;
0688 
0689 
0690   //! Facet for format-based input.
0691   /*!
0692    */
0693   template <class time_type,
0694             class CharT,
0695             class InItrT = std::istreambuf_iterator<CharT, std::char_traits<CharT> > >
0696   class BOOST_SYMBOL_VISIBLE time_input_facet :
0697     public boost::date_time::date_input_facet<typename time_type::date_type , CharT, InItrT> {
0698     public:
0699       typedef typename time_type::date_type date_type;
0700       typedef typename time_type::time_duration_type time_duration_type;
0701       typedef typename time_duration_type::fractional_seconds_type fracional_seconds_type;
0702       typedef boost::date_time::period<time_type,time_duration_type> period_type;
0703       typedef boost::date_time::date_input_facet<typename time_type::date_type, CharT, InItrT> base_type;
0704       typedef typename base_type::duration_type date_duration_type;
0705       typedef typename base_type::year_type year_type;
0706       typedef typename base_type::month_type month_type;
0707       typedef typename base_type::day_type day_type;
0708       typedef typename base_type::string_type string_type;
0709       typedef typename string_type::const_iterator const_itr;
0710       typedef typename base_type::char_type   char_type;
0711       typedef typename base_type::format_date_parser_type format_date_parser_type;
0712       typedef typename base_type::period_parser_type period_parser_type;
0713       typedef typename base_type::special_values_parser_type special_values_parser_type;
0714       typedef typename base_type::date_gen_parser_type date_gen_parser_type;
0715       typedef typename base_type::special_values_parser_type::match_results match_results;
0716 
0717       static const char_type* fractional_seconds_format;                // f
0718       static const char_type* fractional_seconds_or_none_format;        // F
0719       static const char_type* seconds_with_fractional_seconds_format;   // s
0720       static const char_type* seconds_format;                           // S
0721       static const char_type* standard_format;                          // x X
0722       static const char_type* zone_abbrev_format;                       // z
0723       static const char_type* zone_name_format;                         // Z
0724       static const char_type* zone_iso_format;                          // q
0725       static const char_type* zone_iso_extended_format;                 // Q
0726       static const char_type* duration_seperator;
0727       static const char_type* iso_time_format_specifier;
0728       static const char_type* iso_time_format_extended_specifier;
0729       static const char_type* default_time_input_format;
0730       static const char_type* default_time_duration_format;
0731       static std::locale::id id;
0732 
0733       //! Constructor that takes a format string for a ptime
0734       explicit time_input_facet(const string_type& format, ::size_t ref_arg = 0)
0735         : base_type(format, ref_arg),
0736           m_time_duration_format(default_time_duration_format)
0737       { }
0738 
0739       explicit time_input_facet(const string_type& format,
0740                                 const format_date_parser_type& date_parser,
0741                                 const special_values_parser_type& sv_parser,
0742                                 const period_parser_type& per_parser,
0743                                 const date_gen_parser_type& date_gen_parser,
0744                                 ::size_t ref_arg = 0)
0745         : base_type(format,
0746                     date_parser,
0747                     sv_parser,
0748                     per_parser,
0749                     date_gen_parser,
0750                     ref_arg),
0751           m_time_duration_format(default_time_duration_format)
0752       {}
0753 
0754       //! sets default formats for ptime, local_date_time, and time_duration
0755       explicit time_input_facet(::size_t ref_arg = 0)
0756         : base_type(default_time_input_format, ref_arg),
0757           m_time_duration_format(default_time_duration_format)
0758       { }
0759 
0760       //! Set the format for time_duration
0761       void time_duration_format(const char_type* const format) {
0762         m_time_duration_format = format;
0763       }
0764       virtual void set_iso_format()
0765       {
0766         this->m_format = iso_time_format_specifier;
0767       }
0768       virtual void set_iso_extended_format()
0769       {
0770         this->m_format = iso_time_format_extended_specifier;
0771       }
0772 
0773       InItrT get(InItrT& sitr,
0774                  InItrT& stream_end,
0775                  std::ios_base& ios_arg,
0776                  period_type& p) const
0777       {
0778         p = this->m_period_parser.get_period(sitr,
0779                                              stream_end,
0780                                              ios_arg,
0781                                              p,
0782                                              time_duration_type::unit(),
0783                                              *this);
0784         return sitr;
0785       }
0786 
0787       //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
0788       //default time_duration format is %H:%M:%S%F HH:MM:SS[.fff...]
0789 
0790       InItrT get(InItrT& sitr,
0791                  InItrT& stream_end,
0792                  std::ios_base& ios_arg,
0793                  time_duration_type& td) const
0794       {
0795         // skip leading whitespace
0796         while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; }
0797 
0798         bool use_current_char = false;
0799 
0800         // num_get will consume the +/-, we may need a copy if special_value
0801         char_type c = '\0';
0802         if((sitr != stream_end) && (*sitr == '-' || *sitr == '+')) {
0803           c = *sitr;
0804         }
0805 
0806         typedef typename time_duration_type::hour_type hour_type;
0807         typedef typename time_duration_type::min_type min_type;
0808         typedef typename time_duration_type::sec_type sec_type;
0809 
0810         hour_type hour = 0;
0811         min_type min = 0;
0812         sec_type sec = 0;
0813         typename time_duration_type::fractional_seconds_type frac(0);
0814 
0815         typedef std::num_get<CharT, InItrT> num_get;
0816         if(!std::has_facet<num_get>(ios_arg.getloc())) {
0817           num_get* ng = new num_get();
0818           std::locale loc = std::locale(ios_arg.getloc(), ng);
0819           ios_arg.imbue(loc);
0820         }
0821 
0822         const_itr itr(m_time_duration_format.begin());
0823         while (itr != m_time_duration_format.end() && (sitr != stream_end)) {
0824           if (*itr == '%') {
0825             if (++itr == m_time_duration_format.end()) break;
0826             if (*itr != '%') {
0827               switch(*itr) {
0828               case 'O':
0829                 {
0830                   // A period may span more than 24 hours. In that case the format
0831                   // string should be composed with the unrestricted hours specifier.
0832                   hour = var_string_to_int<hour_type, CharT>(sitr, stream_end,
0833                                       std::numeric_limits<hour_type>::digits10 + 1);
0834                   if(hour == -1){
0835                      return check_special_value(sitr, stream_end, td, c);
0836                   }
0837                   break;
0838                 }
0839               case 'H':
0840                 {
0841                   match_results mr;
0842                   hour = fixed_string_to_int<hour_type, CharT>(sitr, stream_end, mr, 2);
0843                   if(hour == -1){
0844                      return check_special_value(sitr, stream_end, td, c);
0845                   }
0846                   break;
0847                 }
0848               case 'M':
0849                 {
0850                   match_results mr;
0851                   min = fixed_string_to_int<min_type, CharT>(sitr, stream_end, mr, 2);
0852                   if(min == -1){
0853                      return check_special_value(sitr, stream_end, td, c);
0854                   }
0855                   break;
0856                 }
0857               case 's':
0858               case 'S':
0859                 {
0860                   match_results mr;
0861                   sec = fixed_string_to_int<sec_type, CharT>(sitr, stream_end, mr, 2);
0862                   if(sec == -1){
0863                      return check_special_value(sitr, stream_end, td, c);
0864                   }
0865                   if (*itr == 'S')
0866                     break;
0867                   // %s is the same as %S%f so we drop through into %f
0868                 }
0869                 /* Falls through. */
0870               case 'f':
0871                 {
0872                   // check for decimal, check special_values if missing
0873                   if(*sitr == '.') {
0874                     ++sitr;
0875                     parse_frac_type(sitr, stream_end, frac);
0876                     // sitr will point to next expected char after this parsing
0877                     // is complete so no need to advance it
0878                     use_current_char = true;
0879                   }
0880                   else {
0881                     return check_special_value(sitr, stream_end, td, c);
0882                   }
0883                   break;
0884                 }
0885               case 'F':
0886                 {
0887                   // check for decimal, skip if missing
0888                   if(*sitr == '.') {
0889                     ++sitr;
0890                     parse_frac_type(sitr, stream_end, frac);
0891                     // sitr will point to next expected char after this parsing
0892                     // is complete so no need to advance it
0893                     use_current_char = true;
0894                   }
0895                   else {
0896                     // nothing was parsed so we don't want to advance sitr
0897                     use_current_char = true;
0898                   }
0899                   break;
0900                 }
0901               default:
0902                 {} // ignore what we don't understand?
0903               }// switch
0904             }
0905             else { // itr == '%', second consecutive
0906               ++sitr;
0907             }
0908 
0909             ++itr; //advance past format specifier
0910           }
0911           else {  //skip past chars in format and in buffer
0912             ++itr;
0913             // set use_current_char when sitr is already
0914             // pointing at the next character to process
0915             if (use_current_char) {
0916               use_current_char = false;
0917             }
0918             else {
0919               ++sitr;
0920             }
0921           }
0922         }
0923 
0924         td = time_duration_type(hour, min, sec, frac);
0925         return sitr;
0926       }
0927 
0928 
0929       //! Parses a time object from the input stream
0930       InItrT get(InItrT& sitr,
0931                  InItrT& stream_end,
0932                  std::ios_base& ios_arg,
0933                  time_type& t) const
0934       {
0935         string_type tz_str;
0936         return get(sitr, stream_end, ios_arg, t, tz_str, false);
0937       }
0938       //! Expects a time_zone in the input stream
0939       InItrT get_local_time(InItrT& sitr,
0940                             InItrT& stream_end,
0941                             std::ios_base& ios_arg,
0942                             time_type& t,
0943                             string_type& tz_str) const
0944       {
0945         return get(sitr, stream_end, ios_arg, t, tz_str, true);
0946       }
0947 
0948     protected:
0949 
0950       InItrT get(InItrT& sitr,
0951                  InItrT& stream_end,
0952                  std::ios_base& ios_arg,
0953                  time_type& t,
0954                  string_type& tz_str,
0955                  bool time_is_local) const
0956       {
0957         // skip leading whitespace
0958         while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; }
0959 
0960         bool use_current_char = false;
0961         bool use_current_format_char = false; // used with two character flags
0962 
0963         // num_get will consume the +/-, we may need a copy if special_value
0964         char_type c = '\0';
0965         if((sitr != stream_end) && (*sitr == '-' || *sitr == '+')) {
0966           c = *sitr;
0967         }
0968 
0969         typedef typename time_duration_type::hour_type hour_type;
0970         typedef typename time_duration_type::min_type min_type;
0971         typedef typename time_duration_type::sec_type sec_type;
0972 
0973         // time elements
0974         hour_type hour = 0;
0975         min_type min = 0;
0976         sec_type sec = 0;
0977         typename time_duration_type::fractional_seconds_type frac(0);
0978         // date elements
0979         short day_of_year(0);
0980         /* Initialized the following to their minimum values. These intermediate
0981          * objects are used so we get specific exceptions when part of the input
0982          * is unparsable.
0983          * Ex: "205-Jan-15" will throw a bad_year, "2005-Jsn-15"- bad_month, etc.*/
0984         year_type t_year(1400);
0985         month_type t_month(1);
0986         day_type t_day(1);
0987 
0988         typedef std::num_get<CharT, InItrT> num_get;
0989         if(!std::has_facet<num_get>(ios_arg.getloc())) {
0990           num_get* ng = new num_get();
0991           std::locale loc = std::locale(ios_arg.getloc(), ng);
0992           ios_arg.imbue(loc);
0993         }
0994 
0995         const_itr itr(this->m_format.begin());
0996         while (itr != this->m_format.end() && (sitr != stream_end)) {
0997           if (*itr == '%') {
0998             if (++itr == this->m_format.end()) break;
0999             if (*itr != '%') {
1000               // the cases are grouped by date & time flags - not alphabetical order
1001               switch(*itr) {
1002                 // date flags
1003                 case 'Y':
1004                 case 'y':
1005                   {
1006                     char_type cs[3] = { '%', *itr };
1007                     string_type s(cs);
1008                     match_results mr;
1009                     try {
1010                       t_year = this->m_parser.parse_year(sitr, stream_end, s, mr);
1011                     }
1012                     catch(std::out_of_range&) { // base class for bad_year exception
1013                       if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1014                         t = time_type(static_cast<special_values>(mr.current_match));
1015                         return sitr;
1016                       }
1017                       else {
1018                         throw; // rethrow bad_year
1019                       }
1020                     }
1021                     break;
1022                   }
1023                 case 'B':
1024                 case 'b':
1025                 case 'm':
1026                   {
1027                     char_type cs[3] = { '%', *itr };
1028                     string_type s(cs);
1029                     match_results mr;
1030                     try {
1031                       t_month = this->m_parser.parse_month(sitr, stream_end, s, mr);
1032                     }
1033                     catch(std::out_of_range&) { // base class for bad_month exception
1034                       if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1035                         t = time_type(static_cast<special_values>(mr.current_match));
1036                         return sitr;
1037                       }
1038                       else {
1039                         throw; // rethrow bad_month
1040                       }
1041                     }
1042                     // did m_parser already advance sitr to next char?
1043                     if(mr.has_remaining()) {
1044                       use_current_char = true;
1045                     }
1046                     break;
1047                   }
1048                 case 'a':
1049                 case 'A':
1050                 case 'w':
1051                   {
1052                     // weekday is not used in construction but we need to get it out of the stream
1053                     char_type cs[3] = { '%', *itr };
1054                     string_type s(cs);
1055                     match_results mr;
1056                     typename date_type::day_of_week_type wd(0);
1057                     try {
1058                       wd = this->m_parser.parse_weekday(sitr, stream_end, s, mr);
1059                     }
1060                     catch(std::out_of_range&) { // base class for bad_weekday exception
1061                       if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1062                         t = time_type(static_cast<special_values>(mr.current_match));
1063                         return sitr;
1064                       }
1065                       else {
1066                         throw; // rethrow bad_weekday
1067                       }
1068                     }
1069                     // did m_parser already advance sitr to next char?
1070                     if(mr.has_remaining()) {
1071                       use_current_char = true;
1072                     }
1073                     break;
1074                   }
1075                 case 'j':
1076                   {
1077                     // code that gets julian day (from format_date_parser)
1078                     match_results mr;
1079                     day_of_year = fixed_string_to_int<unsigned short, CharT>(sitr, stream_end, mr, 3);
1080                     if(day_of_year == -1) {
1081                       if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1082                         t = time_type(static_cast<special_values>(mr.current_match));
1083                         return sitr;
1084                       }
1085                     }
1086                     // these next two lines are so we get an exception with bad input
1087                     typedef typename time_type::date_type::day_of_year_type day_of_year_type;
1088                     day_of_year_type t_day_of_year(day_of_year);
1089                     break;
1090                   }
1091                 case 'd':
1092                 case 'e':
1093                   {
1094                     try {
1095                       t_day = (*itr == 'd') ?
1096                           this->m_parser.parse_day_of_month(sitr, stream_end) :
1097                           this->m_parser.parse_var_day_of_month(sitr, stream_end);
1098                     }
1099                     catch(std::out_of_range&) { // base class for exception bad_day_of_month
1100                       match_results mr;
1101                       if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1102                         t = time_type(static_cast<special_values>(mr.current_match));
1103                         return sitr;
1104                       }
1105                       else {
1106                         throw; // rethrow bad_day_of_month
1107                       }
1108                     }
1109                     break;
1110                   }
1111                 // time flags
1112                 case 'H':
1113                   {
1114                     match_results mr;
1115                     hour = fixed_string_to_int<hour_type, CharT>(sitr, stream_end, mr, 2);
1116                     if(hour == -1){
1117                        return check_special_value(sitr, stream_end, t, c);
1118                     }
1119                     break;
1120                   }
1121                 case 'M':
1122                   {
1123                     match_results mr;
1124                     min = fixed_string_to_int<min_type, CharT>(sitr, stream_end, mr, 2);
1125                     if(min == -1){
1126                        return check_special_value(sitr, stream_end, t, c);
1127                     }
1128                     break;
1129                   }
1130                 case 's':
1131                 case 'S':
1132                   {
1133                     match_results mr;
1134                     sec = fixed_string_to_int<sec_type, CharT>(sitr, stream_end, mr, 2);
1135                     if(sec == -1){
1136                        return check_special_value(sitr, stream_end, t, c);
1137                     }
1138                     if (*itr == 'S' || sitr == stream_end)
1139                       break;
1140                     // %s is the same as %S%f so we drop through into %f if we are
1141                     // not at the end of the stream
1142                   }
1143                   /* Falls through. */
1144                 case 'f':
1145                   {
1146                     // check for decimal, check SV if missing
1147                     if(*sitr == '.') {
1148                       ++sitr;
1149                       parse_frac_type(sitr, stream_end, frac);
1150                       // sitr will point to next expected char after this parsing
1151                       // is complete so no need to advance it
1152                       use_current_char = true;
1153                     }
1154                     else {
1155                       return check_special_value(sitr, stream_end, t, c);
1156                     }
1157                     break;
1158                   }
1159                 case 'F':
1160                   {
1161                     // check for decimal, skip if missing
1162                     if(*sitr == '.') {
1163                       ++sitr;
1164                       parse_frac_type(sitr, stream_end, frac);
1165                       // sitr will point to next expected char after this parsing
1166                       // is complete so no need to advance it
1167                       use_current_char = true;
1168                     }
1169                     else {
1170                       // nothing was parsed so we don't want to advance sitr
1171                       use_current_char = true;
1172                     }
1173                     break;
1174                   }
1175                   // time_zone flags
1176                 //case 'q':
1177                 //case 'Q':
1178                 //case 'z':
1179                 case 'Z':
1180                   {
1181                     if(time_is_local) { // skip if 't' is a ptime
1182                       ++itr;
1183                       if(*itr == 'P') {
1184                         // skip leading whitespace
1185                         while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; }
1186                         // parse zone
1187                         while((sitr != stream_end) && (!std::isspace(*sitr))) {
1188                           tz_str += *sitr;
1189                           ++sitr;
1190                         }
1191                       }
1192                       else {
1193                         use_current_format_char = true;
1194                       }
1195 
1196                     }
1197                     else {
1198                       // nothing was parsed so we don't want to advance sitr
1199                       use_current_char = true;
1200                     }
1201 
1202                     break;
1203                   }
1204                 default:
1205                 {} // ignore what we don't understand?
1206               }// switch
1207             }
1208             else { // itr == '%', second consecutive
1209               ++sitr;
1210             }
1211 
1212             if(use_current_format_char) {
1213               use_current_format_char = false;
1214             }
1215             else {
1216               ++itr; //advance past format specifier
1217             }
1218 
1219           }
1220           else {  //skip past chars in format and in buffer
1221             ++itr;
1222             // set use_current_char when sitr is already
1223             // pointing at the next character to process
1224             if (use_current_char) {
1225               use_current_char = false;
1226             }
1227             else {
1228               ++sitr;
1229             }
1230           }
1231         }
1232 
1233         date_type d(not_a_date_time);
1234         if (day_of_year > 0) {
1235           d = date_type(static_cast<unsigned short>(t_year),1,1) + date_duration_type(day_of_year-1);
1236         }
1237         else {
1238           d = date_type(t_year, t_month, t_day);
1239         }
1240 
1241         time_duration_type td(hour, min, sec, frac);
1242         t = time_type(d, td);
1243         return sitr;
1244       }
1245 
1246       //! Helper function to check for special_value
1247       /*! First character may have been consumed during original parse
1248        * attempt. Parameter 'c' should be a copy of that character.
1249        * Throws ios_base::failure if parse fails. */
1250       template<class temporal_type>
1251       inline
1252       InItrT check_special_value(InItrT& sitr,InItrT& stream_end, temporal_type& tt, char_type c='\0') const
1253       {
1254         match_results mr;
1255         if((c == '-' || c == '+') && (*sitr != c)) { // was the first character consumed?
1256           mr.cache += c;
1257         }
1258         (void)this->m_sv_parser.match(sitr, stream_end, mr);
1259         if(mr.current_match == match_results::PARSE_ERROR) {
1260           std::string tmp = convert_string_type<char_type, char>(mr.cache);
1261           boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + tmp + "'"));
1262           BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(return sitr); // should never reach
1263         }
1264         tt = temporal_type(static_cast<special_values>(mr.current_match));
1265         return sitr;
1266       }
1267 
1268       //! Helper function for parsing a fractional second type from the stream
1269       void parse_frac_type(InItrT& sitr,
1270                            InItrT& stream_end,
1271                            fracional_seconds_type& frac) const
1272       {
1273         string_type cache;
1274         while((sitr != stream_end) && std::isdigit(*sitr)) {
1275           cache += *sitr;
1276           ++sitr;
1277         }
1278         if(cache.size() > 0) {
1279           unsigned short precision = time_duration_type::num_fractional_digits();
1280           // input may be only the first few decimal places
1281           if(cache.size() < precision) {
1282             frac = lexical_cast<fracional_seconds_type>(cache);
1283             frac = decimal_adjust(frac, static_cast<unsigned short>(precision - cache.size()));
1284           }
1285           else {
1286             // if input has too many decimal places, drop excess digits
1287             frac = lexical_cast<fracional_seconds_type>(cache.substr(0, precision));
1288           }
1289         }
1290       }
1291 
1292     private:
1293       string_type m_time_duration_format;
1294 
1295       //! Helper function to adjust trailing zeros when parsing fractional digits
1296       template<class int_type>
1297       inline
1298       int_type decimal_adjust(int_type val, const unsigned short places) const
1299       {
1300         unsigned long factor = 1;
1301         for(int i = 0; i < places; ++i){
1302           factor *= 10; // shift decimal to the right
1303         }
1304         return val * factor;
1305       }
1306 
1307   };
1308 
1309 template <class time_type, class CharT, class InItrT>
1310   std::locale::id time_input_facet<time_type, CharT, InItrT>::id;
1311 
1312 template <class time_type, class CharT, class InItrT>
1313   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1314   time_input_facet<time_type, CharT, InItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format;
1315 
1316   template <class time_type, class CharT, class InItrT>
1317   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1318   time_input_facet<time_type, CharT, InItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format;
1319 
1320   template <class time_type, class CharT, class InItrT>
1321   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1322   time_input_facet<time_type, CharT, InItrT>::seconds_with_fractional_seconds_format = time_formats<CharT>::seconds_with_fractional_seconds_format;
1323 
1324   template <class time_type, class CharT, class InItrT>
1325   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1326   time_input_facet<time_type, CharT, InItrT>::seconds_format = time_formats<CharT>::seconds_format;
1327 
1328   template <class time_type, class CharT, class InItrT>
1329   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1330   time_input_facet<time_type, CharT, InItrT>::standard_format = time_formats<CharT>::standard_format;
1331 
1332   template <class time_type, class CharT, class InItrT>
1333   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1334   time_input_facet<time_type, CharT, InItrT>::zone_abbrev_format = time_formats<CharT>::zone_abbrev_format;
1335 
1336   template <class time_type, class CharT, class InItrT>
1337   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1338   time_input_facet<time_type, CharT, InItrT>::zone_name_format = time_formats<CharT>::zone_name_format;
1339 
1340   template <class time_type, class CharT, class InItrT>
1341   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1342   time_input_facet<time_type, CharT, InItrT>::zone_iso_format = time_formats<CharT>::zone_iso_format;
1343 
1344   template <class time_type, class CharT, class InItrT>
1345   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1346   time_input_facet<time_type, CharT, InItrT>::zone_iso_extended_format = time_formats<CharT>::zone_iso_extended_format;
1347 
1348   template <class time_type, class CharT, class InItrT>
1349   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1350   time_input_facet<time_type, CharT, InItrT>::duration_seperator = time_formats<CharT>::duration_seperator;
1351 
1352   template <class time_type, class CharT, class InItrT>
1353   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1354   time_input_facet<time_type, CharT, InItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier;
1355 
1356   template <class time_type, class CharT, class InItrT>
1357   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1358   time_input_facet<time_type, CharT, InItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier;
1359 
1360   template <class time_type, class CharT, class InItrT>
1361   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1362   time_input_facet<time_type, CharT, InItrT>::default_time_input_format = time_formats<CharT>::default_time_input_format;
1363 
1364   template <class time_type, class CharT, class InItrT>
1365   const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1366   time_input_facet<time_type, CharT, InItrT>::default_time_duration_format = time_formats<CharT>::default_time_duration_format;
1367 
1368 } } // namespaces
1369 
1370 #endif