On Windows, soap_timegm() (stdsoap2.cpp (sourceforge.net)) (used when HAVE_TIMEGM is not defined) fails to
convert UTC timestamps near the Unix epoch if the process local timezone has
a positive UTC offset (e.g. UTC+3). Parsing the valid xsd:dateTime value
"1970-01-01T00:00:00Z" / "1970-01-01T00:00:00.000000Z" yields (time_t)-1
instead of 0.
This affects both soap_s2dateTime() (time_t) and the custom timeval
serializer (struct_timeval / soap_s2xsd__dateTime), which call soap_timegm().
Same string on Linux with HAVE_TIMEGM / timegm() correctly yields 0.
Windows path of soap_timegm() emulates timegm() as:
t = mktime(T); // treats T as LOCAL time
if (t == (time_t)-1)
return (time_t)-1; // fails before TZ correction
...
return t - (g - t); // intended UTC correction
For T = 1970-01-01 00:00:00, mktime() interprets the fields as local time.
In UTC+3 that corresponds to 1969-12-31 21:00:00 UTC, which is before the
Unix epoch; the CRT returns (time_t)-1. soap_timegm() propagates that error
sentinel even though the input was explicitly UTC ('Z').
Note: the 'Z' / timezone branch in the dateTime parser is correct — it does
call soap_timegm(). The bug is inside the Windows fallback of soap_timegm().
Callers that convert the resulting timeval/time_t to milliseconds
(seconds * 1000) and store it in an unsigned 64-bit timestamp get
18446744073709550616 (bit pattern of -1000), which then breaks date
libraries (e.g. boost::gregorian::bad_year) when formatting absolute times.
On Win32/MSVC use the CRT UTC inverse of gmtime:
#elif defined(_WIN32)
return _mkgmtime(T);
_mkgmtime / _mkgmtime64 is documented by Microsoft as converting UTC
struct tm to time_t (POSIX timegm equivalent):
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/mkgmtime-mkgmtime32-mkgmtime64
Minimal change to soap_timegm():
#if defined(HAVE_TIMEGM)
return timegm(T);
#elif defined(_WIN32)
return _mkgmtime(T);
#else
/* existing mktime/gmtime fallback */
#endif
After this change, 1970-01-01T00:00:00Z must deserialize to 0 on Windows
regardless of the local timezone.