Re: [Boost-users] [date_time] How to create a date from string with specific format?
Good question -- this is the kind of thing I've been struggling with lately (I tried to post a question about it to the group, but I worded it poorly and the moderator rejected it). Anyway, here's the solution I came up with. I am sure there are better ones! - Dean //! Utility function to split apart string. Returns # of components. inline int split_into_two_or_less(const std::string& s, char sep, std::string& first, std::string& second) { int sep_pos = static_cast<int>(s.find(sep)); if (sep_pos == -1) { first = s; return 1; } else { first = s.substr(0,sep_pos); second = s.substr(sep_pos+1); return 2; } } class expected_character : public boost::bad_lexical_cast { char _messagebuf[81]; public: expected_character(const char* who, char ch, const char* str, int pos) { snprintf(_messagebuf, sizeof(_messagebuf), "%s: Expected '%c' at position %d in \"%s\"", who, ch, pos, str); _messagebuf[sizeof(_messagebuf)-1] = '\0'; } const char* what() const throw() { return _messagebuf; } }; //! Parse date string of form YYYY-MM-DD // Code adapted from boost/date_time/date_parsing.hpp's parse_undelimited_date() template <class date_type> inline date_type parse_delimited_iso_8601_date(const std::string& s) { int offsets[] = {4,1,2,1,2}; int pos = 0; typedef typename date_type::year_type year_type; typename date_type::ymd_type ymd((year_type::min)(),1,1); // TODO: Is there a boost macro for sizeof(a)/sizeof(type)? or for the end of an array? boost::offset_separator osf(offsets, offsets+sizeof(offsets)/sizeof(offsets[0])); boost::tokenizerboost::offset_separator tok(s, osf); for(boost::tokenizerboost::offset_separator::iterator ti=tok.begin(); ti!=tok.end();++ti) { switch(pos) { case 0: ymd.year = boost::lexical_cast<unsigned short>(*ti); break; case 1: if (*ti != "-") { throw expected_character("parse_delimited_iso_8601_date", '-', s.c_str(), 5); } break; case 2: ymd.month = boost::lexical_cast<unsigned short>(*ti); break; case 3: if (*ti != "-") { throw expected_character("parse_delimited_iso_8601_date", '-', s.c_str(), 7); } break; case 4: ymd.day = boost::lexical_cast<unsigned short>(*ti); break; } pos++; } return date_type(ymd); }
Hi Dean, thanks for the answer. Since, I know the format of the date strings I could also use boost::regex for the general format and then feeding a date object with the values. If I get an exception during the date object contruction I know that the user provided me with garbage. Here is some code: // date format: mm-dd-yyyy boost::regex oDateReg( "\\d{2}-\\d{2}-\\d{4}" ); std::string strDate( "11-33-1997" ); if( boost::regex_match( strDate , oDateReg )) { try { std::string strMonth = strDate.substr( 0, 2 ); std::string strDay = strDate.substr( 3, 2 ); std::string strYear = strDate.substr( 6, 4 ); unsigned int nYear = boost::lexical_cast<unsigned int>(strYear); unsigned int nMonth = boost::lexical_cast<unsigned int>(strMonth); unsigned int nDay = boost::lexical_cast<unsigned int>(strDay); date d( nYear, nMonth, nDay ); date::ymd_type ymd = d.year_month_day(); } catch( std::out_of_range oEx ) { std::cout << "Error: " << oEx.what() << std::endl; } } Any thoughts on that? Thanks again, Christian
participants (2)
-
Christian Henning
-
Dean Sturtevant