comparison DEPENDENCIES/generic/include/boost/date_time/date_parsing.hpp @ 16:2665513ce2d3

Add boost headers
author Chris Cannam
date Tue, 05 Aug 2014 11:11:38 +0100
parents
children c530137014c0
comparison
equal deleted inserted replaced
15:663ca0da4350 16:2665513ce2d3
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.txt or http://www.boost.org/LICENSE_1_0.txt)
8 * Author: Jeff Garland, Bart Garst
9 * $Date: 2012-09-30 16:25:22 -0700 (Sun, 30 Sep 2012) $
10 */
11
12 #include <string>
13 #include <iterator>
14 #include <algorithm>
15 #include <boost/tokenizer.hpp>
16 #include <boost/lexical_cast.hpp>
17 #include <boost/date_time/compiler_config.hpp>
18 #include <boost/date_time/parse_format_base.hpp>
19
20 #if defined(BOOST_DATE_TIME_NO_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(std::string inp)
38 {
39 #if !defined(BOOST_DATE_TIME_NO_LOCALE)
40 const std::locale loc(std::locale::classic());
41 #endif
42 std::string::size_type i = 0, n = inp.length();
43 for (; i < n; ++i) {
44 inp[i] =
45 #if defined(BOOST_DATE_TIME_NO_LOCALE)
46 static_cast<char>(std::tolower(inp[i]));
47 #else
48 // tolower and others were brought in to std for borland >= v564
49 // in compiler_config.hpp
50 std::tolower(inp[i], loc);
51 #endif
52 }
53 return inp;
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 inline unsigned short
61 month_str_to_ushort(std::string const& s) {
62 if((s.at(0) >= '0') && (s.at(0) <= '9')) {
63 return boost::lexical_cast<unsigned short>(s);
64 }
65 else {
66 std::string str = 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(str);
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'. Both arrays
78 * must contain 'size' elements. The index of the match is returned.
79 * If no match is found, 'size' is returned.
80 * Ex. "Jan" returns 0, "Dec" returns 11, "Tue" returns 2.
81 * 'size' can be sent in with: (greg_month::max)() (which 12),
82 * (greg_weekday::max)() + 1 (which is 7) or date_time::NumSpecialValues */
83 template<class charT>
84 short find_match(const charT* const* short_names,
85 const charT* const* long_names,
86 short size,
87 const std::basic_string<charT>& s) {
88 for(short i = 0; i < size; ++i){
89 if(short_names[i] == s || long_names[i] == s){
90 return i;
91 }
92 }
93 return size; // not-found, return a value out of range
94 }
95
96 //! Generic function to parse a delimited date (eg: 2002-02-10)
97 /*! Accepted formats are: "2003-02-10" or " 2003-Feb-10" or
98 * "2003-Feburary-10"
99 * The order in which the Month, Day, & Year appear in the argument
100 * string can be accomodated by passing in the appropriate ymd_order_spec
101 */
102 template<class date_type>
103 date_type
104 parse_date(const std::string& s, int order_spec = ymd_order_iso) {
105 std::string spec_str;
106 if(order_spec == ymd_order_iso) {
107 spec_str = "ymd";
108 }
109 else if(order_spec == ymd_order_dmy) {
110 spec_str = "dmy";
111 }
112 else { // (order_spec == ymd_order_us)
113 spec_str = "mdy";
114 }
115
116 typedef typename date_type::year_type year_type;
117 typedef typename date_type::month_type month_type;
118 unsigned pos = 0;
119 unsigned short year(0), month(0), day(0);
120 typedef typename std::basic_string<char>::traits_type traits_type;
121 typedef boost::char_separator<char, traits_type> char_separator_type;
122 typedef boost::tokenizer<char_separator_type,
123 std::basic_string<char>::const_iterator,
124 std::basic_string<char> > tokenizer;
125 typedef boost::tokenizer<char_separator_type,
126 std::basic_string<char>::const_iterator,
127 std::basic_string<char> >::iterator tokenizer_iterator;
128 // may need more delimiters, these work for the regression tests
129 const char sep_char[] = {',','-','.',' ','/','\0'};
130 char_separator_type sep(sep_char);
131 tokenizer tok(s,sep);
132 for(tokenizer_iterator beg=tok.begin();
133 beg!=tok.end() && pos < spec_str.size();
134 ++beg, ++pos) {
135 switch(spec_str.at(pos)) {
136 case 'y':
137 {
138 year = boost::lexical_cast<unsigned short>(*beg);
139 break;
140 }
141 case 'm':
142 {
143 month = month_str_to_ushort<month_type>(*beg);
144 break;
145 }
146 case 'd':
147 {
148 day = boost::lexical_cast<unsigned short>(*beg);
149 break;
150 }
151 default: break;
152 } //switch
153 }
154 return date_type(year, month, day);
155 }
156
157 //! Generic function to parse undelimited date (eg: 20020201)
158 template<class date_type>
159 date_type
160 parse_undelimited_date(const std::string& s) {
161 int offsets[] = {4,2,2};
162 int pos = 0;
163 typedef typename date_type::year_type year_type;
164 //typename date_type::ymd_type ymd((year_type::min)(),1,1);
165 unsigned short y = 0, m = 0, d = 0;
166
167 /* The two bool arguments state that parsing will not wrap
168 * (only the first 8 characters will be parsed) and partial
169 * strings will not be parsed.
170 * Ex:
171 * "2005121" will parse 2005 & 12, but not the "1" */
172 boost::offset_separator osf(offsets, offsets+3, false, false);
173
174 typedef typename boost::tokenizer<boost::offset_separator,
175 std::basic_string<char>::const_iterator,
176 std::basic_string<char> > tokenizer_type;
177 tokenizer_type tok(s, osf);
178 for(typename tokenizer_type::iterator ti=tok.begin(); ti!=tok.end();++ti) {
179 unsigned short i = boost::lexical_cast<unsigned short>(*ti);
180 switch(pos) {
181 case 0: y = i; break;
182 case 1: m = i; break;
183 case 2: d = i; break;
184 default: break;
185 }
186 pos++;
187 }
188 return date_type(y,m,d);
189 }
190
191 //! Helper function for 'date gregorian::from_stream()'
192 /*! Creates a string from the iterators that reference the
193 * begining & end of a char[] or string. All elements are
194 * used in output string */
195 template<class date_type, class iterator_type>
196 inline
197 date_type
198 from_stream_type(iterator_type& beg,
199 iterator_type const& end,
200 char)
201 {
202 std::ostringstream ss;
203 while(beg != end) {
204 ss << *beg++;
205 }
206 return parse_date<date_type>(ss.str());
207 }
208
209 //! Helper function for 'date gregorian::from_stream()'
210 /*! Returns the first string found in the stream referenced by the
211 * begining & end iterators */
212 template<class date_type, class iterator_type>
213 inline
214 date_type
215 from_stream_type(iterator_type& beg,
216 iterator_type const& /* end */,
217 std::string const&)
218 {
219 return parse_date<date_type>(*beg);
220 }
221
222 /* I believe the wchar stuff would be best elsewhere, perhaps in
223 * parse_date<>()? In the mean time this gets us started... */
224 //! Helper function for 'date gregorian::from_stream()'
225 /*! Creates a string from the iterators that reference the
226 * begining & end of a wstring. All elements are
227 * used in output string */
228 template<class date_type, class iterator_type>
229 inline
230 date_type from_stream_type(iterator_type& beg,
231 iterator_type const& end,
232 wchar_t)
233 {
234 std::ostringstream ss;
235 #if !defined(BOOST_DATE_TIME_NO_LOCALE)
236 std::locale loc;
237 std::ctype<wchar_t> const& fac = std::use_facet<std::ctype<wchar_t> >(loc);
238 while(beg != end) {
239 ss << fac.narrow(*beg++, 'X'); // 'X' will cause exception to be thrown
240 }
241 #else
242 while(beg != end) {
243 char c = 'X'; // 'X' will cause exception to be thrown
244 const wchar_t wc = *beg++;
245 if (wc >= 0 && wc <= 127)
246 c = static_cast< char >(wc);
247 ss << c;
248 }
249 #endif
250 return parse_date<date_type>(ss.str());
251 }
252 #ifndef BOOST_NO_STD_WSTRING
253 //! Helper function for 'date gregorian::from_stream()'
254 /*! Creates a string from the first wstring found in the stream
255 * referenced by the begining & end iterators */
256 template<class date_type, class iterator_type>
257 inline
258 date_type
259 from_stream_type(iterator_type& beg,
260 iterator_type const& /* end */,
261 std::wstring const&) {
262 std::wstring ws = *beg;
263 std::ostringstream ss;
264 std::wstring::iterator wsb = ws.begin(), wse = ws.end();
265 #if !defined(BOOST_DATE_TIME_NO_LOCALE)
266 std::locale loc;
267 std::ctype<wchar_t> const& fac = std::use_facet<std::ctype<wchar_t> >(loc);
268 while(wsb != wse) {
269 ss << fac.narrow(*wsb++, 'X'); // 'X' will cause exception to be thrown
270 }
271 #else
272 while(wsb != wse) {
273 char c = 'X'; // 'X' will cause exception to be thrown
274 const wchar_t wc = *wsb++;
275 if (wc >= 0 && wc <= 127)
276 c = static_cast< char >(wc);
277 ss << c;
278 }
279 #endif
280 return parse_date<date_type>(ss.str());
281 }
282 #endif // BOOST_NO_STD_WSTRING
283 #if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
284 // This function cannot be compiled with MSVC 6.0 due to internal compiler shorcomings
285 #else
286 //! function called by wrapper functions: date_period_from_(w)string()
287 template<class date_type, class charT>
288 period<date_type, typename date_type::duration_type>
289 from_simple_string_type(const std::basic_string<charT>& s){
290 typedef typename std::basic_string<charT>::traits_type traits_type;
291 typedef typename boost::char_separator<charT, traits_type> char_separator;
292 typedef typename boost::tokenizer<char_separator,
293 typename std::basic_string<charT>::const_iterator,
294 std::basic_string<charT> > tokenizer;
295 const charT sep_list[4] = {'[','/',']','\0'};
296 char_separator sep(sep_list);
297 tokenizer tokens(s, sep);
298 typename tokenizer::iterator tok_it = tokens.begin();
299 std::basic_string<charT> date_string = *tok_it;
300 // get 2 string iterators and generate a date from them
301 typename std::basic_string<charT>::iterator date_string_start = date_string.begin(),
302 date_string_end = date_string.end();
303 typedef typename std::iterator_traits<typename std::basic_string<charT>::iterator>::value_type value_type;
304 date_type d1 = from_stream_type<date_type>(date_string_start, date_string_end, value_type());
305 date_string = *(++tok_it); // next token
306 date_string_start = date_string.begin(), date_string_end = date_string.end();
307 date_type d2 = from_stream_type<date_type>(date_string_start, date_string_end, value_type());
308 return period<date_type, typename date_type::duration_type>(d1, d2);
309 }
310 #endif
311
312 } } //namespace date_time
313
314
315
316
317 #endif
318