| 1 | #ifndef _DATE_TIME_DATE_PARSING_HPP___ | 
|---|
| 2 | #define _DATE_TIME_DATE_PARSING_HPP___ | 
|---|
| 3 |  | 
|---|
| 4 | /* Copyright (c) 2002,2003,2005 CrystalClear Software, Inc. | 
|---|
| 5 |  * Use, modification and distribution is subject to the  | 
|---|
| 6 |  * Boost Software License, Version 1.0. (See accompanying | 
|---|
| 7 |  * file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) | 
|---|
| 8 |  * Author: Jeff Garland, Bart Garst | 
|---|
| 9 |  * $Date: 2005/07/13 03:59:54 $ | 
|---|
| 10 |  */ | 
|---|
| 11 |  | 
|---|
| 12 | #include "boost/tokenizer.hpp" | 
|---|
| 13 | #include "boost/lexical_cast.hpp" | 
|---|
| 14 | #include "boost/date_time/compiler_config.hpp" | 
|---|
| 15 | #include "boost/date_time/parse_format_base.hpp" | 
|---|
| 16 | #include <string> | 
|---|
| 17 | #include <iterator> | 
|---|
| 18 | #include <algorithm> | 
|---|
| 19 |  | 
|---|
| 20 | #if defined(BOOST_NO_STD_LOCALE) | 
|---|
| 21 | #include <cctype> // ::tolower(int) | 
|---|
| 22 | #else | 
|---|
| 23 | #include <locale> // std::tolower(char, locale) | 
|---|
| 24 | #endif | 
|---|
| 25 |  | 
|---|
| 26 | namespace boost { | 
|---|
| 27 | namespace date_time { | 
|---|
| 28 |  | 
|---|
| 29 |   //! A function to replace the std::transform( , , ,tolower) construct | 
|---|
| 30 |   /*! This function simply takes a string, and changes all the characters | 
|---|
| 31 |    * in that string to lowercase (according to the default system locale). | 
|---|
| 32 |    * In the event that a compiler does not support locales, the old  | 
|---|
| 33 |    * C style tolower() is used. | 
|---|
| 34 |    */ | 
|---|
| 35 |   inline | 
|---|
| 36 |   std::string  | 
|---|
| 37 |   convert_to_lower(const std::string& inp) { | 
|---|
| 38 |     std::string tmp; | 
|---|
| 39 |     unsigned i = 0; | 
|---|
| 40 | #if defined(BOOST_NO_STD_LOCALE) | 
|---|
| 41 |     while(i < inp.length()) { | 
|---|
| 42 |       tmp += static_cast<char>(std::tolower(inp.at(i++))); | 
|---|
| 43 | #else | 
|---|
| 44 |       std::locale loc(""); | 
|---|
| 45 |       while(i < inp.length()) { | 
|---|
| 46 |         // tolower and others were brought in to std for borland >= v564 | 
|---|
| 47 |         // in compiler_config.hpp | 
|---|
| 48 |         std::string::value_type c(inp.at(i++)); | 
|---|
| 49 |         tmp += std::tolower(c, loc); | 
|---|
| 50 | #endif | 
|---|
| 51 |          | 
|---|
| 52 |       } | 
|---|
| 53 |       return tmp; | 
|---|
| 54 |     } | 
|---|
| 55 |      | 
|---|
| 56 |     //! Helper function for parse_date. | 
|---|
| 57 |     /* Used by-value parameter because we change the string and may | 
|---|
| 58 |      * want to preserve the original argument */ | 
|---|
| 59 |     template<class month_type> | 
|---|
| 60 |     unsigned short  | 
|---|
| 61 |     month_str_to_ushort(std::string s) { | 
|---|
| 62 |       if((s.at(0) >= '0') && (s.at(0) <= '9')) { | 
|---|
| 63 |         return boost::lexical_cast<unsigned short>(s); | 
|---|
| 64 |       }  | 
|---|
| 65 |       else { | 
|---|
| 66 |         s = convert_to_lower(s); | 
|---|
| 67 |         typename month_type::month_map_ptr_type ptr = month_type::get_month_map_ptr(); | 
|---|
| 68 |         typename month_type::month_map_type::iterator iter = ptr->find(s); | 
|---|
| 69 |         if(iter != ptr->end()) { // required for STLport | 
|---|
| 70 |           return iter->second; | 
|---|
| 71 |         } | 
|---|
| 72 |       } | 
|---|
| 73 |       return 13; // intentionally out of range - name not found | 
|---|
| 74 |     } | 
|---|
| 75 |   | 
|---|
| 76 |     //! Find index of a string in either of 2 arrays | 
|---|
| 77 |     /*! find_match searches both arrays for a match to 's'. Indexing of the  | 
|---|
| 78 |      * arrays is from 0 to 'limit'. The index of the match is returned. | 
|---|
| 79 |      * Ex. "Jan" returns 0, "Dec" returns 11, "Tue" returns 2. | 
|---|
| 80 |      * 'limit' can be sent in with: greg_month::max(),  | 
|---|
| 81 |      * greg_weekday::max() or date_time::NumSpecialValues */ | 
|---|
| 82 |     template<class charT> | 
|---|
| 83 |     short find_match(const charT* const* short_names,  | 
|---|
| 84 |                      const charT* const* long_names,  | 
|---|
| 85 |                      short limit, | 
|---|
| 86 |                      const std::basic_string<charT>& s) { | 
|---|
| 87 |       for(short i = 0; i <= limit; ++i){ | 
|---|
| 88 |         if(short_names[i] == s || long_names[i] == s){ | 
|---|
| 89 |           return i; | 
|---|
| 90 |         } | 
|---|
| 91 |       } | 
|---|
| 92 |       return static_cast<short>(limit + 1); // not-found, return a value out of range | 
|---|
| 93 |     } | 
|---|
| 94 |      | 
|---|
| 95 |     //! Generic function to parse a delimited date (eg: 2002-02-10) | 
|---|
| 96 |     /*! Accepted formats are: "2003-02-10" or " 2003-Feb-10" or | 
|---|
| 97 |      * "2003-Feburary-10"  | 
|---|
| 98 |      * The order in which the Month, Day, & Year appear in the argument  | 
|---|
| 99 |      * string can be accomodated by passing in the appropriate ymd_order_spec  | 
|---|
| 100 |      */ | 
|---|
| 101 |     template<class date_type> | 
|---|
| 102 |     date_type | 
|---|
| 103 |     parse_date(const std::string& s, int order_spec = ymd_order_iso) { | 
|---|
| 104 |       std::string spec_str(""); | 
|---|
| 105 |       if(order_spec == ymd_order_iso) { | 
|---|
| 106 |         spec_str = "ymd"; | 
|---|
| 107 |       }  | 
|---|
| 108 |       else if(order_spec == ymd_order_dmy) { | 
|---|
| 109 |         spec_str = "dmy"; | 
|---|
| 110 |       }  | 
|---|
| 111 |       else { // (order_spec == ymd_order_us) | 
|---|
| 112 |         spec_str = "mdy"; | 
|---|
| 113 |       } | 
|---|
| 114 |        | 
|---|
| 115 |       typedef typename date_type::year_type year_type; | 
|---|
| 116 |       typedef typename date_type::month_type month_type; | 
|---|
| 117 |       unsigned pos = 0; | 
|---|
| 118 |       unsigned short year(0), month(0), day(0); | 
|---|
| 119 |        | 
|---|
| 120 |       typedef boost::tokenizer<boost::char_separator<char>, | 
|---|
| 121 |                                std::basic_string<char>::const_iterator, | 
|---|
| 122 |                                std::basic_string<char> > tokenizer; | 
|---|
| 123 |       typedef boost::tokenizer<boost::char_separator<char>, | 
|---|
| 124 |                                std::basic_string<char>::const_iterator, | 
|---|
| 125 |                                std::basic_string<char> >::iterator tokenizer_iterator; | 
|---|
| 126 |       // may need more delimiters, these work for the regression tests | 
|---|
| 127 |       const char sep_char[] = {',','-','.',' ','/','\0'}; | 
|---|
| 128 |       boost::char_separator<char> sep(sep_char); | 
|---|
| 129 |       tokenizer tok(s,sep); | 
|---|
| 130 |       for(tokenizer_iterator beg=tok.begin();  | 
|---|
| 131 |           beg!=tok.end() && pos < spec_str.size();  | 
|---|
| 132 |           ++beg, ++pos) { | 
|---|
| 133 |         switch(spec_str.at(pos)) { | 
|---|
| 134 |           case 'y':  | 
|---|
| 135 |           { | 
|---|
| 136 |             year = boost::lexical_cast<unsigned short>(*beg); | 
|---|
| 137 |             break; | 
|---|
| 138 |           } | 
|---|
| 139 |           case 'm':  | 
|---|
| 140 |           { | 
|---|
| 141 |             month = month_str_to_ushort<month_type>(*beg); | 
|---|
| 142 |             break; | 
|---|
| 143 |           } | 
|---|
| 144 |           case 'd':  | 
|---|
| 145 |           { | 
|---|
| 146 |             day = boost::lexical_cast<unsigned short>(*beg); | 
|---|
| 147 |             break; | 
|---|
| 148 |           } | 
|---|
| 149 |         } //switch | 
|---|
| 150 |       } | 
|---|
| 151 |       return date_type(year, month, day); | 
|---|
| 152 |     } | 
|---|
| 153 |      | 
|---|
| 154 |     //! Generic function to parse undelimited date (eg: 20020201) | 
|---|
| 155 |     template<class date_type> | 
|---|
| 156 |     date_type | 
|---|
| 157 |     parse_undelimited_date(const std::string& s) { | 
|---|
| 158 |       int offsets[] = {4,2,2}; | 
|---|
| 159 |       int pos = 0; | 
|---|
| 160 |       typedef typename date_type::year_type year_type; | 
|---|
| 161 |       typename date_type::ymd_type ymd((year_type::min)(),1,1); | 
|---|
| 162 |       boost::offset_separator osf(offsets, offsets+3); | 
|---|
| 163 |       boost::tokenizer<boost::offset_separator> tok(s, osf); | 
|---|
| 164 |       for(boost::tokenizer<boost::offset_separator>::iterator ti=tok.begin(); ti!=tok.end();++ti) { | 
|---|
| 165 |         unsigned short i = boost::lexical_cast<unsigned short>(*ti); | 
|---|
| 166 |         switch(pos) { | 
|---|
| 167 |         case 0: ymd.year = i; break; | 
|---|
| 168 |         case 1: ymd.month = i; break; | 
|---|
| 169 |         case 2: ymd.day = i; break; | 
|---|
| 170 |         } | 
|---|
| 171 |         pos++; | 
|---|
| 172 |       } | 
|---|
| 173 |       return date_type(ymd); | 
|---|
| 174 |     } | 
|---|
| 175 |      | 
|---|
| 176 |     //! Helper function for 'date gregorian::from_stream()' | 
|---|
| 177 |     /*! Creates a string from the iterators that reference the | 
|---|
| 178 |      * begining & end of a char[] or string. All elements are  | 
|---|
| 179 |      * used in output string */ | 
|---|
| 180 |     template<class date_type, class iterator_type> | 
|---|
| 181 |     inline  | 
|---|
| 182 |     date_type | 
|---|
| 183 |     from_stream_type(iterator_type& beg,  | 
|---|
| 184 |                      iterator_type& end, | 
|---|
| 185 |                      char)  | 
|---|
| 186 |     { | 
|---|
| 187 |       std::stringstream ss(""); | 
|---|
| 188 |       while(beg != end) { | 
|---|
| 189 |         ss << *beg++; | 
|---|
| 190 |       } | 
|---|
| 191 |       return parse_date<date_type>(ss.str()); | 
|---|
| 192 |     } | 
|---|
| 193 |   | 
|---|
| 194 |     //! Helper function for 'date gregorian::from_stream()' | 
|---|
| 195 |     /*! Returns the first string found in the stream referenced by the | 
|---|
| 196 |      * begining & end iterators */ | 
|---|
| 197 |     template<class date_type, class iterator_type> | 
|---|
| 198 |     inline  | 
|---|
| 199 |     date_type | 
|---|
| 200 |     from_stream_type(iterator_type& beg,  | 
|---|
| 201 |                      iterator_type& end, | 
|---|
| 202 |                      std::string)  | 
|---|
| 203 |     { | 
|---|
| 204 |       return parse_date<date_type>(*beg); | 
|---|
| 205 |     } | 
|---|
| 206 |  | 
|---|
| 207 |     /* I believe the wchar stuff would be best elsewhere, perhaps in | 
|---|
| 208 |      * parse_date<>()? In the mean time this gets us started... */ | 
|---|
| 209 |     //! Helper function for 'date gregorian::from_stream()' | 
|---|
| 210 |     /*! Creates a string from the iterators that reference the | 
|---|
| 211 |      * begining & end of a wstring. All elements are  | 
|---|
| 212 |      * used in output string */ | 
|---|
| 213 |     template<class date_type, class iterator_type> | 
|---|
| 214 |     inline  | 
|---|
| 215 |     date_type from_stream_type(iterator_type& beg,  | 
|---|
| 216 |                                iterator_type& end, | 
|---|
| 217 |                                wchar_t)  | 
|---|
| 218 |     { | 
|---|
| 219 |       std::stringstream ss(""); | 
|---|
| 220 |       while(beg != end) { | 
|---|
| 221 | #if !defined(BOOST_DATE_TIME_NO_LOCALE) | 
|---|
| 222 |         ss << std::use_facet<std::ctype<wchar_t> >(std::locale()).narrow(*beg++, 'X'); // 'X' will cause exception to be thrown | 
|---|
| 223 | #else | 
|---|
| 224 |         ss << ss.narrow(*beg++, 'X'); | 
|---|
| 225 | #endif | 
|---|
| 226 |       } | 
|---|
| 227 |       return parse_date<date_type>(ss.str()); | 
|---|
| 228 |     } | 
|---|
| 229 | #ifndef BOOST_NO_STD_WSTRING | 
|---|
| 230 |     //! Helper function for 'date gregorian::from_stream()' | 
|---|
| 231 |     /*! Creates a string from the first wstring found in the stream | 
|---|
| 232 |      * referenced by the begining & end iterators */ | 
|---|
| 233 |     template<class date_type, class iterator_type> | 
|---|
| 234 |     inline  | 
|---|
| 235 |     date_type | 
|---|
| 236 |     from_stream_type(iterator_type& beg,  | 
|---|
| 237 |                      iterator_type& end, | 
|---|
| 238 |                      std::wstring) { | 
|---|
| 239 |       std::wstring ws = *beg; | 
|---|
| 240 |       std::stringstream ss(""); | 
|---|
| 241 |       std::wstring::iterator wsb = ws.begin(), wse = ws.end(); | 
|---|
| 242 |       while(wsb != wse) { | 
|---|
| 243 | #if !defined(BOOST_DATE_TIME_NO_LOCALE) | 
|---|
| 244 |         ss << std::use_facet<std::ctype<wchar_t> >(std::locale()).narrow(*wsb++, 'X'); // 'X' will cause exception to be thrown | 
|---|
| 245 | #else | 
|---|
| 246 |         ss << ss.narrow(*wsb++, 'X'); // 'X' will cause exception to be thrown | 
|---|
| 247 | #endif | 
|---|
| 248 |       } | 
|---|
| 249 |       return parse_date<date_type>(ss.str()); | 
|---|
| 250 |     } | 
|---|
| 251 | #endif // BOOST_NO_STD_WSTRING | 
|---|
| 252 | #if (defined(BOOST_MSVC) && (_MSC_VER <= 1200)) | 
|---|
| 253 |     // This function cannot be compiled with MSVC 6.0 due to internal compiler shorcomings | 
|---|
| 254 | #else | 
|---|
| 255 |     //! function called by wrapper functions: date_period_from_(w)string() | 
|---|
| 256 |     template<class date_type, class charT> | 
|---|
| 257 |     period<date_type, typename date_type::duration_type>  | 
|---|
| 258 |     from_simple_string_type(const std::basic_string<charT>& s){ | 
|---|
| 259 |       typedef typename boost::char_separator<charT> char_separator; | 
|---|
| 260 |       typedef typename boost::tokenizer<char_separator, typename std::basic_string<charT>::const_iterator,  | 
|---|
| 261 |                                           std::basic_string<charT> > tokenizer; | 
|---|
| 262 |       const charT sep_list[4] = {'[','/',']','\0'}; | 
|---|
| 263 |       char_separator sep(sep_list); | 
|---|
| 264 |       tokenizer tokens(s, sep); | 
|---|
| 265 |       typename tokenizer::iterator tok_it = tokens.begin();  | 
|---|
| 266 |       std::basic_string<charT> date_string = *tok_it; | 
|---|
| 267 |       // get 2 string iterators and generate a date from them | 
|---|
| 268 |       typename std::basic_string<charT>::iterator date_string_start = date_string.begin(),  | 
|---|
| 269 |                                                   date_string_end = date_string.end();  | 
|---|
| 270 |       typedef typename std::iterator_traits<typename std::basic_string<charT>::iterator>::value_type value_type; | 
|---|
| 271 |       date_type d1 = from_stream_type<date_type>(date_string_start, date_string_end, value_type()); | 
|---|
| 272 |       date_string = *(++tok_it); // next token | 
|---|
| 273 |       date_string_start = date_string.begin(), date_string_end = date_string.end();  | 
|---|
| 274 |       date_type d2 = from_stream_type<date_type>(date_string_start, date_string_end, value_type()); | 
|---|
| 275 |       return period<date_type, typename date_type::duration_type>(d1, d2);  | 
|---|
| 276 |     } | 
|---|
| 277 | #endif // _MSC_VER <= 1200 | 
|---|
| 278 |      | 
|---|
| 279 | } } //namespace date_time | 
|---|
| 280 |  | 
|---|
| 281 |  | 
|---|
| 282 |  | 
|---|
| 283 |  | 
|---|
| 284 | #endif | 
|---|
| 285 |  | 
|---|