2

Let's say my Windows server application runs in an Eastern Time zone (NY).

I convert and store every datetime event (the moment they happen) in UTC, so that any client app that connects to the server reads the event's UTC time and converts and displays it in client's own TZ.

But here's the tricky part, some events report their timestamp in another state's time and doesn't explicitly specify daylight saving info (e.g. xx:xx:xx AM PT, meaning Pacific Time but I don't know if its currently in daylight saving time).

The server could check if it's in daylight saving period but that would be for server's own TZ (which is Eastern Time). The best I could come up with is to read the server's local daylight saving info and use that for PT as well but I know that's not 100% accurate. Especially thru the short window when ET has just started (or stopped) using daylight saving and PT has still hours to do so.

Now my question is, is there a way (in Windows API) to accurately find out about another time-zone's daylight saving status no matter which time zone the server app resides?

Edit: ok, how do I convert this to UTC "Sun, Mar 13, 2016 1:15 AM PT", from a Windows machine that runs in Eastern Time? (note that this date/time particularly selected when the running machine (in ET) is in DST at the moment and date/time to be converted is not just yet in DST. I have the UTC conversion covered but couldn't figure out if the given date/time is in DST or not.

Brian Hawk
  • 728
  • 2
  • 12
  • 24
  • Does [this previous question](http://stackoverflow.com/questions/2532729/daylight-saving-time-and-time-zone-best-practices) help? – Weather Vane Apr 15 '16 at 17:07
  • How do you identify the time zone in your application? If abbreviations like `PT` are all you have, you may find tho very difficult or impossible. Are those inputs limited to some set of fixed values? Or could they literally be anything? – Matt Johnson-Pint Apr 16 '16 at 17:33
  • @MattJohnson they're usually HTTP standard date/time strings (which actually contain DST info, like xx:xx:xx AM PST or PDT if DST is active) but some servers are not so generous to provide the DST info and just say that it's PT (Pasific Time) and leaving you to figure out if PT is in DST or not at the date/time given. The system (Windows) should know this as it adjusts the system clock on 2nd, and 1st Sunday of March and November, and could provide this to user with an API. – Brian Hawk Apr 19 '16 at 04:37
  • What makes things worse is that daylight savings start and end date/times varies from country to country (heck, even some states in US observe it differently, Hawaii and Arizona have no daylight savings). So it would be an awful lot of work for applications to figure out if a given date/time is in DST or not but it would be very easy for the underlying OS to provide this info to the apps because they already have built-in database for every country and time-zone. – Brian Hawk Apr 19 '16 at 04:44
  • Yes, I know all about time zones. check my profile. ;). What I'm asking is, for *your* app, is there a consistent form of input? Are you specifically working with RFC822/2822 style input strings and the limited set of time zone abbreviations it allows? Or is this arbitrary random input? Note that `PST` and `PDT` are part of that spec (used in http headers), but `PT` is not. Please be precise. Thanks. – Matt Johnson-Pint Apr 19 '16 at 06:58
  • Asked another way, are you just looking for info about the APIs available for converting time between time zones? If so, it would help to also know if you're looking for a Windows solution or a Linux/Mac solution, or cross platform, etc. And also, did you search already? What did you find? What didn't work? There are lots of posts on this subject already. – Matt Johnson-Pint Apr 19 '16 at 07:04
  • Matt, my input strings used to be RFC compliant, until recently. Amazon.com for instance started using PT instead of PST/PDT a while back. I need a solution for Windows only. I searched hours (not days) and found out it's not quite possible to do this on Windows without having to write your own code that has some sort of time-zone database of its own (which needs to be updated regularly from country to country if not state to state) – Brian Hawk Apr 27 '16 at 23:50
  • Looks like this is something Windows API is lacking (whereas Linux/Mac has a solution) even though it keeps a record of every country and every state's time-zone start and end dates. And it is also regularly updated thru Windows update if and when the local laws decide to change the rules of their time-zones. By the way Matt, that's one hell of a cool profile ;-) – Brian Hawk Apr 27 '16 at 23:55

2 Answers2

2

Windows' Time Zone data is actually stored in the Registry:

HKLM
  SOFTWARE
    Microsoft
      Windows NT
        CurrentVersion
          Time Zones

"Time Zones" is, in fact, two words.

Each Time Zone has its own subkey, and each subkey has a TZI value that is a binary REG_TZI_FORMAT structure:

typedef struct _REG_TZI_FORMAT
{
    LONG Bias;
    LONG StandardBias;
    LONG DaylightBias;
    SYSTEMTIME StandardDate;
    SYSTEMTIME DaylightDate;
} REG_TZI_FORMAT;

The two relevant structure members are StandardDate and DaylightDate.

Refer to MSDN for more details: TIME_ZONE_INFORMATION

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
scooter me fecit
  • 1,053
  • 5
  • 15
  • @Remy: I added the link to avoid duplicating Microsoft's code, which, is both likely copyrighted and doesn't have clearly marked "fair use" guidelines. – scooter me fecit Apr 15 '16 at 17:40
  • this has nothing to do with my question. The registry is just the place where Windows keeps time-zone information to display to the users so that they can set their computers' time zones. What I needed was to find out if another state (or country for that matter) is currently in DST or not. – Brian Hawk Apr 16 '16 at 04:19
  • It gives you the information you need to figure that out. The members of `DaylightDate`'s `SYSTEMTIME` have what you need. – scooter me fecit Apr 16 '16 at 05:10
  • here's what my Windows' TZI for Pasific Time `LONG Bias = 480 (minutes, which is correct) LONG StandardBias = 0 LONG DaylightBias = -60 SYSTEMTIME StandardDate = { WORD wYear = 0 WORD wMonth = 11 WORD wDayOfWeek = 0 WORD wDay = 1 WORD wHour = 2 WORD wMinute = 0 WORD wSecond = 0 WORD wMilliseconds = 0 } SYSTEMTIME DaylightDate = { WORD wYear = 0 WORD wMonth = 3 WORD wDayOfWeek = 0 WORD wDay = 2 WORD wHour = 2 WORD wMinute = 0 WORD wSecond = 0 WORD wMilliseconds = 0 }` – Brian Hawk Apr 16 '16 at 05:27
  • As you can see, the `StandardDate` and `DaylightDate` structure members don't reflect the correct DST start and end dates – Brian Hawk Apr 16 '16 at 05:33
  • @BrianHawk: Doing more research. – scooter me fecit Apr 20 '16 at 16:14
1

I'm not sure about the Windows API, but in general what you want to do is call mktime, with the TZ value of your remote time in effect. Under Unix you can literally call setenv("TZ", whatever) to do this. Not sure about Windows, but I think you can do the same sort of thing there, too.

It'd surely be nice if, besides mktime and timegm, there was a variant that let you specify the zone to use explicitly (rather than treating the TZ environment variable as a global variable), but such a variant is not standard.

When converting local times when you don't know whether DST is in effect or not, remember to set tm_isdst to -1 so that the library will figure it out for you.

Here's an example:

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

int main()
{
    struct tm tm = {0};
    time_t t;
    tm.tm_hour = 12; tm.tm_min = 30, tm.tm_sec = 15;            /* 12:30:15 */
    tm.tm_year = 2005-1900; tm.tm_mon = 4-1; tm.tm_mday = 12;   /* 2005-04-12 */
    tm.tm_isdst = -1;
    setenv("TZ", "America/Los_Angeles", 1);
    t = mktime(&tm);
    setenv("TZ", "America/New_York", 1);
    printf("%ld = %.24s\n", t, ctime(&t));
}

This tells you that the Los Angeles time 12:30:15 corresponds to the Unix (UTC) time 1113334215 and to the New York time 15:30:15.


Addendum: this won't help for Windows, either, but if you don't like setting an environment variable from inside your program every time you need to work with a time in a different time zone, see if you can use the BSD functions tzalloc, localtime_rz, and mktime_z.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • Minor point: best to completely fill `struct tm`, like `struct tm tm = {0};` before calling `mktime()`. That function uses all fields except `tm_wday, tm_yday` and `struct tm` may have more than the usually 9 fields. – chux - Reinstate Monica Apr 15 '16 at 18:30
  • Did you actually run this code on Windows? In my experience, Windows doesn't pay attention to the TZ environment variable. That's a POSIX thing. For previous treatment of this topic, see [How can a Windows program temporarily change its time zone?](http://stackoverflow.com/q/2611017/33732) – Rob Kennedy Apr 16 '16 at 00:23
  • @RobKennedy No, I tested it on MacOS. I had an idea that this or something like it was possible on Windows, but I could be wrong. – Steve Summit Apr 16 '16 at 02:56
  • @SteveSummit thanks for your work and answer but unfortunately it doesn't work for Windows. (Also, wouldn't setting a global env variable in the system affect other programs too?, or that change is only local to the current program?) – Brian Hawk Apr 16 '16 at 04:25
  • Environment variables are local to the process, at least in Unix/Linux. – Steve Summit Apr 16 '16 at 11:51