Question

I am trying to get the number of seconds that have elapsed since epoch. The code:

long parseTime(string time) {

  cout << "Time entered = " << time << endl;

  long timeSinceEpoch;

  //takes in time in string format - date + time and returns seconds from epoch.
  /* Steps:
   * 1. Remove trailing and leading spaces.
   * 2. Check format of date.
   * 3. Convert to epoch.
   */

  //remove trailing and leading spaces.
  /*
  unsigned int leading = 0, trailing = 0;
  string whitespace = " \t";

  leading = time.find_first_not_of(whitespace);
  trailing = time.find_last_not_of(whitespace);

  string newTime = time.substr(leading, (trailing - leading + 1));
  cout << "Old time = " << time << " new time = " << newTime << endl;
  */
  string newTime = time;

  struct tm t;

  if(newTime.find("/") != string::npos) {
    //format of date is mm/dd/yyyy. followed by clock in hh:mm (24 hour clock).
    cout << "Time format contains slashes." << endl;
    if(strptime(newTime.c_str(), "%m/%e/%Y %H:%M", &t) == NULL) {
      cout << "Error. Check string for formatting." << endl;
    }
  } else if(newTime.find("-") != string::npos) {
    //format of date is yyyy-mm-dd hh:mm:ss (hh in 24 hour clock format).
    if(strptime(newTime.c_str(), "%Y-%m-%e %H:%M:%S", &t) == NULL) {
     cout << "Error. Check string for formatting of new date." << endl;
    }
  }

  if(t.tm_isdst) {
    t.tm_isdst = 0;
  }

  timeSinceEpoch = mktime(&t);
  cout << "Time since epoch = " << timeSinceEpoch << endl;

  return timeSinceEpoch;
}

Now, when a string containing date and time is passed to the function:
3/26/2013 3:17
It results in time since epoch = -1. Here is the output from the debugger:

Breakpoint 2, parseTime (time=...) at informationExtractor.cpp:44
44        cout << "Time entered = " << time << endl;
(gdb) n
Time entered = 3/26/2013 3:17
66        string newTime = time;
(gdb)
70        if(newTime.find("/") != string::npos) {
(gdb) p newTime
$3 = {static npos = <optimized out>,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
    _M_p = 0x8004ab0c "3/26/2013 3:17"}}
(gdb) n
72          cout << "Time format contains slashes." << endl;
(gdb)
Time format contains slashes.
73          if(strptime(newTime.c_str(), "%m/%e/%Y %H:%M", &t) == NULL) {
(gdb)
83        if(t.tm_isdst) {
(gdb) p newTime.c_str()@strlen(newTime.c_str())
Only values in memory can be extended with '@'.
(gdb) n
84          t.tm_isdst = 0;
(gdb) p newTime
$4 = {static npos = <optimized out>,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
    _M_p = 0x8004ab0c "3/26/2013 3:17"}}
(gdb) n
87        timeSinceEpoch = mktime(&t);
(gdb) p t
$5 = {tm_sec = 1628993312, tm_min = 17, tm_hour = 3, tm_mday = 26, tm_mon = 2, tm_year = 113, tm_wday = 2, tm_yday = 84,
  tm_isdst = 0}
(gdb) n
88        cout << "Time since epoch = " << timeSinceEpoch << endl;
(gdb)
Time since epoch = -1
90        return timeSinceEpoch;
(gdb)  

If you notice, tm_sec in t is 1628993312 while timesinceEpoch is -1. tm_sec is also well within the range for long which is the datatype of timesinceEpoch. Any ideas on why and how to solve for this are welcome.

Was it helpful?

Solution

The point is that in your code tm_sec is an uninitialised value. It should be a value between 0 and 59. So add this line of code to your first if branch.

if(strptime(newTime.c_str(), "%m/%e/%Y %H:%M", &t) == NULL) {
  cout << "Error. Check string for formatting." << endl;
}
t.tm_sec = 0; // initialise seconds field

OTHER TIPS

john is right. strptime does not initialize tm and only touch fields which is explicitly specified (see "Notes" of strptime(3)), so t.tm_sec is not initialized.

To prevent this kind of error, you can declare varialbes with initialization

struct tm t = { 0 }; // zero filled
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top