相关文章推荐
成熟的圣诞树  ·  从DX 12 ...·  1 周前    · 
另类的单车  ·  如何卸载.vsix ...·  2 天前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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?

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.

    Well if you don't know the DST you need to determine it yourself (good luck with that), or set it to -1. There is no other option. If you set it to 0, you get no DST at all which is guaranteed wrong, if you set it to 1 you force DST on which is also guaranteed wrong. – rustyx Aug 5, 2016 at 12:25 @RustyX Hard coding to -1, 0, or 1 will always be wrong. -1 is the least bad, but still bad. The explicit status (0 or 1) should be input to the software from the user, or stored in the data (file or database). Basically it must come from something external to the application. – Rich Jahn Dec 20, 2016 at 15:44 @RichJahn: It is stored in a database: the TZ database of about every UNIX/Linux system. About easiest way to retrieve it from there for any given time is to perform mktime with tm_isdst set to -1... And do you remember when DST changes occur? Requiring this information from the user is not something reasonable. "You should avoid setting tm_isdst to -1 if possible." - In what reasonable, common use scenarios is it possible? – SF. Mar 31, 2017 at 10:52 @SF. My entire point is "it" is not stored anywhere. The computer does not know. By analogy, if I said: the absolute value is 5, was the original number positive or negative? You can't write a program to figure that out unless it's a mind-reading program. The answer is: I don't know, you tell me. I know that Nov 5, 2017 midnight is U.S. CDT, and 5:00 AM is U.S. CST. But 1:30 AM? I don't know, you tell me. Applications I've written make it a fatal error or prompt the user if the time is ambiguous. I think most date picker UIs just ignore this issue altogether unfortunately. – Rich Jahn Apr 4, 2017 at 21:27 "So mktime() will output either a 1 or 0" --> I'd expect that to be "So mktime() will output either a positive value or 0". Yet perhaps various Unix flavors are more specific. – chux - Reinstate Monica Aug 13, 2018 at 15:53

    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.

    I think that you should indeed use -1 for the tm_isdst field unless you have the information about the type of time you are dealing with.

    For example, in California we still have PST and PDT. If you are parsing a date and that timezone information is present, then you should set the tm_isdst accordingly. As Jim McNamara mentioned, these names are available in the tzname[] array after a call to tzset().

    For example, the following C++ code write PST/PDT:

    int main(int argc, char * argv [])
        tzset();
        std::cerr << tzname[0] << "/" << tzname[1] << "\n";
        return 0;
    

    The offset in the tzname[] array corresponds to the value of tm_isdst. (PST -- Pacific Standard Time, tm_isdst = 0, and PDT, Pacific Daylight Time, tm_isdst = 1.)

    If you do not have the timezone information in your input, then using -1 is the best choice. You run into a problem only when the date corresponds to the day and time when the change happens. As Rich Jahn explains, on Nov 4, 2012, he had a time change between standard and daylight time and around that time, gmtime() has to make a choice and it is not unlike the opposite of what you'd expect. That being said, it only happens for a total of 2 hours in a year and in the middle of the night. So unless you are working on a critical type of software where date is very important, it probably won't matter much.

    So, as a recap:

  • if you have the timezone attached to the date you want to convert, use that information to determine the value of tm_isdst (that being said, I'm not too sure how you handle that in case you have to support all timezones... the tzname[] array only gives you the user's current timezone.)
  • in all other cases, use -1
  • What you're saying is true, I guess, but sounds so passive, and such a low bar, like I don't have the info, guess I'll just live it it. If you input a local time only, then yes your time will be correct 99.98% of the time, but with just slightly more code it can be correct 100% of the time. Obviously people would not accept voting machines that 0.02% of the time recorded 2 votes instead of 1. My advice is use an unambiguous format like ISO 8601. – Rich Jahn Aug 23, 2019 at 0:00 @RichJahn, Have you tried to go around, say at Walmart, and ask people what the timezone is in that place? How many gave you the right answer? It's a huge burden to teach over 7 billion people what a timezone is. However, most will know what date & time are. My advise would be to ask all governments in the world to drop winter vs summer time to get started. – Alexis Wilke Aug 23, 2019 at 2:34

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.