Home > Back-end >  tm struct converts to wrong time_t
tm struct converts to wrong time_t

Time:09-28

I have the following code to parse a datetime string received from GPS satellites into the struct tm, and then use mktime() to get the epoch from it, the result is correct on my Debian machine, but wrong on my ESP32 with ESP-IDF, do you have any suggestion on why this is happening, is something wrong with DST or timezone stuff?

#include "rs_time.h"

time_t time_from_gnss_info_time(const char * datetime_str){
    time_t epoch;
    struct tm tm;
    sscanf(
        datetime_str,
        "M-----",
        &tm.tm_year,
        &tm.tm_mon,
        &tm.tm_mday,
        &tm.tm_hour,
        &tm.tm_min,
        &tm.tm_sec
    );
    epoch = mktime(&tm); // result is '1462765068' or Mon May  9 03:37:48 2016
    printf("the date and time is: %s %ld ",ctime(&epoch), time(NULL));
    return epoch;

}

the value for epoch after using mktime() when the datetime_str is '20210913221332' is: 1462765068, also the ctime() representation is : Mon May 9 03:37:48 2016

CodePudding user response:

  • .tm_year is years since 1900. .tm_mon is months since January.

  • mktime() uses all members of struct tm (except for .tm_wday, .tm_yday) to form the return value. OP's code did not initialize/set .tm_isdst or others - struct tm may have more than usual 9 members. Initialize them all.

  • mktime() forms a time_t assuming struct tm is a local time, not universal time which is usually what GPS provides. TZ adjustment may be needed - not yet shown.

  • time_t does not certainly match a long. Cast to a wide type. (time_t may even be floating point.) and match specifiers.

  • Add error checking.

time_t time_from_gnss_info_time(const char *datetime_str) {
  // Code is likely scanning per the current daylight time setting.
  // Use .tm_isdst = -1 to let mktime to determine it.
  // Or use 0 for standard time or any   value for daylight time.
  // All other members are zeroed
  // struct tm tm; // Not this
  struct tm tm = {.tm_isdst = -1};
  if (sscanf(datetime_str, "M-----", &tm.tm_year, &tm.tm_mon,
      &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
    return -1;
  }
  // Adjust some members.
  tm.tm_year -= 1900;
  tm.tm_mon--;
  time_t epoch = mktime(&tm);
  printf("The date and time is: %s%lld\n", ctime(&epoch),
      (long long) time(NULL));
  return epoch;
}

int main(void) {
  time_t t = time_from_gnss_info_time("20210913221332");
  printf("%lld\n", (long long) t);
}

Output

The date and time is: Mon Sep 13 22:13:32 2021
1664290016
1631589212

Additional error checking possible: extra txt, spaces, signs, extreme values, ...

  • Related