Search code examples
cdatetimeunix-timestamp

Why is mktime unsetting gmtoff ? How to make mktime use the gmtoff field?


I want to get an unix timestamp from a string containing a representation of the time of the form YYYYMMDDThhmmss+TZ.

For that, I convert the string into a struct tm and then use mktime to convert it to an unix timestamp.

str = "20150228T202832+02";
struct tm time_struct = {0};
strptime(str,"%Y%m%dT%H%M%S%z", &time_struct);
uint64_t timestamp = mktime(&time_struct); /* ignore and unset TZ */

It becomes a problem when I use a different time zone than the one I'm in. The mktime function ignores and unset the tm_gmtoff field of the struct tm, returning a wrong timestamp (the difference is given by the string's time zone minus my time zone).

  • Why is mktime ignoring the tm_gmtoff field of the struct tm?
  • Why is mktime setting the tm_gmtoff field to my current time zone without modifying accordingly the rest of the struct tm ? (making the struct tm represent a different time!)

To correct this behavior, I would like to add the difference between my time zone and the time zone of the string to the fields of the struct tm, before making the call to mktime.

  • How could I get my current time zone without making a new (useless) struct tm ?

Solution

  • Here is a code snippet that responds to my problem. The trick was to use the global variable timezone.

    /*
        Function: timestamp_from_datetime
        Returns the timestamp corresponding to a formated string YYYYMMDDTHHMMSS+TZ
    
        Parameters:
            datetime - must be non-NULL
    
        Returns:
            The timestamp associated to datetime
     */
    time_t timestamp_from_datetime(const char *datetime)
    {
        struct tm time_struct = (struct tm) {0};
        strptime(datetime,"%Y%m%dT%H%M%S%z", &time_struct);
        long int gmtoff = time_struct.tm_gmtoff;
        return mktime(&time_struct) - gmtoff - timezone;
    }