Back to home page

EIC code displayed by LXR

 
 

    


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

0001 
0002 #ifndef DATE_TIME_FORMAT_DATE_PARSER_HPP__
0003 #define DATE_TIME_FORMAT_DATE_PARSER_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: Jeff Garland, Bart Garst
0010  * $Date$
0011  */
0012 
0013 
0014 #include "boost/lexical_cast.hpp"
0015 #include "boost/date_time/string_parse_tree.hpp"
0016 #include "boost/date_time/strings_from_facet.hpp"
0017 #include "boost/date_time/special_values_parser.hpp"
0018 #include <string>
0019 #include <vector>
0020 #include <sstream>
0021 #include <iterator>
0022 #ifndef BOOST_NO_STDC_NAMESPACE
0023 #  include <cctype>
0024 #else
0025 #  include <ctype.h>
0026 #endif
0027 
0028 #ifdef BOOST_NO_STDC_NAMESPACE
0029 namespace std {
0030   using ::isspace;
0031   using ::isdigit;
0032 }
0033 #endif
0034 namespace boost { namespace date_time {
0035 
0036 //! Helper function for parsing fixed length strings into integers
0037 /*! Will consume 'length' number of characters from stream. Consumed
0038  * character are transfered to parse_match_result struct.
0039  * Returns '-1' if no number can be parsed or incorrect number of
0040  * digits in stream. */
0041 template<typename int_type, typename charT>
0042 inline
0043 int_type
0044 fixed_string_to_int(std::istreambuf_iterator<charT>& itr,
0045                     std::istreambuf_iterator<charT>& stream_end,
0046                     parse_match_result<charT>& mr,
0047                     unsigned int length,
0048                     const charT& fill_char)
0049 {
0050   //typedef std::basic_string<charT>  string_type;
0051   unsigned int j = 0;
0052   //string_type s;
0053   while (j < length && itr != stream_end &&
0054       (std::isdigit(*itr) || *itr == fill_char)) {
0055     if(*itr == fill_char) {
0056       /* Since a fill_char can be anything, we convert it to a zero.
0057        * lexical_cast will behave predictably when zero is used as fill. */
0058       mr.cache += ('0');
0059     }
0060     else {
0061       mr.cache += (*itr);
0062     }
0063     itr++;
0064     j++;
0065   }
0066   int_type i = static_cast<int_type>(-1);
0067   // mr.cache will hold leading zeros. size() tells us when input is too short.
0068   if(mr.cache.size() < length) {
0069     return i;
0070   }
0071   try {
0072     i = boost::lexical_cast<int_type>(mr.cache);
0073   }catch(bad_lexical_cast&){
0074     // we want to return -1 if the cast fails so nothing to do here
0075   }
0076   return i;
0077 }
0078 
0079 //! Helper function for parsing fixed length strings into integers
0080 /*! Will consume 'length' number of characters from stream. Consumed
0081  * character are transfered to parse_match_result struct.
0082  * Returns '-1' if no number can be parsed or incorrect number of
0083  * digits in stream. */
0084 template<typename int_type, typename charT>
0085 inline
0086 int_type
0087 fixed_string_to_int(std::istreambuf_iterator<charT>& itr,
0088                     std::istreambuf_iterator<charT>& stream_end,
0089                     parse_match_result<charT>& mr,
0090                     unsigned int length)
0091 {
0092   return fixed_string_to_int<int_type, charT>(itr, stream_end, mr, length, '0');
0093 }
0094 
0095 //! Helper function for parsing varied length strings into integers
0096 /*! Will consume 'max_length' characters from stream only if those
0097  * characters are digits. Returns '-1' if no number can be parsed.
0098  * Will not parse a number preceeded by a '+' or '-'. */
0099 template<typename int_type, typename charT>
0100 inline
0101 int_type
0102 var_string_to_int(std::istreambuf_iterator<charT>& itr,
0103                   const std::istreambuf_iterator<charT>& stream_end,
0104                   unsigned int max_length)
0105 {
0106   typedef std::basic_string<charT>  string_type;
0107   unsigned int j = 0;
0108   string_type s;
0109   while (itr != stream_end && (j < max_length) && std::isdigit(*itr)) {
0110     s += (*itr);
0111     ++itr;
0112     ++j;
0113   }
0114   int_type i = static_cast<int_type>(-1);
0115   if(!s.empty()) {
0116     i = boost::lexical_cast<int_type>(s);
0117   }
0118   return i;
0119 }
0120 
0121 
0122 //! Class with generic date parsing using a format string
0123 /*! The following is the set of recognized format specifiers
0124  -  %a - Short weekday name
0125  -  %A - Long weekday name
0126  -  %b - Abbreviated month name
0127  -  %B - Full month name
0128  -  %d - Day of the month as decimal 01 to 31
0129  -  %j - Day of year as decimal from 001 to 366
0130  -  %m - Month name as a decimal 01 to 12
0131  -  %U - Week number 00 to 53 with first Sunday as the first day of week 1?
0132  -  %w - Weekday as decimal number 0 to 6 where Sunday == 0
0133  -  %W - Week number 00 to 53 where Monday is first day of week 1
0134  -  %x - facet default date representation
0135  -  %y - Year without the century - eg: 04 for 2004
0136  -  %Y - Year with century
0137 
0138  The weekday specifiers (%a and %A) do not add to the date construction,
0139  but they provide a way to skip over the weekday names for formats that
0140  provide them.
0141 
0142  todo -- Another interesting feature that this approach could provide is
0143          an option to fill in any missing fields with the current values
0144          from the clock.  So if you have %m-%d the parser would detect
0145          the missing year value and fill it in using the clock.
0146 
0147  todo -- What to do with the %x.  %x in the classic facet is just bad...
0148 
0149  */
0150 template<class date_type, typename charT>
0151 class format_date_parser
0152 {
0153  public:
0154   typedef std::basic_string<charT>        string_type;
0155   typedef std::basic_istringstream<charT>  stringstream_type;
0156   typedef std::istreambuf_iterator<charT> stream_itr_type;
0157   typedef typename string_type::const_iterator const_itr;
0158   typedef typename date_type::year_type  year_type;
0159   typedef typename date_type::month_type month_type;
0160   typedef typename date_type::day_type day_type;
0161   typedef typename date_type::duration_type duration_type;
0162   typedef typename date_type::day_of_week_type day_of_week_type;
0163   typedef typename date_type::day_of_year_type day_of_year_type;
0164   typedef string_parse_tree<charT> parse_tree_type;
0165   typedef typename parse_tree_type::parse_match_result_type match_results;
0166   typedef std::vector<std::basic_string<charT> > input_collection_type;
0167 
0168   // TODO sv_parser uses its default constructor - write the others
0169 
0170   format_date_parser(const string_type& format_str,
0171                      const input_collection_type& month_short_names,
0172                      const input_collection_type& month_long_names,
0173                      const input_collection_type& weekday_short_names,
0174                      const input_collection_type& weekday_long_names) :
0175     m_format(format_str),
0176     m_month_short_names(month_short_names, 1),
0177     m_month_long_names(month_long_names, 1),
0178     m_weekday_short_names(weekday_short_names),
0179     m_weekday_long_names(weekday_long_names)
0180   {}
0181 
0182   format_date_parser(const string_type& format_str,
0183                      const std::locale& locale) :
0184     m_format(format_str),
0185     m_month_short_names(gather_month_strings<charT>(locale), 1),
0186     m_month_long_names(gather_month_strings<charT>(locale, false), 1),
0187     m_weekday_short_names(gather_weekday_strings<charT>(locale)),
0188     m_weekday_long_names(gather_weekday_strings<charT>(locale, false))
0189   {}
0190 
0191   format_date_parser(const format_date_parser<date_type,charT>& fdp)
0192   {
0193     this->m_format = fdp.m_format;
0194     this->m_month_short_names = fdp.m_month_short_names;
0195     this->m_month_long_names = fdp.m_month_long_names;
0196     this->m_weekday_short_names = fdp.m_weekday_short_names;
0197     this->m_weekday_long_names = fdp.m_weekday_long_names;
0198   }
0199 
0200   string_type format() const
0201   {
0202     return m_format;
0203   }
0204 
0205   void format(string_type format_str)
0206   {
0207     m_format = format_str;
0208   }
0209 
0210   void short_month_names(const input_collection_type& month_names)
0211   {
0212     m_month_short_names = parse_tree_type(month_names, 1);
0213   }
0214   void long_month_names(const input_collection_type& month_names)
0215   {
0216     m_month_long_names = parse_tree_type(month_names, 1);
0217   }
0218   void short_weekday_names(const input_collection_type& weekday_names)
0219   {
0220     m_weekday_short_names = parse_tree_type(weekday_names);
0221   }
0222   void long_weekday_names(const input_collection_type& weekday_names)
0223   {
0224     m_weekday_long_names = parse_tree_type(weekday_names);
0225   }
0226 
0227   date_type
0228   parse_date(const string_type& value,
0229              const string_type& format_str,
0230              const special_values_parser<date_type,charT>& sv_parser) const
0231   {
0232     stringstream_type ss(value);
0233     stream_itr_type sitr(ss);
0234     stream_itr_type stream_end;
0235     return parse_date(sitr, stream_end, format_str, sv_parser);
0236   }
0237 
0238   date_type
0239   parse_date(std::istreambuf_iterator<charT>& sitr,
0240              std::istreambuf_iterator<charT>& stream_end,
0241              const special_values_parser<date_type,charT>& sv_parser) const
0242   {
0243     return parse_date(sitr, stream_end, m_format, sv_parser);
0244   }
0245 
0246   /*! Of all the objects that the format_date_parser can parse, only a
0247    * date can be a special value. Therefore, only parse_date checks
0248    * for special_values. */
0249   date_type
0250   parse_date(std::istreambuf_iterator<charT>& sitr,
0251              std::istreambuf_iterator<charT>& stream_end,
0252              string_type format_str,
0253              const special_values_parser<date_type,charT>& sv_parser) const
0254   {
0255     bool use_current_char = false;
0256 
0257     // skip leading whitespace
0258     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0259 
0260     short year(0), month(0), day(0), day_of_year(0);// wkday(0);
0261     /* Initialized the following to their minimum values. These intermediate
0262      * objects are used so we get specific exceptions when part of the input
0263      * is unparsable.
0264      * Ex: "205-Jan-15" will throw a bad_year, "2005-Jsn-15"- bad_month, etc.*/
0265     year_type t_year(1400);
0266     month_type t_month(1);
0267     day_type t_day(1);
0268     day_of_week_type wkday(0);
0269 
0270 
0271     const_itr itr(format_str.begin());
0272     while (itr != format_str.end() && (sitr != stream_end)) {
0273       if (*itr == '%') {
0274         if ( ++itr == format_str.end())
0275           break;
0276         if (*itr != '%') {
0277           switch(*itr) {
0278           case 'a':
0279             {
0280               //this value is just throw away.  It could be used for
0281               //error checking potentially, but it isn't helpful in
0282               //actually constructing the date - we just need to get it
0283               //out of the stream
0284               match_results mr = m_weekday_short_names.match(sitr, stream_end);
0285               if(mr.current_match == match_results::PARSE_ERROR) {
0286                 // check special_values
0287                 if(sv_parser.match(sitr, stream_end, mr)) {
0288                   return date_type(static_cast<special_values>(mr.current_match));
0289                 }
0290               }
0291               wkday = mr.current_match;
0292               if (mr.has_remaining()) {
0293                 use_current_char = true;
0294               }
0295               break;
0296             }
0297           case 'A':
0298             {
0299               //this value is just throw away.  It could be used for
0300               //error checking potentially, but it isn't helpful in
0301               //actually constructing the date - we just need to get it
0302               //out of the stream
0303               match_results mr = m_weekday_long_names.match(sitr, stream_end);
0304               if(mr.current_match == match_results::PARSE_ERROR) {
0305                 // check special_values
0306                 if(sv_parser.match(sitr, stream_end, mr)) {
0307                   return date_type(static_cast<special_values>(mr.current_match));
0308                 }
0309               }
0310               wkday = mr.current_match;
0311               if (mr.has_remaining()) {
0312                 use_current_char = true;
0313               }
0314               break;
0315             }
0316           case 'b':
0317             {
0318               match_results mr = m_month_short_names.match(sitr, stream_end);
0319               if(mr.current_match == match_results::PARSE_ERROR) {
0320                 // check special_values
0321                 if(sv_parser.match(sitr, stream_end, mr)) {
0322                   return date_type(static_cast<special_values>(mr.current_match));
0323                 }
0324               }
0325               t_month = month_type(mr.current_match);
0326               if (mr.has_remaining()) {
0327                 use_current_char = true;
0328               }
0329               break;
0330             }
0331           case 'B':
0332             {
0333               match_results mr = m_month_long_names.match(sitr, stream_end);
0334               if(mr.current_match == match_results::PARSE_ERROR) {
0335                 // check special_values
0336                 if(sv_parser.match(sitr, stream_end, mr)) {
0337                   return date_type(static_cast<special_values>(mr.current_match));
0338                 }
0339               }
0340               t_month = month_type(mr.current_match);
0341               if (mr.has_remaining()) {
0342                 use_current_char = true;
0343               }
0344               break;
0345             }
0346           case 'd':
0347             {
0348               match_results mr;
0349               day = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
0350               if(day == -1) {
0351                 if(sv_parser.match(sitr, stream_end, mr)) {
0352                   return date_type(static_cast<special_values>(mr.current_match));
0353                 }
0354               }
0355               t_day = day_type(day);
0356               break;
0357             }
0358           case 'e':
0359             {
0360               match_results mr;
0361               day = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2, ' ');
0362               if(day == -1) {
0363                 if(sv_parser.match(sitr, stream_end, mr)) {
0364                   return date_type(static_cast<special_values>(mr.current_match));
0365                 }
0366               }
0367               t_day = day_type(day);
0368               break;
0369             }
0370           case 'j':
0371             {
0372               match_results mr;
0373               day_of_year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 3);
0374               if(day_of_year == -1) {
0375                 if(sv_parser.match(sitr, stream_end, mr)) {
0376                   return date_type(static_cast<special_values>(mr.current_match));
0377                 }
0378               }
0379               // these next two lines are so we get an exception with bad input
0380               day_of_year_type t_day_of_year(1);
0381               t_day_of_year = day_of_year_type(day_of_year);
0382               break;
0383             }
0384           case 'm':
0385             {
0386               match_results mr;
0387               month = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
0388               if(month == -1) {
0389                 if(sv_parser.match(sitr, stream_end, mr)) {
0390                   return date_type(static_cast<special_values>(mr.current_match));
0391                 }
0392               }
0393               t_month = month_type(month);
0394               break;
0395             }
0396           case 'Y':
0397             {
0398               match_results mr;
0399               year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 4);
0400               if(year == -1) {
0401                 if(sv_parser.match(sitr, stream_end, mr)) {
0402                   return date_type(static_cast<special_values>(mr.current_match));
0403                 }
0404               }
0405               t_year = year_type(year);
0406               break;
0407             }
0408           case 'y':
0409             {
0410               match_results mr;
0411               year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
0412               if(year == -1) {
0413                 if(sv_parser.match(sitr, stream_end, mr)) {
0414                   return date_type(static_cast<special_values>(mr.current_match));
0415                 }
0416               }
0417               year += 2000; //make 2 digit years in this century
0418               t_year = year_type(year);
0419               break;
0420             }
0421           default:
0422             {} //ignore those we don't understand
0423 
0424           }//switch
0425 
0426         }
0427         else { // itr == '%', second consecutive
0428           sitr++;
0429         }
0430 
0431         itr++; //advance past format specifier
0432       }
0433       else {  //skip past chars in format and in buffer
0434         itr++;
0435         if (use_current_char) {
0436           use_current_char = false;
0437         }
0438         else {
0439           sitr++;
0440         }
0441       }
0442     }
0443 
0444     if (day_of_year > 0) {
0445       date_type d(static_cast<unsigned short>(year-1),12,31); //end of prior year
0446       return d + duration_type(day_of_year);
0447     }
0448 
0449     return date_type(t_year, t_month, t_day); // exceptions were thrown earlier
0450                                         // if input was no good
0451   }
0452 
0453   //! Throws bad_month if unable to parse
0454   month_type
0455   parse_month(std::istreambuf_iterator<charT>& sitr,
0456              std::istreambuf_iterator<charT>& stream_end,
0457              string_type format_str) const
0458   {
0459     match_results mr;
0460     return parse_month(sitr, stream_end, format_str, mr);
0461   }
0462 
0463   //! Throws bad_month if unable to parse
0464   month_type
0465   parse_month(std::istreambuf_iterator<charT>& sitr,
0466              std::istreambuf_iterator<charT>& stream_end,
0467              string_type format_str,
0468              match_results& mr) const
0469   {
0470     bool use_current_char = false;
0471 
0472     // skip leading whitespace
0473     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0474 
0475     short month(0);
0476 
0477     const_itr itr(format_str.begin());
0478     while (itr != format_str.end() && (sitr != stream_end)) {
0479       if (*itr == '%') {
0480         if ( ++itr == format_str.end())
0481           break;
0482         if (*itr != '%') {
0483           switch(*itr) {
0484           case 'b':
0485             {
0486               mr = m_month_short_names.match(sitr, stream_end);
0487               month = mr.current_match;
0488               if (mr.has_remaining()) {
0489                 use_current_char = true;
0490               }
0491               break;
0492             }
0493           case 'B':
0494             {
0495               mr = m_month_long_names.match(sitr, stream_end);
0496               month = mr.current_match;
0497               if (mr.has_remaining()) {
0498                 use_current_char = true;
0499               }
0500               break;
0501             }
0502           case 'm':
0503             {
0504               month = var_string_to_int<short, charT>(sitr, stream_end, 2);
0505               // var_string_to_int returns -1 if parse failed. That will
0506               // cause a bad_month exception to be thrown so we do nothing here
0507               break;
0508             }
0509           default:
0510             {} //ignore those we don't understand
0511 
0512           }//switch
0513 
0514         }
0515         else { // itr == '%', second consecutive
0516           sitr++;
0517         }
0518 
0519         itr++; //advance past format specifier
0520       }
0521       else {  //skip past chars in format and in buffer
0522         itr++;
0523         if (use_current_char) {
0524           use_current_char = false;
0525         }
0526         else {
0527           sitr++;
0528         }
0529       }
0530     }
0531 
0532     return month_type(month); // throws bad_month exception when values are zero
0533   }
0534 
0535   //! Expects 1 or 2 digits 1-31. Throws bad_day_of_month if unable to parse
0536   day_type
0537   parse_var_day_of_month(std::istreambuf_iterator<charT>& sitr,
0538                          std::istreambuf_iterator<charT>& stream_end) const
0539   {
0540     // skip leading whitespace
0541     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0542 
0543     return day_type(var_string_to_int<short, charT>(sitr, stream_end, 2));
0544   }
0545   //! Expects 2 digits 01-31. Throws bad_day_of_month if unable to parse
0546   day_type
0547   parse_day_of_month(std::istreambuf_iterator<charT>& sitr,
0548                      std::istreambuf_iterator<charT>& stream_end) const
0549   {
0550     // skip leading whitespace
0551     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0552 
0553     //return day_type(var_string_to_int<short, charT>(sitr, stream_end, 2));
0554     match_results mr;
0555     return day_type(fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2));
0556   }
0557 
0558   day_of_week_type
0559   parse_weekday(std::istreambuf_iterator<charT>& sitr,
0560              std::istreambuf_iterator<charT>& stream_end,
0561              string_type format_str) const
0562   {
0563     match_results mr;
0564     return parse_weekday(sitr, stream_end, format_str, mr);
0565   }
0566   day_of_week_type
0567   parse_weekday(std::istreambuf_iterator<charT>& sitr,
0568              std::istreambuf_iterator<charT>& stream_end,
0569              string_type format_str,
0570              match_results& mr) const
0571   {
0572     bool use_current_char = false;
0573 
0574     // skip leading whitespace
0575     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0576 
0577     short wkday(0);
0578 
0579     const_itr itr(format_str.begin());
0580     while (itr != format_str.end() && (sitr != stream_end)) {
0581       if (*itr == '%') {
0582         if ( ++itr == format_str.end())
0583           break;
0584         if (*itr != '%') {
0585           switch(*itr) {
0586           case 'a':
0587             {
0588               //this value is just throw away.  It could be used for
0589               //error checking potentially, but it isn't helpful in
0590               //actually constructing the date - we just need to get it
0591               //out of the stream
0592               mr = m_weekday_short_names.match(sitr, stream_end);
0593               wkday = mr.current_match;
0594               if (mr.has_remaining()) {
0595                 use_current_char = true;
0596               }
0597               break;
0598             }
0599           case 'A':
0600             {
0601               //this value is just throw away.  It could be used for
0602               //error checking potentially, but it isn't helpful in
0603               //actually constructing the date - we just need to get it
0604               //out of the stream
0605               mr = m_weekday_long_names.match(sitr, stream_end);
0606               wkday = mr.current_match;
0607               if (mr.has_remaining()) {
0608                 use_current_char = true;
0609               }
0610               break;
0611             }
0612           case 'w':
0613             {
0614               // weekday as number 0-6, Sunday == 0
0615               wkday = var_string_to_int<short, charT>(sitr, stream_end, 2);
0616               break;
0617             }
0618           default:
0619             {} //ignore those we don't understand
0620 
0621           }//switch
0622 
0623         }
0624         else { // itr == '%', second consecutive
0625           sitr++;
0626         }
0627 
0628         itr++; //advance past format specifier
0629       }
0630       else {  //skip past chars in format and in buffer
0631         itr++;
0632         if (use_current_char) {
0633           use_current_char = false;
0634         }
0635         else {
0636           sitr++;
0637         }
0638       }
0639     }
0640 
0641     return day_of_week_type(wkday); // throws bad_day_of_month exception
0642                                     // when values are zero
0643   }
0644 
0645   //! throws bad_year if unable to parse
0646   year_type
0647   parse_year(std::istreambuf_iterator<charT>& sitr,
0648              std::istreambuf_iterator<charT>& stream_end,
0649              string_type format_str) const
0650   {
0651     match_results mr;
0652     return parse_year(sitr, stream_end, format_str, mr);
0653   }
0654 
0655   //! throws bad_year if unable to parse
0656   year_type
0657   parse_year(std::istreambuf_iterator<charT>& sitr,
0658              std::istreambuf_iterator<charT>& stream_end,
0659              string_type format_str,
0660              match_results& mr) const
0661   {
0662     // skip leading whitespace
0663     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0664 
0665     unsigned short year(0);
0666 
0667     const_itr itr(format_str.begin());
0668     while (itr != format_str.end() && (sitr != stream_end)) {
0669       if (*itr == '%') {
0670         if ( ++itr == format_str.end())
0671           break;
0672         if (*itr != '%') {
0673           //match_results mr;
0674           switch(*itr) {
0675           case 'Y':
0676             {
0677               // year from 4 digit string
0678               year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 4);
0679               break;
0680             }
0681           case 'y':
0682             {
0683               // year from 2 digit string (no century)
0684               year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
0685               year += 2000; //make 2 digit years in this century
0686               break;
0687             }
0688           default:
0689             {} //ignore those we don't understand
0690 
0691           }//switch
0692 
0693         }
0694         else { // itr == '%', second consecutive
0695           sitr++;
0696         }
0697 
0698         itr++; //advance past format specifier
0699       }
0700       else {  //skip past chars in format and in buffer
0701         itr++;
0702         sitr++;
0703       }
0704     }
0705 
0706     return year_type(year); // throws bad_year exception when values are zero
0707   }
0708 
0709 
0710  private:
0711   string_type m_format;
0712   parse_tree_type m_month_short_names;
0713   parse_tree_type m_month_long_names;
0714   parse_tree_type m_weekday_short_names;
0715   parse_tree_type m_weekday_long_names;
0716 
0717 };
0718 
0719 } } //namespace
0720 
0721 #endif
0722 
0723 
0724