Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mktime and tm_isdst

I saw a lot of different views so thought of asking here.

I read man mktime:

 (A positive or zero value for tm_isdst causes mktime() to presume initially
 that summer time (for example, Daylight Saving Time) is or is not in
 effect for the specified time, respectively.  A negative value for
 tm_isdst causes the mktime() function to attempt to divine whether summer
 time is in effect for the specified time. 

My question is, shouldn't tm_isdst be kept as -1 to let the system decide if its dst or not and that way the code becomes dst agnostic?

Am I missing something?

like image 952
hari Avatar asked Dec 19 '11 08:12

hari


People also ask

What is Tm_isdst in C?

Setting tm_isdst to - 1 tells the mktime() function to determine whether daylight savings time applies. If so, mktime() returns tm_isdst greater than 0 . If not, it returns tm_isdst of 0 unless DST information is not available on the system, in which case mktime() returns tm_isdst of - 1 .

What does mktime do?

The mktime() function returns the Unix timestamp for a date. Tip: This function is identical to gmmktime() except the passed parameters represents a date (not a GMT date).

What is Mktime in C?

C library function - mktime() The C library function time_t mktime(struct tm *timeptr) converts the structure pointed to by timeptr into a time_t value according to the local time zone.

What does Mktime return?

The mktime() function returns Universal Coordinate Time (UTC) having type time_t. The value (time_t)(-1) is returned if the Universal Coordinate Time cannot be represented.


2 Answers

You should avoid setting tm_isdst to -1 if possible. The system can't always determine DST status from date and time alone. It is ambiguous the hour before and after DST ends. For example, if you pass mktime() 1:30 AM November 4, 2012, that's not enough information to get a correct time_t value from mktime(). Usually I have seen mktime() assume standard time in the case that it is ambiguous, but I haven't seen any documentation that guarantees that behavior on all platforms. 1:30 AM November 4, 2012 with tm_isdst == 1 would be 1 hour before, because the hour 1:00:00 to 1:59:59 repeats.

#include <stdio.h>
#include <time.h>

int main()
{
    time_t daylight, standard;
    struct tm timestr;
    double diff;

    timestr.tm_year = 2012 - 1900;
    timestr.tm_mon = 11 - 1;
    timestr.tm_mday = 4;
    timestr.tm_hour = 1;
    timestr.tm_min = 30;
    timestr.tm_sec = 0;

    /* first with standard time */
    timestr.tm_isdst = 0;
    standard = mktime(&timestr);

    /* now with daylight time */
    timestr.tm_isdst = 1;
    daylight = mktime(&timestr);

    diff = difftime(standard, daylight);

    printf("Difference is %f hour(s)", diff/60.0/60.0);

    return 0;
}

This produces:

Difference is 1.000000 hour(s)

Both are November 4, 2012 1:30 AM, however both are two distinct time_t values, 1 hour apart.

mktime() essentially has 2 outputs:

  • time_t
  • repaired time struct

The time struct is both an input and output. It is modified by mktime() to return all struct members to nominal ranges. For example, if you increment the tm_hour member += 500, that means increment the time by 500 hours. The tm_hour member will be changed to a value 00 to 23, and the tm_day, tm_mday, and etc will all be adjusted accordingly. tm_isdst is also both an input and output. Its values are as follows:

  • 1 (DST in effect, i.e. daylight time)
  • 0 (DST not in effect, i.e. standard time)
  • -1 (Unknown DST status)

So mktime() will output either a 1 or 0 for tm_isdst, never -1.

-1 is a possible input, but I would think of it as meaning "Unknown". Don't think of it as meaning "determine automatically", because in general, mktime() can't always determine it automatically.

The explicit DST status (0 or 1) should come from something external to the software, for example store it in the file or database, or prompt the user.

like image 174
Rich Jahn Avatar answered Oct 03 '22 10:10

Rich Jahn


I believe the original reason for that is some timezones do not have daylight savings time. Since mktime is not async-safe nor is it re-entrant allows the implementation to store the current value of daylight savings in the POSIX extern char tzname[2], indexed by daylight [0 or 1]. This means tzname[0]="[std TZ name]" and tzname="[daylight TZ name, e.g. EDT]"

See your tzset() man page for more information on this. Standards conforming mktime() is required to behave as though it called tzset() anyway. This kind of obviates the use of tm_isdst, IMO.

Bottom line: your particular implementation and timezone(s) would dictate whether you would use -1, 0, or 1 for tm_isdst. There is no one default correct way for all implementations.

like image 5
jim mcnamara Avatar answered Oct 03 '22 11:10

jim mcnamara