How to parse and check date in std :: string in C ++?

I am working on a project where I need to read a date to make sure it is a valid date. For example, February 29th is only a valid date in leap years, or June 31st is not a valid date, so the computer will display this information based on input. My problem is that I cannot figure out how to parse a string so that the user can enter “05/11/1996” as a date (for example), and then take this and put it in separate integers. I was thinking of trying to do something with a while loop and a string thread, but I was a bit stuck. If someone could help me, I would really appreciate it.

+6
c ++ string date validation parsing
source share
4 answers

If the format is similar to your example, you can take out an integer as follows:

int day, month, year; sscanf(buffer, "%2d/%2d/%4d", &month, &day, &year); 

where, of course, in the buffer you have a date ("05/11/1996")

+5
source share

A possible solution can also be based on strptime , however, note that this function only checks if the day is from the interval <1;31> and the month is from <1;12> , i.e. "30/02/2013" remains valid:

 #include <iostream> #include <ctime> int main() { struct tm tm; std::string s("32/02/2013"); if (strptime(s.c_str(), "%d/%m/%Y", &tm)) std::cout << "date is valid" << std::endl; else std::cout << "date is invalid" << std::endl; } 
But since strptime not always available, and an extra check would be nice, here is what you could do:
  • extraction day, month, year
  • fill in struct tm
  • normalize him
  • check if the normalized date is still the same as for the day, month, year.

i.e:.

 #include <iostream> #include <sstream> #include <ctime> // function expects the string in format dd/mm/yyyy: bool extractDate(const std::string& s, int& d, int& m, int& y){ std::istringstream is(s); char delimiter; if (is >> d >> delimiter >> m >> delimiter >> y) { struct tm t = {0}; t.tm_mday = d; t.tm_mon = m - 1; t.tm_year = y - 1900; t.tm_isdst = -1; // normalize: time_t when = mktime(&t); const struct tm *norm = localtime(&when); // the actual date would be: // m = norm->tm_mon + 1; // d = norm->tm_mday; // y = norm->tm_year; // eg 29/02/2013 would become 01/03/2013 // validate (is the normalized date still the same?): return (norm->tm_mday == d && norm->tm_mon == m - 1 && norm->tm_year == y - 1900); } return false; } 

used as:

 int main() { std::string s("29/02/2013"); int d,m,y; if (extractDate(s, d, m, y)) std::cout << "date " << d << "/" << m << "/" << y << " is valid" << std::endl; else std::cout << "date is invalid" << std::endl; } 

which in this case would date is invalid , since normalization would detect that 29/02/2013 was normalized on 01/03/2013 .

+11
source share

I would prefer to use Boost DateTime:

Watch Live on Coliru

 #include <iostream> #include <boost/date_time/local_time/local_time.hpp> struct dateparser { dateparser(std::string fmt) { // set format using namespace boost::local_time; local_time_input_facet* input_facet = new local_time_input_facet(); input_facet->format(fmt.c_str()); ss.imbue(std::locale(ss.getloc(), input_facet)); } bool operator()(std::string const& text) { ss.clear(); ss.str(text); bool ok = ss >> pt; if (ok) { auto tm = to_tm(pt); year = tm.tm_year; month = tm.tm_mon + 1; // for 1-based (1:jan, .. 12:dec) day = tm.tm_mday; } return ok; } boost::posix_time::ptime pt; unsigned year, month, day; private: std::stringstream ss; }; int main(){ dateparser parser("%d/%m/%Y"); // not thread safe // parse for (auto&& txt : { "05/11/1996", "30/02/1983", "29/02/2000", "29/02/2001" }) { if (parser(txt)) std::cout << txt << " -> " << parser.pt << " is the " << parser.day << "th of " << std::setw(2) << std::setfill('0') << parser.month << " in the year " << parser.year << "\n"; else std::cout << txt << " is not a valid date\n"; } } 

Outputs:

 05/11/1996 -> 1996-Nov-05 00:00:00 is the 5th of 11 in the year 96 30/02/1983 is not a valid date 29/02/2000 -> 2000-Feb-29 00:00:00 is the 29th of 02 in the year 100 29/02/2001 is not a valid date 
+5
source share

Another option is to use std::get_time from the <iomanip> header (available since C ++ 11). A good example of its use can be found here .

+3
source share

All Articles