How to parse date / time from a string?

Input : strings with date and optional time. Different views would be good, but necessary. Strings are user supplied and may be distorted. Examples:

  • "2004-03-21 12:45:33" (I think this is the default layout)
  • "2004/03/21 12:45:33" (optional layout)
  • "23.09.2004 04:12:21" (German format, optional)
  • "2003-02-11" (time may be absent)

Required result : seconds from the era (1970/01/01 00:00:00) or another fixed point.

Bonus In addition, reading the UTC offset of local system time would be great.

It is assumed that the input is considered local time on the machine in question. The output must be UTC. The system is Linux only (needs Debian Lenny and Ubuntu).

I tried using boost/date_time , but I have to admit that I cannot wrap my head around the documentation. The following works without the necessary conversion from local system time to UTC:

 std::string date = "2000-01-01"; boost::posix_time::ptime ptimedate = boost::posix_time::time_from_string(date); ptimedate += boost::posix_time::hours(Hardcoded_UTC_Offset);// where to get from? struct tm = boost::posix_time::to_tm(ptimedate); int64_t ticks = mktime(&mTmTime); 

I think boost::date_time can provide the necessary UTC offset, but I don't know how to do it.

+48
c ++ boost datetime utc boost-date-time
Sep 24 '10 at 10:37
source share
4 answers

Although I don’t know how to format a one-month input to boost, I can do it after two-digit editing:

 #include <iostream> #include <boost/date_time.hpp> namespace bt = boost::posix_time; const std::locale formats[] = { std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d %H:%M:%S")), std::locale(std::locale::classic(),new bt::time_input_facet("%Y/%m/%d %H:%M:%S")), std::locale(std::locale::classic(),new bt::time_input_facet("%d.%m.%Y %H:%M:%S")), std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d"))}; const size_t formats_n = sizeof(formats)/sizeof(formats[0]); std::time_t pt_to_time_t(const bt::ptime& pt) { bt::ptime timet_start(boost::gregorian::date(1970,1,1)); bt::time_duration diff = pt - timet_start; return diff.ticks()/bt::time_duration::rep_type::ticks_per_second; } void seconds_from_epoch(const std::string& s) { bt::ptime pt; for(size_t i=0; i<formats_n; ++i) { std::istringstream is(s); is.imbue(formats[i]); is >> pt; if(pt != bt::ptime()) break; } std::cout << " ptime is " << pt << '\n'; std::cout << " seconds from epoch are " << pt_to_time_t(pt) << '\n'; } int main() { seconds_from_epoch("2004-03-21 12:45:33"); seconds_from_epoch("2004/03/21 12:45:33"); seconds_from_epoch("23.09.2004 04:12:21"); seconds_from_epoch("2003-02-11"); } 

note that seconds-from-era output will assume that the date is in UTC:

 ~ $ ./test | head -2 ptime is 2004-Mar-21 12:45:33 seconds from epoch are 1079873133 ~ $ date -d @1079873133 Sun Mar 21 07:45:33 EST 2004 

You could use boost::posix_time::c_time::localtime() from #include <boost/date_time/c_time.hpp> to get this conversion, assuming the input is in the current time zone, but it's pretty inconsistent: for me, for example, the result will be different between today and the next month, when daylight saving time ends.

+58
Sep 24 2018-10-12T00:
source share
β€” -

boost::gregorian contains some things you need if you don't do more work:

 using namespace boost::gregorian; { // The following date is in ISO 8601 extended format (CCYY-MM-DD) std::string s("2000-01-01"); date d(from_simple_string(s)); std::cout << to_simple_string(d) << std::endl; } 

There is an example of how to use UTC offsets with boost::posix_time here .

You can generate date and time from custom input string formats using date_input_facet and time_input_facet . There is an I / O tutorial on this page that should help you get started.

+7
Sep 24 2018-10-10T00:
source share

If the c-style is valid: strptime () is the way to go, because you can specify the format and it can take the language in the account:

 tm brokenTime; strptime(str.c_str(), "%Y-%m-%d %T", &brokenTime); time_t sinceEpoch = timegm(brokenTime); 

Different layouts should be checked with a return value (if possible). The time zone should be added by checking the system clock (localtime_r () using time (), tm_zone)

+6
Sep 24 '10 at 11:10
source share

The simplest portable solution is to use scanf :

 int year, month, day, hour, minute, second = 0; int r = 0; r = scanf ("%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second); if (r == 6) { printf ("%d-%d-%d %d:%d:%d\n", year, month, day, hour, minute, second); } else { r = scanf ("%d/%d/%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second); // and so on ... 

Initialize a struct tm using int values ​​and pass it to mktime to get calendar time as time_t . To convert time zones, please see the Information in gmtime .

+1
Sep 24 '10 at 11:02
source share



All Articles