1

This one has been stumping me for a good minute now. I am working on a program that is written in C++ that I need to be able to send times encoded in ISO8601 between two different servers. The major stickler here seems to be Windows.

Thus far, I have ported over strptime() from NetBSD in order to easily read a date/time string off the wire and turn it into a tm*. However, I am totally stumped when it comes to correctly turning it into a localized tm* so I can then display this time to the user in their local timezone using strftime(). A naive approach would be to simply take the difference between localtime(time(0)) and gmtime(time(0)), but this wouldn't be consistent for an arbitrary date where daylight savings time is involved.

The approach I've been taking so far is to use only POSIX date and time functions and to write Windows shims when necessary (done for strptime() so far, and timegm() perhaps in the future if necessary). I would prefer to keep doing that, but the simple fact is that the tm* struct in Windows is missing some fields that Linux and OSX do, so I might not have a choice but to write non-portable code that is guarded by #if WIN32. I also would really prefer not to have to pull in boost for this.

AlexMax
  • 1,204
  • 14
  • 36

1 Answers1

1

Given a struct tm *utc_tm you can turn it into a time_t utc using (nonportable) timegm, then turn that into a struct tm *local_tm using localtime:

time_t utc = timegm(utc_tm);
struct tm local_tm;
localtime_r(&utc, &local_tm);

From what I can tell, the simplest implementations of timegm involve doing the conversion yourself using a month table and leap year calculation. Alternatively, if your strptime fills in tm_yday correctly you can use the formula from https://stackoverflow.com/a/9076848/567292:

tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
    (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
    ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
Community
  • 1
  • 1
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • Your answer confused me at first because this is an approach I had discarded; I was under the mistaken impression that time_t's were shifted by timezone on Windows. A closer look at MSDN, however, confirmed the correctness of your approach. Thanks! – AlexMax Sep 21 '12 at 17:05