15

How do I convert a date string, formatted as "MM-DD-YY HH:MM:SS", to a time_t value in either C or C++?

Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188
An̲̳̳drew
  • 13,375
  • 13
  • 47
  • 46

7 Answers7

20

Use strptime() to parse the time into a struct tm, then use mktime() to convert to a time_t.

Robert Gamble
  • 106,424
  • 25
  • 145
  • 137
  • strptime() doesn't appear to be available on Windows. Is there a good alternative? – An̲̳̳drew Nov 26 '08 at 19:17
  • Don't know if a good alternative on Windows, there are several open source implementations floating around that you could use. Alternatively, if you know the date will always be in the format you provided, you can parse it into a struct tm, perhaps using sscanf, and then use mktime to get a time_t. – Robert Gamble Nov 26 '08 at 19:23
  • here's an example http://stackoverflow.com/a/11213640/1115059 – Jaydeep Solanki Sep 19 '14 at 01:46
  • @An̲̳̳drew `strptime()` is often available on Windows with a gcc compiler. The availability is a compiler issue, not an OS one. – chux - Reinstate Monica Jan 30 '18 at 00:07
4

In the absence of strptime you could use sscanf to parse the data into a struct tm and then call mktime. Not the most elegant solution but it would work.

Rob
  • 76,700
  • 56
  • 158
  • 197
3

Boost's date time library should help; in particular you might want to look at http://www.boost.org/doc/libs/1_37_0/doc/html/date_time/date_time_io.html

3

Note that strptime mentioned in accepted answer is not portable. Here's handy C++11 code I use to convert string to std::time_t :

static std::time_t to_time_t(const std::string& str, bool is_dst = false, const std::string& format = "%Y-%b-%d %H:%M:%S")
{
    std::tm t = {0};
    t.tm_isdst = is_dst ? 1 : 0;
    std::istringstream ss(str);
    ss >> std::get_time(&t, format.c_str());
    return mktime(&t);
}

You can call it like this:

std::time_t t = to_time_t("2018-February-12 23:12:34");

You can find string format parameters here.

Shital Shah
  • 63,284
  • 17
  • 238
  • 185
  • 1) Code does not set the `tm_isdst` member. Failing to do so can make for inconsistent results. 2) `struct tm` does allow for additional members that benefit with initialization. Perhaps `std::tm t = { 0 };`? 3) OP's month string is numeric, not alpha, Use `"%m"` rather then `"%b"`. 4) OP used different order than YMD hms. – chux - Reinstate Monica Jan 30 '18 at 00:42
  • I've added dst option. Init with 0 is good idea. Other things can easily be adjusted as individual requirements. – Shital Shah Feb 23 '18 at 07:07
2

I'm afraid there isn't any in Standard C / C++ . There is the POSIX function strptime which can convert to struct tm, which can then be converted to time_t using mktime.

If you are aiming for cross platform compatibility, better use boost::date_time, which has sophisticated functions for this.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
1

best way to convert a date string, formatted as "MM-DD-YY HH:MM:SS", to a time_t

Restricting code to standard C library functions is looking for the inverse of strftime(). To expand @Rob general idea, uses sscanf().

Use "%n" to detect completed scan

time_t date_string_to_time(const char *date) {
  struct tm tm = { 0 }; // Important, initialize all members
  int n = 0;
  sscanf(date, "%d-%d-%d %d:%d:%d %n", &tm.tm_mon, &tm.tm_mday, &tm.tm_year,
      &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &n);
  // If scan did not completely succeed or extra junk
  if (n == 0 || date[n]) {
    return (time_t) -1;
  }
  tm.tm_isdst = -1; // Assume local daylight setting per date/time
  tm.tm_mon--;      // Months since January
  // Assume 2 digit year if in the range 2000-2099, else assume year as given
  if (tm.tm_year >= 0 && tm.tm_year < 100) {
    tm.tm_year += 2000;
  }
  tm.tm_year -= 1900; // Years since 1900
  time_t t = mktime(&tm);
  return t;
}

Additional code could be used to insure only 2 digit timestamp parts, positive values, spacing, etc.

Note: this assume the "MM-DD-YY HH:MM:SS" is a local time.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 1
    Interesting, I've never really found a use case for `%n` since I've always used the return value of `*scanf` to ensure all arguments were scanned. However, it appears `%n` (the way you use it) does this *and* ensures there's no extra gumpf following the expected string. It's not often I learn anything new about C nowadays, so kudos :-) – paxdiablo Jan 30 '18 at 00:40
  • 1
    @paxdiablo Thanks. The `" %n"`, in general, helps detect any required trailing text too, something the return value does not distinguish. E.g. `"%d xyz %n"`. – chux - Reinstate Monica Jan 30 '18 at 00:46
-1
    static time_t MKTimestamp(int year, int month, int day, int hour, int min, int sec)
{
    time_t rawtime;
    struct tm * timeinfo;

    time ( &rawtime );
    timeinfo = gmtime ( &rawtime );
    timeinfo->tm_year = year-1900 ;
    timeinfo->tm_mon = month-1;
    timeinfo->tm_mday = day;
    timeinfo->tm_hour = hour;
    timeinfo->tm_min = min;
    timeinfo->tm_sec = sec;
    timeinfo->tm_isdst = 0; // disable daylight saving time

    time_t ret = mktime ( timeinfo );

    return ret;
}

 static time_t GetDateTime(const std::string pstr)
{
    try 
    {
        // yyyy-mm-dd
        int m, d, y, h, min;
        std::istringstream istr (pstr);

        istr >> y;
        istr.ignore();
        istr >> m;
        istr.ignore();
        istr >> d;
        istr.ignore();
        istr >> h;
        istr.ignore();
        istr >> min;
        time_t t;

        t=MKTimestamp(y,m,d,h-1,min,0);
        return t;
    }
    catch(...)
    {

    }
}
hmehdi
  • 101
  • 1
  • 5