Evan Teran
Evan Teran

Reputation: 90452

Given a Date/Time as a string, what is the best way to know if it was DST at that time?

Let's say I'm given a string such as this: "2009-4-9", meaning April 9th, 2009. Assuming for starters, that I am only concerned with local time (I have concerns about other time zones as well, but I'll tackle the easy stuff first). What is the best way to know if Daylight Savings was in effect at that time?

You can assume that the system has the properly updated timezone files such as /etc/localtime and I am interested in portable solutions. Either c or c++ are acceptable as well.

You can also assume that I only care about past or present dates, never the future.

Currently I have a "hack" which looks like this (I know localtime_r is a library extension, but it's close enough to the same functionality that I can make it portable)

struct tm tm;
// convert the time string to a broken down structure in localtime
if(strptime("2009-4-9", "%Y-%m-%d", &tm)) {
    // convert the broken down structure into seconds since epoch
    const time_t t = mktime(&tm);

    // convert it back to a broken down structure, this seems pointless at first...
    // but libc will fill out fields such as tm_isdst
    localtime_r(&t, &tm);

    printf("DST : %d\n", tm.tm_isdst);
}

While this works (and seems to be a pretty effective way), I feel like it's silly to be converting back and forth. Is there a better way?

Upvotes: 1

Views: 564

Answers (3)

caf
caf

Reputation: 239051

You do not need to call localtime_r() at all. mktime() normalises the struct tm that you pass it, including setting tm_isdst to a nonnegative value if it was passed in set to -1. So all you need is:

struct tm tm = { 0 };
// convert the time string to a broken down structure in localtime
if(strptime("2009-4-9", "%Y-%m-%d", &tm)) {
    tm.tm_isdst = -1;
    // normalise the broken down structure - this calculates tm_isdst
    mktime(&tm);

    printf("DST : %d\n", tm.tm_isdst);
}

This behaviour of mktime() is required by the C standard; for example, C99 says:

The mktime function converts the broken-down time, expressed as local time, in the structure pointed to by timeptr into a calendar time value with the same encoding as that of the values returned by the time function. The original values of the tm_wday and tm_yday components of the structure are ignored, and the original values of the other components are not restricted to the ranges indicated above.276 On successful completion, the values of the tm_wday and tm_yday components of the structure are set appropriately, and the other components are set to represent the specified calendar time, but with their values forced to the ranges indicated above; the final value of tm_mday is not set until tm_mon and tm_year are determined.

with footnote 276 explicitly addressing the tm_isdst member:

276) Thus, a positive or zero value for tm_isdst causes the mktime function to presume initially that Daylight Saving Time, respectively, is or is not in effect for the specified time. A negative value causes it to attempt to determine whether Daylight Saving Time is in effect for the specified time.

Upvotes: 4

Missaka Wijekoon
Missaka Wijekoon

Reputation: 891

I have done many time conversions before in C and I think you pretty much have it the way I would have done it too. As far as I know, localtime_r and its relatives may be your only option (unless there is some third party date library.) Of course, Greg Hewgill is correct for the "gray hour" between time switches.

Upvotes: 1

Greg Hewgill
Greg Hewgill

Reputation: 993243

The conversion from UTC to local time is not a reversible function. For example, in the autumn when the clocks jump back an hour, the local times between 02:00 and 03:00 occur twice. Given a time in this interval, it's not possible to determine whether the local time happened at a specific UTC time in local daylight time, or one hour later in local standard time.

Upvotes: 3

Related Questions