Platform: Windows XP
libcurl: 7.14
With the system clock properly configured to
automatically adjust for Daylight Saving Time,
curl_getdate() appears to return a time_t value which
is 1 hour ahead of the correct value. This prevents
cookies from expiring at the proper time.
The following demonstrates the problem:
#include <stdio.h>
#include "curl/curl.h"
int main()
{
time_t tNow = ::time(NULL);
tm tmGMT;
char szGMT[128];
::strftime\( szGMT, 128, "%a, %d-%b-%Y %H:%M:%S GMT",
&tmGMT );
time\_t tCURL = ::curl\_getdate\(szGMT, NULL\); time\_t tDiff = tCURL - tNow; printf\("Current time: %s\n", szGMT\); printf\("Sytem time\_t: %i\n", tNow\); printf\("libcurl time\_t: %i\n", tCURL\); printf\("Difference: %i seconds\n", tCURL - tNow\); return 0;
}
-----------------------------------------------------------
Example run with properly configured system clock
(during DST):
Current time: Thu, 30-Jun-2005 03:02:14 GMT
Sytem time_t: 1120100534
libcurl time_t: 1120104134
Difference: 3600 seconds
-----------------------------------------------------------
Example run with automatic DST adjustment disabled:
Current time: Thu, 30-Jun-2005 03:02:28 GMT
Sytem time_t: 1120100548
libcurl time_t: 1120100548
Difference: 0 seconds
Logged In: YES
user_id=1110
I'm puzzled.
Why is "automatic DST adjustment" ? Isn't that the thing
that automatically changes to DST at one date and then at
another later date it again switches off DST?
If so, how on earth can that affect the date functions like
this?
libcurl is simply using mktime() and gmtime(). I don't see
how that can be wrong. To me, it looks like Windows or the c
library you're using, is doing it wrong.
Logged In: YES
user_id=1110
Can you check what mktime() returns for this setup with and
without auto-DST set?
I can't but suspect that this is yet another chapter in the
windows-DST-mess:
http://www.codeproject.com/datetime/dstbugs.asp
Logged In: YES
user_id=1110
I don't have/use windows myself. Without assistance I can't
solve this problem.
Logged In: YES
user_id=47168
Without an environment variable "TZ=GMT+1" I'm getting the
same result. With TZ set, there is no problem and difference
regarding system DST is set or not.
Logged In: YES
user_id=1110
Ok. Now we're getting somewhere!
Is there any (Windows-) way we can figure out what timezone
we're in and set the TZ variable before these time functions
are used, if we find out it isn't already set?
Thanks Gisle!
Logged In: YES
user_id=47168
Something like:
const char *env = getenv("TZ");
if (!env)
putenv("TZ=GMT");
before time() makes the difference 0.
AFAIK, $TZ is only used by libc (msvcrt.dll). The official info
is returned by GetTimeZoneInformation().
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/sysinfo/base/gettimezoneinformation.asp
We should be able to use that (bias) in case $TZ isn't defined.
Logged In: YES
user_id=1110
Great!
I've just committed this fix. Closing this, considered fixed.
Logged In: YES
user_id=866512
const char *env = getenv("TZ");
if(!env)
_putenv("TZ=GMT");
Note the underscore in _putenv. This version of putenv does
not leak memory (7 bytes "TZ=GMT\0") when libcurl used as a
static lib. Tested under MSVC 7.1
:)
Logged In: YES
user_id=86583
Originator: NO
I think this bug is still there.
I have made extensive tests with different date-strings and TZ environment variables. The following combinations return different results on linux and windows:
TZ=CEST (central european summer time).
Dates are "Wed, 02 Aug 2006 14:16:26 GMT"
"Wed, 02 Aug 2006 15:16:26 CET"
"Wed, 02 Aug 2006 16:16:26 CEST"
Linux returns the correct datetimes, windows is off by one hour.
Other TZ values I tested: UTC. MEZ, UTC+2 worked correctly. So it seems to be the TZ value with summer time (dst).
By tracing the internal values I was able to narrow down the problem to the gmtime call and the following call to mktime. The return value of mktime (t2) is off.
On a hunch, I then changed the code to hold a copy of the gmtime return value - that seems to fixed the problem:
#ifdef HAVE_GMTIME_R
/* thread-safe version */
struct tm keeptime2;
gmt = (struct tm *)gmtime_r(&t, &keeptime2);
if(!gmt)
return -1; /* illegal date/time */
t2 = mktime(gmt);
#else
struct tm gmt2;
gmt = gmtime(&t); /* use gmtime_r() if available */
if(!gmt)
return -1; /* illegal date/time */
gmt2 = *gmt; /* create local copy */
t2 = mktime(&gmt2);
#endif
/* Add the time zone diff (between the given timezone and GMT) and the
diff between the local time zone and GMT. */
delta = (long)((tzoff!=-1?tzoff:0) + (t - t2));
It looks like windows has a problem with the non-reentrant version of gmtime + mktime if TZ has a DST timezome.
BTW: defining HAVE_GMTIME_R for windows also fixes the problem. We can probably do this too.
And with this fix, the _putenv("TZ=GMT") hack is no longer necessary.
Cheers,
Martin
Logged In: YES
user_id=1110
Originator: NO
But since Windows doesn't provide the libc it really comes down to what the compiler vendors provide. Do really all windows compilers come with gmtime_r() support? If so it would certainly make sense to simply switch to using that...
Logged In: YES
user_id=86583
Originator: NO
MSVC 2003 has gmtime_r, don't know about other compilers/runtimes.
I think we should
a) fix the non-reentrant code path
b) set HAVE_GMTIME_R for MSVC 2003 and higher
#if _MSC_VER > 1310
#define GMTIME
#endif
Logged In: YES
user_id=1110
Originator: NO
Many thanks for your work on this. Fix has been committed. Closing this bug report (again)!