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