File indexing completed on 2025-01-18 09:30:38
0001
0002 #ifndef DATE_TIME_FORMAT_DATE_PARSER_HPP__
0003 #define DATE_TIME_FORMAT_DATE_PARSER_HPP__
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include "boost/lexical_cast.hpp"
0015 #include "boost/date_time/string_parse_tree.hpp"
0016 #include "boost/date_time/strings_from_facet.hpp"
0017 #include "boost/date_time/special_values_parser.hpp"
0018 #include <string>
0019 #include <vector>
0020 #include <sstream>
0021 #include <iterator>
0022 #ifndef BOOST_NO_STDC_NAMESPACE
0023 # include <cctype>
0024 #else
0025 # include <ctype.h>
0026 #endif
0027
0028 #ifdef BOOST_NO_STDC_NAMESPACE
0029 namespace std {
0030 using ::isspace;
0031 using ::isdigit;
0032 }
0033 #endif
0034 namespace boost { namespace date_time {
0035
0036
0037
0038
0039
0040
0041 template<typename int_type, typename charT>
0042 inline
0043 int_type
0044 fixed_string_to_int(std::istreambuf_iterator<charT>& itr,
0045 std::istreambuf_iterator<charT>& stream_end,
0046 parse_match_result<charT>& mr,
0047 unsigned int length,
0048 const charT& fill_char)
0049 {
0050
0051 unsigned int j = 0;
0052
0053 while (j < length && itr != stream_end &&
0054 (std::isdigit(*itr) || *itr == fill_char)) {
0055 if(*itr == fill_char) {
0056
0057
0058 mr.cache += ('0');
0059 }
0060 else {
0061 mr.cache += (*itr);
0062 }
0063 itr++;
0064 j++;
0065 }
0066 int_type i = static_cast<int_type>(-1);
0067
0068 if(mr.cache.size() < length) {
0069 return i;
0070 }
0071 try {
0072 i = boost::lexical_cast<int_type>(mr.cache);
0073 }catch(bad_lexical_cast&){
0074
0075 }
0076 return i;
0077 }
0078
0079
0080
0081
0082
0083
0084 template<typename int_type, typename charT>
0085 inline
0086 int_type
0087 fixed_string_to_int(std::istreambuf_iterator<charT>& itr,
0088 std::istreambuf_iterator<charT>& stream_end,
0089 parse_match_result<charT>& mr,
0090 unsigned int length)
0091 {
0092 return fixed_string_to_int<int_type, charT>(itr, stream_end, mr, length, '0');
0093 }
0094
0095
0096
0097
0098
0099 template<typename int_type, typename charT>
0100 inline
0101 int_type
0102 var_string_to_int(std::istreambuf_iterator<charT>& itr,
0103 const std::istreambuf_iterator<charT>& stream_end,
0104 unsigned int max_length)
0105 {
0106 typedef std::basic_string<charT> string_type;
0107 unsigned int j = 0;
0108 string_type s;
0109 while (itr != stream_end && (j < max_length) && std::isdigit(*itr)) {
0110 s += (*itr);
0111 ++itr;
0112 ++j;
0113 }
0114 int_type i = static_cast<int_type>(-1);
0115 if(!s.empty()) {
0116 i = boost::lexical_cast<int_type>(s);
0117 }
0118 return i;
0119 }
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150 template<class date_type, typename charT>
0151 class format_date_parser
0152 {
0153 public:
0154 typedef std::basic_string<charT> string_type;
0155 typedef std::basic_istringstream<charT> stringstream_type;
0156 typedef std::istreambuf_iterator<charT> stream_itr_type;
0157 typedef typename string_type::const_iterator const_itr;
0158 typedef typename date_type::year_type year_type;
0159 typedef typename date_type::month_type month_type;
0160 typedef typename date_type::day_type day_type;
0161 typedef typename date_type::duration_type duration_type;
0162 typedef typename date_type::day_of_week_type day_of_week_type;
0163 typedef typename date_type::day_of_year_type day_of_year_type;
0164 typedef string_parse_tree<charT> parse_tree_type;
0165 typedef typename parse_tree_type::parse_match_result_type match_results;
0166 typedef std::vector<std::basic_string<charT> > input_collection_type;
0167
0168
0169
0170 format_date_parser(const string_type& format_str,
0171 const input_collection_type& month_short_names,
0172 const input_collection_type& month_long_names,
0173 const input_collection_type& weekday_short_names,
0174 const input_collection_type& weekday_long_names) :
0175 m_format(format_str),
0176 m_month_short_names(month_short_names, 1),
0177 m_month_long_names(month_long_names, 1),
0178 m_weekday_short_names(weekday_short_names),
0179 m_weekday_long_names(weekday_long_names)
0180 {}
0181
0182 format_date_parser(const string_type& format_str,
0183 const std::locale& locale) :
0184 m_format(format_str),
0185 m_month_short_names(gather_month_strings<charT>(locale), 1),
0186 m_month_long_names(gather_month_strings<charT>(locale, false), 1),
0187 m_weekday_short_names(gather_weekday_strings<charT>(locale)),
0188 m_weekday_long_names(gather_weekday_strings<charT>(locale, false))
0189 {}
0190
0191 format_date_parser(const format_date_parser<date_type,charT>& fdp)
0192 {
0193 this->m_format = fdp.m_format;
0194 this->m_month_short_names = fdp.m_month_short_names;
0195 this->m_month_long_names = fdp.m_month_long_names;
0196 this->m_weekday_short_names = fdp.m_weekday_short_names;
0197 this->m_weekday_long_names = fdp.m_weekday_long_names;
0198 }
0199
0200 string_type format() const
0201 {
0202 return m_format;
0203 }
0204
0205 void format(string_type format_str)
0206 {
0207 m_format = format_str;
0208 }
0209
0210 void short_month_names(const input_collection_type& month_names)
0211 {
0212 m_month_short_names = parse_tree_type(month_names, 1);
0213 }
0214 void long_month_names(const input_collection_type& month_names)
0215 {
0216 m_month_long_names = parse_tree_type(month_names, 1);
0217 }
0218 void short_weekday_names(const input_collection_type& weekday_names)
0219 {
0220 m_weekday_short_names = parse_tree_type(weekday_names);
0221 }
0222 void long_weekday_names(const input_collection_type& weekday_names)
0223 {
0224 m_weekday_long_names = parse_tree_type(weekday_names);
0225 }
0226
0227 date_type
0228 parse_date(const string_type& value,
0229 const string_type& format_str,
0230 const special_values_parser<date_type,charT>& sv_parser) const
0231 {
0232 stringstream_type ss(value);
0233 stream_itr_type sitr(ss);
0234 stream_itr_type stream_end;
0235 return parse_date(sitr, stream_end, format_str, sv_parser);
0236 }
0237
0238 date_type
0239 parse_date(std::istreambuf_iterator<charT>& sitr,
0240 std::istreambuf_iterator<charT>& stream_end,
0241 const special_values_parser<date_type,charT>& sv_parser) const
0242 {
0243 return parse_date(sitr, stream_end, m_format, sv_parser);
0244 }
0245
0246
0247
0248
0249 date_type
0250 parse_date(std::istreambuf_iterator<charT>& sitr,
0251 std::istreambuf_iterator<charT>& stream_end,
0252 string_type format_str,
0253 const special_values_parser<date_type,charT>& sv_parser) const
0254 {
0255 bool use_current_char = false;
0256
0257
0258 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0259
0260 short year(0), month(0), day(0), day_of_year(0);
0261
0262
0263
0264
0265 year_type t_year(1400);
0266 month_type t_month(1);
0267 day_type t_day(1);
0268 day_of_week_type wkday(0);
0269
0270
0271 const_itr itr(format_str.begin());
0272 while (itr != format_str.end() && (sitr != stream_end)) {
0273 if (*itr == '%') {
0274 if ( ++itr == format_str.end())
0275 break;
0276 if (*itr != '%') {
0277 switch(*itr) {
0278 case 'a':
0279 {
0280
0281
0282
0283
0284 match_results mr = m_weekday_short_names.match(sitr, stream_end);
0285 if(mr.current_match == match_results::PARSE_ERROR) {
0286
0287 if(sv_parser.match(sitr, stream_end, mr)) {
0288 return date_type(static_cast<special_values>(mr.current_match));
0289 }
0290 }
0291 wkday = mr.current_match;
0292 if (mr.has_remaining()) {
0293 use_current_char = true;
0294 }
0295 break;
0296 }
0297 case 'A':
0298 {
0299
0300
0301
0302
0303 match_results mr = m_weekday_long_names.match(sitr, stream_end);
0304 if(mr.current_match == match_results::PARSE_ERROR) {
0305
0306 if(sv_parser.match(sitr, stream_end, mr)) {
0307 return date_type(static_cast<special_values>(mr.current_match));
0308 }
0309 }
0310 wkday = mr.current_match;
0311 if (mr.has_remaining()) {
0312 use_current_char = true;
0313 }
0314 break;
0315 }
0316 case 'b':
0317 {
0318 match_results mr = m_month_short_names.match(sitr, stream_end);
0319 if(mr.current_match == match_results::PARSE_ERROR) {
0320
0321 if(sv_parser.match(sitr, stream_end, mr)) {
0322 return date_type(static_cast<special_values>(mr.current_match));
0323 }
0324 }
0325 t_month = month_type(mr.current_match);
0326 if (mr.has_remaining()) {
0327 use_current_char = true;
0328 }
0329 break;
0330 }
0331 case 'B':
0332 {
0333 match_results mr = m_month_long_names.match(sitr, stream_end);
0334 if(mr.current_match == match_results::PARSE_ERROR) {
0335
0336 if(sv_parser.match(sitr, stream_end, mr)) {
0337 return date_type(static_cast<special_values>(mr.current_match));
0338 }
0339 }
0340 t_month = month_type(mr.current_match);
0341 if (mr.has_remaining()) {
0342 use_current_char = true;
0343 }
0344 break;
0345 }
0346 case 'd':
0347 {
0348 match_results mr;
0349 day = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
0350 if(day == -1) {
0351 if(sv_parser.match(sitr, stream_end, mr)) {
0352 return date_type(static_cast<special_values>(mr.current_match));
0353 }
0354 }
0355 t_day = day_type(day);
0356 break;
0357 }
0358 case 'e':
0359 {
0360 match_results mr;
0361 day = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2, ' ');
0362 if(day == -1) {
0363 if(sv_parser.match(sitr, stream_end, mr)) {
0364 return date_type(static_cast<special_values>(mr.current_match));
0365 }
0366 }
0367 t_day = day_type(day);
0368 break;
0369 }
0370 case 'j':
0371 {
0372 match_results mr;
0373 day_of_year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 3);
0374 if(day_of_year == -1) {
0375 if(sv_parser.match(sitr, stream_end, mr)) {
0376 return date_type(static_cast<special_values>(mr.current_match));
0377 }
0378 }
0379
0380 day_of_year_type t_day_of_year(1);
0381 t_day_of_year = day_of_year_type(day_of_year);
0382 break;
0383 }
0384 case 'm':
0385 {
0386 match_results mr;
0387 month = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
0388 if(month == -1) {
0389 if(sv_parser.match(sitr, stream_end, mr)) {
0390 return date_type(static_cast<special_values>(mr.current_match));
0391 }
0392 }
0393 t_month = month_type(month);
0394 break;
0395 }
0396 case 'Y':
0397 {
0398 match_results mr;
0399 year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 4);
0400 if(year == -1) {
0401 if(sv_parser.match(sitr, stream_end, mr)) {
0402 return date_type(static_cast<special_values>(mr.current_match));
0403 }
0404 }
0405 t_year = year_type(year);
0406 break;
0407 }
0408 case 'y':
0409 {
0410 match_results mr;
0411 year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
0412 if(year == -1) {
0413 if(sv_parser.match(sitr, stream_end, mr)) {
0414 return date_type(static_cast<special_values>(mr.current_match));
0415 }
0416 }
0417 year += 2000;
0418 t_year = year_type(year);
0419 break;
0420 }
0421 default:
0422 {}
0423
0424 }
0425
0426 }
0427 else {
0428 sitr++;
0429 }
0430
0431 itr++;
0432 }
0433 else {
0434 itr++;
0435 if (use_current_char) {
0436 use_current_char = false;
0437 }
0438 else {
0439 sitr++;
0440 }
0441 }
0442 }
0443
0444 if (day_of_year > 0) {
0445 date_type d(static_cast<unsigned short>(year-1),12,31);
0446 return d + duration_type(day_of_year);
0447 }
0448
0449 return date_type(t_year, t_month, t_day);
0450
0451 }
0452
0453
0454 month_type
0455 parse_month(std::istreambuf_iterator<charT>& sitr,
0456 std::istreambuf_iterator<charT>& stream_end,
0457 string_type format_str) const
0458 {
0459 match_results mr;
0460 return parse_month(sitr, stream_end, format_str, mr);
0461 }
0462
0463
0464 month_type
0465 parse_month(std::istreambuf_iterator<charT>& sitr,
0466 std::istreambuf_iterator<charT>& stream_end,
0467 string_type format_str,
0468 match_results& mr) const
0469 {
0470 bool use_current_char = false;
0471
0472
0473 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0474
0475 short month(0);
0476
0477 const_itr itr(format_str.begin());
0478 while (itr != format_str.end() && (sitr != stream_end)) {
0479 if (*itr == '%') {
0480 if ( ++itr == format_str.end())
0481 break;
0482 if (*itr != '%') {
0483 switch(*itr) {
0484 case 'b':
0485 {
0486 mr = m_month_short_names.match(sitr, stream_end);
0487 month = mr.current_match;
0488 if (mr.has_remaining()) {
0489 use_current_char = true;
0490 }
0491 break;
0492 }
0493 case 'B':
0494 {
0495 mr = m_month_long_names.match(sitr, stream_end);
0496 month = mr.current_match;
0497 if (mr.has_remaining()) {
0498 use_current_char = true;
0499 }
0500 break;
0501 }
0502 case 'm':
0503 {
0504 month = var_string_to_int<short, charT>(sitr, stream_end, 2);
0505
0506
0507 break;
0508 }
0509 default:
0510 {}
0511
0512 }
0513
0514 }
0515 else {
0516 sitr++;
0517 }
0518
0519 itr++;
0520 }
0521 else {
0522 itr++;
0523 if (use_current_char) {
0524 use_current_char = false;
0525 }
0526 else {
0527 sitr++;
0528 }
0529 }
0530 }
0531
0532 return month_type(month);
0533 }
0534
0535
0536 day_type
0537 parse_var_day_of_month(std::istreambuf_iterator<charT>& sitr,
0538 std::istreambuf_iterator<charT>& stream_end) const
0539 {
0540
0541 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0542
0543 return day_type(var_string_to_int<short, charT>(sitr, stream_end, 2));
0544 }
0545
0546 day_type
0547 parse_day_of_month(std::istreambuf_iterator<charT>& sitr,
0548 std::istreambuf_iterator<charT>& stream_end) const
0549 {
0550
0551 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0552
0553
0554 match_results mr;
0555 return day_type(fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2));
0556 }
0557
0558 day_of_week_type
0559 parse_weekday(std::istreambuf_iterator<charT>& sitr,
0560 std::istreambuf_iterator<charT>& stream_end,
0561 string_type format_str) const
0562 {
0563 match_results mr;
0564 return parse_weekday(sitr, stream_end, format_str, mr);
0565 }
0566 day_of_week_type
0567 parse_weekday(std::istreambuf_iterator<charT>& sitr,
0568 std::istreambuf_iterator<charT>& stream_end,
0569 string_type format_str,
0570 match_results& mr) const
0571 {
0572 bool use_current_char = false;
0573
0574
0575 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0576
0577 short wkday(0);
0578
0579 const_itr itr(format_str.begin());
0580 while (itr != format_str.end() && (sitr != stream_end)) {
0581 if (*itr == '%') {
0582 if ( ++itr == format_str.end())
0583 break;
0584 if (*itr != '%') {
0585 switch(*itr) {
0586 case 'a':
0587 {
0588
0589
0590
0591
0592 mr = m_weekday_short_names.match(sitr, stream_end);
0593 wkday = mr.current_match;
0594 if (mr.has_remaining()) {
0595 use_current_char = true;
0596 }
0597 break;
0598 }
0599 case 'A':
0600 {
0601
0602
0603
0604
0605 mr = m_weekday_long_names.match(sitr, stream_end);
0606 wkday = mr.current_match;
0607 if (mr.has_remaining()) {
0608 use_current_char = true;
0609 }
0610 break;
0611 }
0612 case 'w':
0613 {
0614
0615 wkday = var_string_to_int<short, charT>(sitr, stream_end, 2);
0616 break;
0617 }
0618 default:
0619 {}
0620
0621 }
0622
0623 }
0624 else {
0625 sitr++;
0626 }
0627
0628 itr++;
0629 }
0630 else {
0631 itr++;
0632 if (use_current_char) {
0633 use_current_char = false;
0634 }
0635 else {
0636 sitr++;
0637 }
0638 }
0639 }
0640
0641 return day_of_week_type(wkday);
0642
0643 }
0644
0645
0646 year_type
0647 parse_year(std::istreambuf_iterator<charT>& sitr,
0648 std::istreambuf_iterator<charT>& stream_end,
0649 string_type format_str) const
0650 {
0651 match_results mr;
0652 return parse_year(sitr, stream_end, format_str, mr);
0653 }
0654
0655
0656 year_type
0657 parse_year(std::istreambuf_iterator<charT>& sitr,
0658 std::istreambuf_iterator<charT>& stream_end,
0659 string_type format_str,
0660 match_results& mr) const
0661 {
0662
0663 while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
0664
0665 unsigned short year(0);
0666
0667 const_itr itr(format_str.begin());
0668 while (itr != format_str.end() && (sitr != stream_end)) {
0669 if (*itr == '%') {
0670 if ( ++itr == format_str.end())
0671 break;
0672 if (*itr != '%') {
0673
0674 switch(*itr) {
0675 case 'Y':
0676 {
0677
0678 year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 4);
0679 break;
0680 }
0681 case 'y':
0682 {
0683
0684 year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
0685 year += 2000;
0686 break;
0687 }
0688 default:
0689 {}
0690
0691 }
0692
0693 }
0694 else {
0695 sitr++;
0696 }
0697
0698 itr++;
0699 }
0700 else {
0701 itr++;
0702 sitr++;
0703 }
0704 }
0705
0706 return year_type(year);
0707 }
0708
0709
0710 private:
0711 string_type m_format;
0712 parse_tree_type m_month_short_names;
0713 parse_tree_type m_month_long_names;
0714 parse_tree_type m_weekday_short_names;
0715 parse_tree_type m_weekday_long_names;
0716
0717 };
0718
0719 } }
0720
0721 #endif
0722
0723
0724