source: NonGTP/Boost/boost/date_time/date_parsing.hpp @ 857

Revision 857, 10.7 KB checked in by igarcia, 18 years ago (diff)
Line 
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
26namespace boost {
27namespace 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
Note: See TracBrowser for help on using the repository browser.