Fix daylight saving time computations by converting from broken libc
authorStefan Vogel <sv@exept.de>
Mon, 29 Mar 2010 20:03:08 +0200
changeset 12817 33771eb7d88b
parent 12816 ff4a03e2da97
child 12818 b75404445906
Fix daylight saving time computations by converting from broken libc to windows primitives
Win32OperatingSystem.st
--- a/Win32OperatingSystem.st	Mon Mar 29 19:54:04 2010 +0200
+++ b/Win32OperatingSystem.st	Mon Mar 29 20:03:08 2010 +0200
@@ -480,48 +480,48 @@
     tv.tv_usec = 0;
 
     if (readMode) {
-	n = select (sock + 1, & fds, NULL, NULL, & tv);
+        n = select (sock + 1, & fds, NULL, NULL, & tv);
     } else {
-	n = select (sock + 1, NULL, & fds, NULL, & tv);
+        n = select (sock + 1, NULL, & fds, NULL, & tv);
     }
 
     if (n == 0) {
-	return (0);
+        return (0);
     }
 
     if (n > 0) {
-	return ((FD_ISSET (sock, & fds)) ? 1 : 0);
+        return ((FD_ISSET (sock, & fds)) ? 1 : 0);
     }
 
     winErrNo = WSAGetLastError();
     switch (winErrNo) {
-	case WSAENOTSOCK:
-	    if (readMode) {
-
-		DWORD  w = 0;
-		HANDLE h = (HANDLE) _get_osfhandle (aFD);
-
-		if (PeekNamedPipe (h, 0, 0, 0, & w, 0)) {
-		    if( !__isWinNT || w > 0 )
-			return (1);
-
-		    return (0);
-		}
+        case WSAENOTSOCK:
+            if (readMode) {
+
+                DWORD  w = 0;
+                HANDLE h = (HANDLE) _get_osfhandle (aFD);
+
+                if (PeekNamedPipe (h, 0, 0, 0, & w, 0)) {
+                    if( !__isWinNT || w > 0 )
+                        return (1);
+
+                    return (0);
+                }
 #if 0
-		console_fprintf(stderr, "_canAccessIOWithoutBlocking non Socket\n");
-#endif
-		return (-1);
-	    }
-	    /* in writeMode we return allways true for none-sockets */
-	    return (1);
-
-	case WSAEINPROGRESS:
-	case WSAEWOULDBLOCK:
-	    return (0);
-
-	default:
-	    console_fprintf(stderr, "_canAccessIOWithoutBlocking -> %d (0x%x)\n", winErrNo, winErrNo);
-	    return (-1);
+                console_fprintf(stderr, "_canAccessIOWithoutBlocking non Socket\n");
+#endif
+                return (-1);
+            }
+            /* in writeMode we return allways true for none-sockets */
+            return (1);
+
+        case WSAEINPROGRESS:
+        case WSAEWOULDBLOCK:
+            return (0);
+
+        default:
+            console_fprintf(stderr, "_canAccessIOWithoutBlocking -> %d (0x%x)\n", winErrNo, winErrNo);
+            return (-1);
     }
 
     /* not reached */
@@ -543,7 +543,7 @@
     FARPROC entry;
 
     if (*pLibHandle == NULL) {
-	*pLibHandle = LoadLibrary(libraryName);
+        *pLibHandle = LoadLibrary(libraryName);
     }
     entry = GetProcAddress(*pLibHandle, functionName);
     return entry;
@@ -575,6 +575,14 @@
     return __get_functionAddress(&libHandle, "ole32.DLL", functionName);
 }
 
+void TimetToFileTime( time_t t, LPFILETIME pft )
+{
+    LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
+    pft->dwLowDateTime = (DWORD) ll;
+    pft->dwHighDateTime = ll >>32;
+}
+
+
 %}
 ! !
 
@@ -8388,7 +8396,6 @@
     if (P_RtlGenRandom == 0) {
         HINSTANCE hAdvapi32 = LoadLibrary("advapi32.dll");
         // console_printf("hAdvapi32: %x\n", hAdvapi32);
-        console_printf("hAdvapi32: %x\n", hAdvapi32);
         if (hAdvapi32) {
             P_RtlGenRandom = (BOOL (__stdcall *)(PVOID , ULONG))
                                 GetProcAddress(hAdvapi32, "SystemFunction036");
@@ -9734,53 +9741,6 @@
 
 !Win32OperatingSystem class methodsFor:'time and date'!
 
-computeDatePartsOf:osTime for:aBlock
-    "compute year, month and day from the OS time, osTime
-     and evaluate the argument, a 3-arg block with these.
-     Conversion is to localtime including any daylight saving adjustments."
-
-    |year month day osSeconds|
-
-    osSeconds := osTime // 1000.
-%{
-    struct tm* tmPtr;
-    struct tm tmValue;
-    INT t;
-    time_t tt;
-
-    t = __longIntVal(osSeconds);
-    tt = (time_t)t;
-
-#ifdef __BORLANDC__
-    tmPtr = localtime(&tt);
-#else
-    /* be thread safe */
-    if (localtime_s(&tmValue, &tt) == 0)
-	tmPtr = &tmValue;
-    else
-	tmPtr = NULL;
-#endif
-
-    if (tmPtr != NULL) {
-	year = __mkSmallInteger(tmPtr->tm_year + 1900);
-	month = __mkSmallInteger(tmPtr->tm_mon + 1);
-	day = __mkSmallInteger(tmPtr->tm_mday);
-    }
-%}.
-    year isNil ifTrue:[
-	self primitiveFailed
-    ].
-    aBlock value:year value:month value:day
-
-    "
-     OperatingSystem computeDatePartsOf:0 for:[:y :m :d |
-	y printCR. m printCR. d printCR
-     ]
-    "
-
-    "Modified: / 06-07-2006 / 18:18:04 / cg"
-!
-
 computeOSTimeFromUTCYear:y month:m day:d hour:h minute:min second:s millisecond:millis
     "return the OS-dependent time for the given time and day.
      The arguments are assumed to be in UTC time."
@@ -9793,36 +9753,25 @@
     if (__bothSmallInteger(y, m)
      && __bothSmallInteger(d, h)
      && __bothSmallInteger(min, s)) {
-	time_t t;
-	TIME_ZONE_INFORMATION tzInfo;
-	int gmtoffMinutes;
-
-	if (GetTimeZoneInformation(&tzInfo) < 0) goto error;
-
-	tm.tm_hour = __intVal(h);
-	tm.tm_min = __intVal(min);
-	tm.tm_sec = __intVal(s);
-
-	tm.tm_year = __intVal(y) - 1900;
-	tm.tm_mon = __intVal(m) - 1;
-	tm.tm_mday = __intVal(d);
-	tm.tm_isdst = -1;
-
-	t = mktime(&tm);
-
-	gmtoffMinutes = tzInfo.Bias;
-	if (tm.tm_isdst) {
-	    gmtoffMinutes += tzInfo.DaylightBias;
-	} else {
-	    gmtoffMinutes += tzInfo.StandardBias;
-	}
-	t = t - gmtoffMinutes*60;
-	osSeconds = __MKUINT((INT)t);
+        time_t t;
+
+        tm.tm_hour = __intVal(h);
+        tm.tm_min = __intVal(min);
+        tm.tm_sec = __intVal(s);
+
+        tm.tm_year = __intVal(y) - 1900;
+        tm.tm_mon = __intVal(m) - 1;
+        tm.tm_mday = __intVal(d);
+        tm.tm_isdst = 0;
+
+        t = mktime(&tm);
+
+        osSeconds = __MKUINT((INT)t);
     }
 error:;
 %}.
     osSeconds notNil ifTrue:[
-	^ osSeconds * 1000 + millis
+        ^ osSeconds * 1000 + millis
     ].
     ^ self primitiveFailed
 
@@ -9869,127 +9818,6 @@
 
 !
 
-computeTimePartsOf:osTime for:aBlock
-    "compute hours, minutes, seconds and milliseconds from the osTime
-     and evaluate the argument, a 4-arg block with these.
-     Conversion is to localtime including any daylight saving adjustments."
-
-    |hours minutes seconds millis osSeconds|
-
-    osSeconds := osTime // 1000.
-    millis := osTime \\ 1000.
-%{
-    struct tm *tmPtr;
-    struct tm tmValue;
-    INT t;
-    time_t tt;
-
-    t = __longIntVal(osSeconds);
-    tt = (time_t)t;
-
-#ifdef __BORLANDC__
-    tmPtr = localtime(&tt);
-#else
-    /* be thread safe */
-    if (localtime_s(&tmValue, &tt) == 0)
-	tmPtr = &tmValue;
-    else
-	tmPtr = NULL;
-#endif
-
-    if (tmPtr != NULL) {
-	hours = __mkSmallInteger(tmPtr->tm_hour);
-	minutes = __mkSmallInteger(tmPtr->tm_min);
-	seconds = __mkSmallInteger(tmPtr->tm_sec);
-    }
-%}.
-    hours isNil ifTrue:[
-	self primitiveFailed
-    ].
-    aBlock value:hours value:minutes value:seconds value:millis
-
-    "
-     OperatingSystem computeTimePartsOf:100 for:[:h :m :s :milli |
-	h printCR. m printCR. s printCR. millis printCR
-     ]
-    "
-
-    "Modified: / 06-07-2006 / 18:18:39 / cg"
-!
-
-computeUTCTimeAndDateFrom:osTime
-    "given an OS-dependent time in osTime, return an Array
-     containing year, month, day, hour, minute and seconds,
-     offset to UTC, daylight savings time flag, milliseconds,
-     dayInYear (1..) and dayInWeek (1..).
-     Conversion is to UTC."
-
-    |year month day hours minutes seconds millis utcOffset
-     dst yDay wDay osSeconds ret|
-
-    millis := osTime \\ 1000.
-    osSeconds := osTime // 1000.
-%{
-    struct tm *tmPtr;
-    struct tm *gmTmPtr;
-    long t;
-
-    t = __longIntVal(osSeconds);
-
-    tmPtr = gmtime(&t);
-    hours = __mkSmallInteger(tmPtr->tm_hour);
-    minutes = __mkSmallInteger(tmPtr->tm_min);
-    seconds = __mkSmallInteger(tmPtr->tm_sec);
-
-    year = __mkSmallInteger(tmPtr->tm_year + 1900);
-    month = __mkSmallInteger(tmPtr->tm_mon + 1);
-    day = __mkSmallInteger(tmPtr->tm_mday);
-
-    yDay = __mkSmallInteger(tmPtr->tm_yday + 1);
-    wDay = __mkSmallInteger(tmPtr->tm_wday == 0 ? 7 : tmPtr->tm_wday);
-    dst = (tmPtr->tm_isdst == 0) ? false : true;
-
-#ifdef WINDOWS_IS_POSIX_CONFORM_WHICH_IT_IS_NOT
-    utcOffset = __MKINT(tmPtr->tm_gmtoff);
-#else
-    {
-	TIME_ZONE_INFORMATION tzInfo;
-	int gmtoffMinutes = 0;
-
-	if (GetTimeZoneInformation(&tzInfo) < 0) goto error;
-	gmtoffMinutes = tzInfo.Bias;
-	if (tmPtr->tm_isdst) {
-	    gmtoffMinutes += tzInfo.DaylightBias;
-	} else {
-	    gmtoffMinutes += tzInfo.StandardBias;
-	}
-
-	utcOffset = __MKINT(gmtoffMinutes*60);
-    }
-#endif
-error:;
-%}.
-    "I would love to have SELF-like inline objects ..."
-    ret := Array new:11.
-    ret at:1 put:year.
-    ret at:2 put:month.
-    ret at:3 put:day.
-    ret at:4 put:hours.
-    ret at:5 put:minutes.
-    ret at:6 put:seconds.
-    ret at:7 put:utcOffset.
-    ret at:8 put:dst.
-    ret at:9 put:millis.
-    ret at:10 put:yDay.
-    ret at:11 put:wDay.
-    ^ ret
-
-    "
-     OperatingSystem computeUTCTimeAndDateFrom:0
-     OperatingSystem computeUTCTimeAndDateFrom:self getOSTime
-    "
-!
-
 getMicrosecondTime
     "This returns a microsecond timer value.
      The returned value is a 64bit value
@@ -10066,65 +9894,27 @@
 
      Dont use this method in application code since it is an internal (private)
      interface. For compatibility with ST-80, use Time>>millisecondClockValue.
-     or use instances of Time, Date or Timestamp to work with.
-    "
+     or use instances of Time, Date or Timestamp to work with."
 
     |seconds millis|
 
 %{
-
-    long t;
-
-#if !defined(HAS_GETTIMEOFDAY)
-# if defined(HAS_FTIME)
-    struct timeb timebuffer;
-
-    ftime(&timebuffer);
-    seconds = __MKUINT(timebuffer.time);
-    millis = __MKUINT(timebuffer.millitm);
-#   define HAVE_TIME
-# endif
-
-# ifndef HAVE_TIME
-#  ifdef MSDOS_LIKE
-#   ifdef __BORLANDC__
-    struct timeb timebuffer;
-    ftime(&timebuffer);
-#   else
-    struct _timeb timebuffer;
-    _ftime(&timebuffer);
-#   endif
-    seconds = __MKUINT(timebuffer.time);
-    millis = __MKUINT(timebuffer.millitm);
-#   define HAVE_TIME
-#  endif
-# endif
-#endif
-
-#ifndef HAVE_TIME
-    /* assume HAS_GETTIMEOFDAY
-     * - will result in a linkage error
-     * if not fixed.
-     */
-    /*
-     * bsd time
-     */
-    struct timeval tb;
-    struct timezone tzb;
-
-    gettimeofday(&tb, &tzb);
-
-    seconds = __MKUINT(tb.tv_sec);
-    millis = __MKUINT(tb.tv_usec / 1000);
-#endif
-
-#undef HAVE_TIME
-
+    FILETIME fileTime;
+    LONGLONG nsTime100;             /* number 100ns since 160x */
+    LONGLONG millisSince1970;
+
+    GetSystemTimeAsFileTime(&fileTime);
+    nsTime100 = ((LONGLONG)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
+    millisSince1970 = (nsTime100 / 10000) - 11644473600000;
+
+    /* do large integer arithmethic in smalltalk */
+    seconds = __MKUINT((unsigned INT)(millisSince1970 / 1000));
+    millis  = __mkSmallInteger((unsigned INT)(millisSince1970 % 1000));
 %}.
     ^ (seconds * 1000) + millis
 
     "
-     OperatingSystem getOSTime printCR.
+     OperatingSystem getOSTime.
      Delay waitForSeconds:0.2.
      OperatingSystem getOSTime printCR.
     "
@@ -10243,14 +10033,13 @@
      OS-second value.
      An internal helper"
 
-    |year month day hours minutes seconds utcOffset
-     dst yDay wDay info reason|
-
-%{
-    struct tm *tmPtr;
-    struct tm tmValue;
+    |year month day hours minutes seconds utcOffset dstOffset
+     dst yDay weekDay info reason|
+
+%{
     UINT t;
-    time_t tt;
+    FILETIME fileTime, localFileTime;
+    SYSTEMTIME sysTime;
 
     t = __longIntVal(osSeconds);
 
@@ -10270,82 +10059,43 @@
             }
         }
     }
-    if (t == 0) {
-        reason = @symbol(invalidOSTime);
-        goto error;
-    }
-
-    tt = (time_t)t;
+
+    TimetToFileTime((time_t)t, &fileTime);
 
     if (isLocalTime == true) {
-#ifdef __BORLANDC__
-        tmPtr = localtime(&tt);
-#else
-        /* be thread safe */
-        if (localtime_s(&tmValue, &tt) == 0)
-            tmPtr = &tmValue;
-        else
-            tmPtr = NULL;
-#endif
-        if (tmPtr == NULL) {
-            reason = @symbol(localtimeConversionFailed);
+        TIME_ZONE_INFORMATION tzInfo;
+        int tzState;
+        LONGLONG longTime;
+
+        FileTimeToLocalFileTime(&fileTime, &localFileTime);
+        FileTimeToSystemTime(&localFileTime, &sysTime);
+
+        longTime = ((LONGLONG)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
+        longTime -= ((LONGLONG)localFileTime.dwHighDateTime << 32) + localFileTime.dwLowDateTime;
+        utcOffset = __mkSmallInteger((INT)(longTime / 10000000));
+
+        if ((tzState = GetTimeZoneInformation(&tzInfo)) < 0) {
+            reason = @symbol(getTimeZoneFailed);
             goto error;
         }
-
-#ifdef WINDOWS_IS_POSIX_CONFORM_WHICH_IT_IS_NOT
-        utcOffset = __MKINT(tmPtr->tm_gmtoff);
-#else
-        {
-            TIME_ZONE_INFORMATION tzInfo;
-            int tzState, gmtoffMinutes = 0;
-
-            if ((tzState = GetTimeZoneInformation(&tzInfo)) < 0) {
-                reason = @symbol(getTimeZoneFailed);
-                goto error;
-            }
-            gmtoffMinutes = tzInfo.Bias;
-            if (tzState == TIME_ZONE_ID_DAYLIGHT) {
-                gmtoffMinutes += tzInfo.DaylightBias;
-                tmPtr->tm_isdst = 1;
-            } else {
-                gmtoffMinutes += tzInfo.StandardBias;
-                tmPtr->tm_isdst = 0;
-            }
-            utcOffset = __MKINT(gmtoffMinutes*60);
-        }
-#endif
+        dstOffset = __mkSmallInteger((tzInfo.Bias + tzInfo.DaylightBias) * 60);
     } else {
-#ifdef __BORLANDC__
-        tmPtr = gmtime(&tt);
-#else
-        /* be thread safe */
-        if (gmtime_s(&tmValue, &tt) == 0)
-            tmPtr = &tmValue;
-        else
-            tmPtr = NULL;
-#endif
-        if (tmPtr == NULL) {
-            reason = @symbol(conversionToGMTimeFailed);
-            goto error;
-        }
-        utcOffset = __mkSmallInteger(0);
-    }
-
-    hours = __mkSmallInteger(tmPtr->tm_hour);
-    minutes = __mkSmallInteger(tmPtr->tm_min);
-    seconds = __mkSmallInteger(tmPtr->tm_sec);
-
-    year = __mkSmallInteger(tmPtr->tm_year + 1900);
-    month = __mkSmallInteger(tmPtr->tm_mon + 1);
-    day = __mkSmallInteger(tmPtr->tm_mday);
-
-    yDay = __mkSmallInteger(tmPtr->tm_yday+1);
-    wDay = __mkSmallInteger(tmPtr->tm_wday == 0 ? 7 : tmPtr->tm_wday);
-
-    dst = (tmPtr->tm_isdst == 0) ? false : true;
+        FileTimeToSystemTime(&fileTime, &sysTime);
+        utcOffset = dstOffset = __mkSmallInteger(0);
+    }
+
+    hours = __mkSmallInteger(sysTime.wHour);
+    minutes = __mkSmallInteger(sysTime.wMinute);
+    seconds = __mkSmallInteger(sysTime.wSecond);
+
+    year = __mkSmallInteger(sysTime.wYear);
+    month = __mkSmallInteger(sysTime.wMonth);
+    day = __mkSmallInteger(sysTime.wDay);
+
+    weekDay = __mkSmallInteger(sysTime.wDayOfWeek == 0 ? 7 : sysTime.wDayOfWeek);
 error:;
 %}.
-    dst isNil ifTrue:[
+    year isNil ifTrue:[
         ^ self primitiveFailed
     ].
 
@@ -10359,9 +10109,9 @@
         seconds:seconds
         milliseconds:osMilliseconds
         utcOffset:utcOffset
-        dst:dst
+        dst:(utcOffset = dstOffset)
         dayInYear:yDay
-        dayInWeek:wDay.
+        dayInWeek:weekDay.
 
     LastTimeInfo := info.
     LastTimeInfoSeconds := osSeconds.
@@ -10375,6 +10125,7 @@
      OperatingSystem timeInfoFromSeconds:0 milliseconds:0 localTime:false
      OperatingSystem timeInfoFromSeconds:3600 milliseconds:0 localTime:true
      OperatingSystem timeInfoFromSeconds:Timestamp now utcSecondsSince1970 milliseconds:0 localTime:true
+     OperatingSystem timeInfoFromSeconds:Timestamp now utcSecondsSince1970 milliseconds:0 localTime:false
     "
 
     "Modified: / 06-07-2006 / 18:18:56 / cg"
@@ -16499,11 +16250,11 @@
 !Win32OperatingSystem class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.392 2010-03-29 11:24:05 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.393 2010-03-29 18:03:08 stefan Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.392 2010-03-29 11:24:05 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.393 2010-03-29 18:03:08 stefan Exp $'
 ! !
 
 Win32OperatingSystem initialize!