ossrv_pub/boost_apis/boost/date_time/format_date_parser.hpp
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 
       
     2 #ifndef DATE_TIME_FORMAT_DATE_PARSER_HPP__
       
     3 #define DATE_TIME_FORMAT_DATE_PARSER_HPP__
       
     4 
       
     5 /* Copyright (c) 2004-2005 CrystalClear Software, Inc.
       
     6  * Use, modification and distribution is subject to the 
       
     7  * Boost Software License, Version 1.0. (See accompanying
       
     8  * file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
       
     9  * Author: Jeff Garland, Bart Garst
       
    10  * $Date: 2006/02/18 20:58:01 $
       
    11  */
       
    12 
       
    13 
       
    14 #include "boost/lexical_cast.hpp"
       
    15 #include "boost/date_time/string_parse_tree.hpp"
       
    16 #include "boost/date_time/strings_from_facet.hpp"
       
    17 #include "boost/date_time/special_values_parser.hpp"
       
    18 #include <string>
       
    19 #include <vector>
       
    20 
       
    21 namespace boost { namespace date_time {
       
    22   
       
    23 //! Helper function for parsing fixed length strings into integers
       
    24 /*! Will consume 'length' number of characters from stream. Consumed 
       
    25  * character are transfered to parse_match_result struct. 
       
    26  * Returns '-1' if no number can be parsed or incorrect number of 
       
    27  * digits in stream. */
       
    28 template<typename int_type, typename charT>
       
    29 inline
       
    30 int_type
       
    31 fixed_string_to_int(std::istreambuf_iterator<charT>& itr,
       
    32                     std::istreambuf_iterator<charT>& stream_end,
       
    33                     parse_match_result<charT>& mr,
       
    34                     unsigned int length,
       
    35                     const charT& fill_char)
       
    36 {
       
    37   //typedef std::basic_string<charT>  string_type;
       
    38   unsigned int j = 0;
       
    39   //string_type s;
       
    40   while (j < length && itr != stream_end && 
       
    41       (std::isdigit(*itr) || *itr == fill_char)) {
       
    42     if(*itr == fill_char) {
       
    43       /* Since a fill_char can be anything, we convert it to a zero. 
       
    44        * lexical_cast will behave predictably when zero is used as fill. */
       
    45       mr.cache += ('0'); 
       
    46     }
       
    47     else {
       
    48       mr.cache += (*itr);
       
    49     }
       
    50     itr++;
       
    51     j++;
       
    52   }
       
    53   int_type i = -1;
       
    54   // mr.cache will hold leading zeros. size() tells us when input is too short.
       
    55   if(mr.cache.size() < length) {
       
    56     return i;
       
    57   }
       
    58   try {
       
    59     i = boost::lexical_cast<int_type>(mr.cache);
       
    60   }catch(bad_lexical_cast blc){
       
    61     // we want to return -1 if the cast fails so nothing to do here
       
    62   }
       
    63   return i;
       
    64 }
       
    65 
       
    66 //! Helper function for parsing fixed length strings into integers
       
    67 /*! Will consume 'length' number of characters from stream. Consumed 
       
    68  * character are transfered to parse_match_result struct. 
       
    69  * Returns '-1' if no number can be parsed or incorrect number of 
       
    70  * digits in stream. */
       
    71 template<typename int_type, typename charT>
       
    72 inline
       
    73 int_type
       
    74 fixed_string_to_int(std::istreambuf_iterator<charT>& itr,
       
    75                     std::istreambuf_iterator<charT>& stream_end,
       
    76                     parse_match_result<charT>& mr,
       
    77                     unsigned int length)
       
    78 {
       
    79   return fixed_string_to_int<int_type, charT>(itr, stream_end, mr, length, '0');
       
    80 }
       
    81 
       
    82 //! Helper function for parsing varied length strings into integers
       
    83 /*! Will consume 'max_length' characters from stream only if those 
       
    84  * characters are digits. Returns '-1' if no number can be parsed. 
       
    85  * Will not parse a number preceeded by a '+' or '-'. */
       
    86 template<typename int_type, typename charT>
       
    87 inline
       
    88 int_type
       
    89 var_string_to_int(std::istreambuf_iterator<charT>& itr,
       
    90                   std::istreambuf_iterator<charT>& stream_end,
       
    91                   unsigned int max_length)
       
    92 {
       
    93   typedef std::basic_string<charT>  string_type;
       
    94   unsigned int j = 0;
       
    95   string_type s;
       
    96   while ((j < max_length) && std::isdigit(*itr)) {
       
    97     s += (*itr);
       
    98     itr++;
       
    99     j++;
       
   100   }
       
   101   int_type i = -1;
       
   102   if(s.length() != 0) {
       
   103     i = boost::lexical_cast<int_type>(s);
       
   104   }
       
   105   return i;
       
   106 }
       
   107 
       
   108 
       
   109 //! Class with generic date parsing using a format string
       
   110 /*! The following is the set of recognized format specifiers
       
   111  -  %a - Short weekday name
       
   112  -  %A - Long weekday name
       
   113  -  %b - Abbreviated month name
       
   114  -  %B - Full month name
       
   115  -  %d - Day of the month as decimal 01 to 31
       
   116  -  %j - Day of year as decimal from 001 to 366
       
   117  -  %m - Month name as a decimal 01 to 12
       
   118  -  %U - Week number 00 to 53 with first Sunday as the first day of week 1?
       
   119  -  %w - Weekday as decimal number 0 to 6 where Sunday == 0
       
   120  -  %W - Week number 00 to 53 where Monday is first day of week 1
       
   121  -  %x - facet default date representation
       
   122  -  %y - Year without the century - eg: 04 for 2004
       
   123  -  %Y - Year with century 
       
   124 
       
   125  The weekday specifiers (%a and %A) do not add to the date construction,
       
   126  but they provide a way to skip over the weekday names for formats that
       
   127  provide them.
       
   128 
       
   129  todo -- Another interesting feature that this approach could provide is
       
   130          an option to fill in any missing fields with the current values
       
   131          from the clock.  So if you have %m-%d the parser would detect
       
   132          the missing year value and fill it in using the clock. 
       
   133 
       
   134  todo -- What to do with the %x.  %x in the classic facet is just bad...
       
   135 
       
   136  */
       
   137 template<class date_type, typename charT>
       
   138 class format_date_parser
       
   139 {
       
   140  public:
       
   141   typedef std::basic_string<charT>        string_type;
       
   142   typedef std::basic_ostringstream<charT>  stringstream_type;
       
   143   typedef std::istreambuf_iterator<charT> stream_itr_type;
       
   144   typedef typename string_type::const_iterator const_itr;
       
   145   typedef typename date_type::year_type  year_type;
       
   146   typedef typename date_type::month_type month_type;
       
   147   typedef typename date_type::day_type day_type;
       
   148   typedef typename date_type::duration_type duration_type;
       
   149   typedef typename date_type::day_of_week_type day_of_week_type;
       
   150   typedef typename date_type::day_of_year_type day_of_year_type;
       
   151   typedef string_parse_tree<charT> parse_tree_type;
       
   152   typedef typename parse_tree_type::parse_match_result_type match_results;
       
   153   typedef std::vector<std::basic_string<charT> > input_collection_type;
       
   154 
       
   155   // TODO sv_parser uses its default constructor - write the others
       
   156   
       
   157   format_date_parser(const string_type& format_str,
       
   158                      const input_collection_type& month_short_names,
       
   159                      const input_collection_type& month_long_names,
       
   160                      const input_collection_type& weekday_short_names,
       
   161                      const input_collection_type& weekday_long_names) :
       
   162     m_format(format_str),
       
   163     m_month_short_names(month_short_names, 1),
       
   164     m_month_long_names(month_long_names, 1),
       
   165     m_weekday_short_names(weekday_short_names),
       
   166     m_weekday_long_names(weekday_long_names)
       
   167   {}
       
   168   
       
   169   format_date_parser(const string_type& format_str,
       
   170                      const std::locale& locale) :
       
   171     m_format(format_str),
       
   172     m_month_short_names(gather_month_strings<charT>(locale), 1),
       
   173     m_month_long_names(gather_month_strings<charT>(locale, false), 1),
       
   174     m_weekday_short_names(gather_weekday_strings<charT>(locale)),
       
   175     m_weekday_long_names(gather_weekday_strings<charT>(locale, false))
       
   176   {}
       
   177 
       
   178   format_date_parser(const format_date_parser<date_type,charT>& fdp)
       
   179   {
       
   180     this->m_format = fdp.m_format;
       
   181     this->m_month_short_names = fdp.m_month_short_names;
       
   182     this->m_month_long_names = fdp.m_month_long_names;
       
   183     this->m_weekday_short_names = fdp.m_weekday_short_names;
       
   184     this->m_weekday_long_names = fdp.m_weekday_long_names;
       
   185   }
       
   186   
       
   187   string_type format() const
       
   188   {
       
   189     return m_format;
       
   190   }
       
   191 
       
   192   void format(string_type format_str)
       
   193   {
       
   194     m_format = format_str;
       
   195   }
       
   196 
       
   197   void short_month_names(const input_collection_type& month_names)
       
   198   {
       
   199     m_month_short_names = parse_tree_type(month_names, 1);
       
   200   }
       
   201   void long_month_names(const input_collection_type& month_names)
       
   202   {
       
   203     m_month_long_names = parse_tree_type(month_names, 1);
       
   204   }
       
   205   void short_weekday_names(const input_collection_type& weekday_names)
       
   206   {
       
   207     m_weekday_short_names = parse_tree_type(weekday_names);
       
   208   }
       
   209   void long_weekday_names(const input_collection_type& weekday_names)
       
   210   {
       
   211     m_weekday_long_names = parse_tree_type(weekday_names);
       
   212   }
       
   213 
       
   214   date_type
       
   215   parse_date(const string_type& value, 
       
   216              const string_type& format_str,
       
   217              const special_values_parser<date_type,charT>& sv_parser) const
       
   218   {
       
   219     stringstream_type ss;
       
   220     ss << value; 
       
   221     stream_itr_type sitr(ss);
       
   222     stream_itr_type stream_end;
       
   223     return parse_date(sitr, stream_end, format_str, sv_parser);
       
   224   }
       
   225 
       
   226   date_type
       
   227   parse_date(std::istreambuf_iterator<charT>& sitr, 
       
   228              std::istreambuf_iterator<charT>& stream_end,
       
   229              const special_values_parser<date_type,charT>& sv_parser) const
       
   230   {
       
   231     return parse_date(sitr, stream_end, m_format, sv_parser);
       
   232   }
       
   233 
       
   234   /*! Of all the objects that the format_date_parser can parse, only a 
       
   235    * date can be a special value. Therefore, only parse_date checks 
       
   236    * for special_values. */
       
   237   date_type
       
   238   parse_date(std::istreambuf_iterator<charT>& sitr, 
       
   239              std::istreambuf_iterator<charT>& stream_end,
       
   240              string_type format_str,
       
   241              const special_values_parser<date_type,charT>& sv_parser) const
       
   242   {
       
   243     bool use_current_char = false;
       
   244     
       
   245     // skip leading whitespace
       
   246     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 
       
   247     charT current_char = *sitr;
       
   248 
       
   249     short year(0), month(0), day(0), day_of_year(0);// wkday(0); 
       
   250     /* Initialized the following to their minimum values. These intermediate 
       
   251      * objects are used so we get specific exceptions when part of the input 
       
   252      * is unparsable. 
       
   253      * Ex: "205-Jan-15" will throw a bad_year, "2005-Jsn-15"- bad_month, etc.*/
       
   254     year_type t_year(1400);
       
   255     month_type t_month(1);
       
   256     day_type t_day(1);
       
   257     day_of_week_type wkday(0);
       
   258     
       
   259     
       
   260     const_itr itr(format_str.begin());
       
   261     while (itr != format_str.end() && (sitr != stream_end)) {
       
   262       if (*itr == '%') {
       
   263         itr++;
       
   264         if (*itr != '%') {
       
   265           switch(*itr) {
       
   266           case 'a': 
       
   267             {
       
   268               //this value is just throw away.  It could be used for
       
   269               //error checking potentially, but it isn't helpful in 
       
   270               //actually constructing the date - we just need to get it
       
   271               //out of the stream
       
   272               match_results mr = m_weekday_short_names.match(sitr, stream_end);
       
   273               if(mr.current_match == match_results::PARSE_ERROR) {
       
   274                 // check special_values
       
   275                 if(sv_parser.match(sitr, stream_end, mr)) {
       
   276                   return date_type(static_cast<special_values>(mr.current_match));
       
   277                 }
       
   278               }
       
   279               wkday = mr.current_match;
       
   280               if (mr.has_remaining()) {
       
   281                 current_char = mr.last_char();
       
   282                 use_current_char = true;
       
   283               }
       
   284               break;
       
   285             }
       
   286           case 'A': 
       
   287             {
       
   288               //this value is just throw away.  It could be used for
       
   289               //error checking potentially, but it isn't helpful in 
       
   290               //actually constructing the date - we just need to get it
       
   291               //out of the stream
       
   292               match_results mr = m_weekday_long_names.match(sitr, stream_end);
       
   293               if(mr.current_match == match_results::PARSE_ERROR) {
       
   294                 // check special_values
       
   295                 if(sv_parser.match(sitr, stream_end, mr)) {
       
   296                   return date_type(static_cast<special_values>(mr.current_match));
       
   297                 }
       
   298               }
       
   299               wkday = mr.current_match;
       
   300               if (mr.has_remaining()) {
       
   301                 current_char = mr.last_char();
       
   302                 use_current_char = true;
       
   303               }
       
   304               break;
       
   305             }
       
   306           case 'b': 
       
   307             {
       
   308               match_results mr = m_month_short_names.match(sitr, stream_end);
       
   309               if(mr.current_match == match_results::PARSE_ERROR) {
       
   310                 // check special_values
       
   311                 if(sv_parser.match(sitr, stream_end, mr)) {
       
   312                   return date_type(static_cast<special_values>(mr.current_match));
       
   313                 }
       
   314               }
       
   315               t_month = month_type(mr.current_match);
       
   316               if (mr.has_remaining()) {
       
   317                 current_char = mr.last_char();
       
   318                 use_current_char = true;
       
   319               }
       
   320               break;
       
   321             }
       
   322           case 'B': 
       
   323             {
       
   324               match_results mr = m_month_long_names.match(sitr, stream_end);
       
   325               if(mr.current_match == match_results::PARSE_ERROR) {
       
   326                 // check special_values
       
   327                 if(sv_parser.match(sitr, stream_end, mr)) {
       
   328                   return date_type(static_cast<special_values>(mr.current_match));
       
   329                 }
       
   330               }
       
   331               t_month = month_type(mr.current_match);
       
   332               if (mr.has_remaining()) {
       
   333                 current_char = mr.last_char();
       
   334                 use_current_char = true;
       
   335               }
       
   336               break;
       
   337             }
       
   338           case 'd': 
       
   339             {
       
   340               match_results mr;
       
   341               day = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
       
   342               if(day == -1) {
       
   343                 if(sv_parser.match(sitr, stream_end, mr)) {
       
   344                   return date_type(static_cast<special_values>(mr.current_match));
       
   345                 }
       
   346               }
       
   347               t_day = day_type(day);
       
   348               break;
       
   349             }
       
   350           case 'e': 
       
   351             {
       
   352               match_results mr;
       
   353               day = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2, ' ');
       
   354               if(day == -1) {
       
   355                 if(sv_parser.match(sitr, stream_end, mr)) {
       
   356                   return date_type(static_cast<special_values>(mr.current_match));
       
   357                 }
       
   358               }
       
   359               t_day = day_type(day);
       
   360               break;
       
   361             }
       
   362           case 'j': 
       
   363             {
       
   364               match_results mr;
       
   365               day_of_year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 3);
       
   366               if(day_of_year == -1) {
       
   367                 if(sv_parser.match(sitr, stream_end, mr)) {
       
   368                   return date_type(static_cast<special_values>(mr.current_match));
       
   369                 }
       
   370               }
       
   371               // these next two lines are so we get an exception with bad input
       
   372               day_of_year_type t_day_of_year(1);
       
   373               t_day_of_year = day_of_year_type(day_of_year);
       
   374               break;
       
   375             }
       
   376           case 'm': 
       
   377             {
       
   378               match_results mr;
       
   379               month = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
       
   380               if(month == -1) {
       
   381                 if(sv_parser.match(sitr, stream_end, mr)) {
       
   382                   return date_type(static_cast<special_values>(mr.current_match));
       
   383                 }
       
   384               }
       
   385               t_month = month_type(month);
       
   386               break;
       
   387             }
       
   388           case 'Y': 
       
   389             {
       
   390               match_results mr;
       
   391               year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 4);
       
   392               if(year == -1) {
       
   393                 if(sv_parser.match(sitr, stream_end, mr)) {
       
   394                   return date_type(static_cast<special_values>(mr.current_match));
       
   395                 }
       
   396               }
       
   397               t_year = year_type(year);
       
   398               break;
       
   399             }
       
   400           case 'y': 
       
   401             {
       
   402               match_results mr;
       
   403               year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
       
   404               if(year == -1) {
       
   405                 if(sv_parser.match(sitr, stream_end, mr)) {
       
   406                   return date_type(static_cast<special_values>(mr.current_match));
       
   407                 }
       
   408               }
       
   409               year += 2000; //make 2 digit years in this century
       
   410               t_year = year_type(year);
       
   411               break;
       
   412             }
       
   413           default:
       
   414             {} //ignore those we don't understand
       
   415             
       
   416           }//switch
       
   417           
       
   418         }
       
   419         else { // itr == '%', second consecutive
       
   420           sitr++;
       
   421         }
       
   422         
       
   423         itr++; //advance past format specifier
       
   424       }
       
   425       else {  //skip past chars in format and in buffer
       
   426         itr++;
       
   427         if (use_current_char) {
       
   428           use_current_char = false;
       
   429           current_char = *sitr;
       
   430         }
       
   431         else {
       
   432           sitr++;
       
   433         }
       
   434       }
       
   435     }
       
   436     
       
   437     if (day_of_year > 0) {
       
   438       date_type d(static_cast<unsigned short>(year-1),12,31); //end of prior year
       
   439       return d + duration_type(day_of_year);
       
   440     }
       
   441     
       
   442     return date_type(t_year, t_month, t_day); // exceptions were thrown earlier 
       
   443                                         // if input was no good 
       
   444   }
       
   445  
       
   446   //! Throws bad_month if unable to parse
       
   447   month_type
       
   448   parse_month(std::istreambuf_iterator<charT>& sitr, 
       
   449              std::istreambuf_iterator<charT>& stream_end,
       
   450              string_type format_str) const
       
   451   {
       
   452     match_results mr;
       
   453     return parse_month(sitr, stream_end, format_str, mr);
       
   454   }
       
   455  
       
   456   //! Throws bad_month if unable to parse
       
   457   month_type
       
   458   parse_month(std::istreambuf_iterator<charT>& sitr, 
       
   459              std::istreambuf_iterator<charT>& stream_end,
       
   460              string_type format_str,
       
   461              match_results& mr) const
       
   462   {
       
   463     bool use_current_char = false;
       
   464     
       
   465     // skip leading whitespace
       
   466     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 
       
   467     charT current_char = *sitr;
       
   468 
       
   469     short month(0);
       
   470     
       
   471     const_itr itr(format_str.begin());
       
   472     while (itr != format_str.end() && (sitr != stream_end)) {
       
   473       if (*itr == '%') {
       
   474         itr++;
       
   475         if (*itr != '%') {
       
   476           switch(*itr) {
       
   477           case 'b': 
       
   478             {
       
   479               mr = m_month_short_names.match(sitr, stream_end);
       
   480               month = mr.current_match;
       
   481               if (mr.has_remaining()) {
       
   482                 current_char = mr.last_char();
       
   483                 use_current_char = true;
       
   484               }
       
   485               break;
       
   486             }
       
   487           case 'B': 
       
   488             {
       
   489               mr = m_month_long_names.match(sitr, stream_end);
       
   490               month = mr.current_match;
       
   491               if (mr.has_remaining()) {
       
   492                 current_char = mr.last_char();
       
   493                 use_current_char = true;
       
   494               }
       
   495               break;
       
   496             }
       
   497           case 'm': 
       
   498             {
       
   499               month = var_string_to_int<short, charT>(sitr, stream_end, 2);
       
   500               // var_string_to_int returns -1 if parse failed. That will 
       
   501               // cause a bad_month exception to be thrown so we do nothing here
       
   502               break;
       
   503             }
       
   504           default:
       
   505             {} //ignore those we don't understand
       
   506             
       
   507           }//switch
       
   508           
       
   509         }
       
   510         else { // itr == '%', second consecutive
       
   511           sitr++;
       
   512         }
       
   513         
       
   514         itr++; //advance past format specifier
       
   515       }
       
   516       else {  //skip past chars in format and in buffer
       
   517         itr++;
       
   518         if (use_current_char) {
       
   519           use_current_char = false;
       
   520           current_char = *sitr;
       
   521         }
       
   522         else {
       
   523           sitr++;
       
   524         }
       
   525       }
       
   526     }
       
   527     
       
   528     return month_type(month); // throws bad_month exception when values are zero
       
   529   }
       
   530 
       
   531   //! Expects 1 or 2 digits 1-31. Throws bad_day_of_month if unable to parse
       
   532   day_type
       
   533   parse_var_day_of_month(std::istreambuf_iterator<charT>& sitr, 
       
   534                          std::istreambuf_iterator<charT>& stream_end) const
       
   535   {
       
   536     // skip leading whitespace
       
   537     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 
       
   538 
       
   539     return day_type(var_string_to_int<short, charT>(sitr, stream_end, 2));
       
   540   }
       
   541   //! Expects 2 digits 01-31. Throws bad_day_of_month if unable to parse
       
   542   day_type
       
   543   parse_day_of_month(std::istreambuf_iterator<charT>& sitr, 
       
   544                      std::istreambuf_iterator<charT>& stream_end) const
       
   545   {
       
   546     // skip leading whitespace
       
   547     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 
       
   548 
       
   549     //return day_type(var_string_to_int<short, charT>(sitr, stream_end, 2));
       
   550     match_results mr;
       
   551     return day_type(fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2));
       
   552   }
       
   553 
       
   554   day_of_week_type
       
   555   parse_weekday(std::istreambuf_iterator<charT>& sitr, 
       
   556              std::istreambuf_iterator<charT>& stream_end,
       
   557              string_type format_str) const
       
   558   {
       
   559     match_results mr;
       
   560     return parse_weekday(sitr, stream_end, format_str, mr);
       
   561   }
       
   562   day_of_week_type
       
   563   parse_weekday(std::istreambuf_iterator<charT>& sitr, 
       
   564              std::istreambuf_iterator<charT>& stream_end,
       
   565              string_type format_str,
       
   566              match_results& mr) const
       
   567   {
       
   568     bool use_current_char = false;
       
   569     
       
   570     // skip leading whitespace
       
   571     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 
       
   572     charT current_char = *sitr;
       
   573 
       
   574     short wkday(0);
       
   575     
       
   576     const_itr itr(format_str.begin());
       
   577     while (itr != format_str.end() && (sitr != stream_end)) {
       
   578       if (*itr == '%') {
       
   579         itr++;
       
   580         if (*itr != '%') {
       
   581           switch(*itr) {
       
   582           case 'a': 
       
   583             {
       
   584               //this value is just throw away.  It could be used for
       
   585               //error checking potentially, but it isn't helpful in 
       
   586               //actually constructing the date - we just need to get it
       
   587               //out of the stream
       
   588               mr = m_weekday_short_names.match(sitr, stream_end);
       
   589               wkday = mr.current_match;
       
   590               if (mr.has_remaining()) {
       
   591                 current_char = mr.last_char();
       
   592                 use_current_char = true;
       
   593               }
       
   594               break;
       
   595             }
       
   596           case 'A': 
       
   597             {
       
   598               //this value is just throw away.  It could be used for
       
   599               //error checking potentially, but it isn't helpful in 
       
   600               //actually constructing the date - we just need to get it
       
   601               //out of the stream
       
   602               mr = m_weekday_long_names.match(sitr, stream_end);
       
   603               wkday = mr.current_match;
       
   604               if (mr.has_remaining()) {
       
   605                 current_char = mr.last_char();
       
   606                 use_current_char = true;
       
   607               }
       
   608               break;
       
   609             }
       
   610           case 'w':
       
   611             {
       
   612               // weekday as number 0-6, Sunday == 0
       
   613               wkday = var_string_to_int<short, charT>(sitr, stream_end, 2);
       
   614               break;
       
   615             }
       
   616           default:
       
   617             {} //ignore those we don't understand
       
   618             
       
   619           }//switch
       
   620           
       
   621         }
       
   622         else { // itr == '%', second consecutive
       
   623           sitr++;
       
   624         }
       
   625         
       
   626         itr++; //advance past format specifier
       
   627       }
       
   628       else {  //skip past chars in format and in buffer
       
   629         itr++;
       
   630         if (use_current_char) {
       
   631           use_current_char = false;
       
   632           current_char = *sitr;
       
   633         }
       
   634         else {
       
   635           sitr++;
       
   636         }
       
   637       }
       
   638     }
       
   639     
       
   640     return day_of_week_type(wkday); // throws bad_day_of_month exception 
       
   641                                     // when values are zero
       
   642   }
       
   643   
       
   644   //! throws bad_year if unable to parse
       
   645   year_type
       
   646   parse_year(std::istreambuf_iterator<charT>& sitr, 
       
   647              std::istreambuf_iterator<charT>& stream_end,
       
   648              string_type format_str) const
       
   649   {
       
   650     match_results mr;
       
   651     return parse_year(sitr, stream_end, format_str, mr);
       
   652   }
       
   653 
       
   654   //! throws bad_year if unable to parse
       
   655   year_type
       
   656   parse_year(std::istreambuf_iterator<charT>& sitr, 
       
   657              std::istreambuf_iterator<charT>& stream_end,
       
   658              string_type format_str,
       
   659              match_results& mr) const
       
   660   {
       
   661     bool use_current_char = false;
       
   662     
       
   663     // skip leading whitespace
       
   664     while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; } 
       
   665     charT current_char = *sitr;
       
   666 
       
   667     unsigned short year(0);
       
   668     
       
   669     const_itr itr(format_str.begin());
       
   670     while (itr != format_str.end() && (sitr != stream_end)) {
       
   671       if (*itr == '%') {
       
   672         itr++;
       
   673         if (*itr != '%') {
       
   674           //match_results mr;
       
   675           switch(*itr) {
       
   676           case 'Y':
       
   677             {
       
   678               // year from 4 digit string
       
   679               year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 4);
       
   680               break;
       
   681             }
       
   682           case 'y':
       
   683             {
       
   684               // year from 2 digit string (no century)
       
   685               year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
       
   686               year += 2000; //make 2 digit years in this century
       
   687               break;
       
   688             }
       
   689           default:
       
   690             {} //ignore those we don't understand
       
   691             
       
   692           }//switch
       
   693           
       
   694         }
       
   695         else { // itr == '%', second consecutive
       
   696           sitr++;
       
   697         }
       
   698         
       
   699         itr++; //advance past format specifier
       
   700       }
       
   701       else {  //skip past chars in format and in buffer
       
   702         itr++;
       
   703         if (use_current_char) {
       
   704           use_current_char = false;
       
   705           current_char = *sitr;
       
   706         }
       
   707         else {
       
   708           sitr++;
       
   709         }
       
   710       }
       
   711     }
       
   712     
       
   713     return year_type(year); // throws bad_year exception when values are zero
       
   714   }
       
   715   
       
   716   
       
   717  private:
       
   718   string_type m_format;
       
   719   parse_tree_type m_month_short_names;
       
   720   parse_tree_type m_month_long_names;
       
   721   parse_tree_type m_weekday_short_names;
       
   722   parse_tree_type m_weekday_long_names;
       
   723 
       
   724 };
       
   725 
       
   726 } } //namespace
       
   727 
       
   728 #endif
       
   729 
       
   730 
       
   731