Piotr Caban : msvcrt: Fixed mktime and _mktime64 implementation.

Alexandre Julliard julliard at winehq.org
Mon Dec 10 14:00:39 CST 2012


Module: wine
Branch: master
Commit: a66ed048a32fd1cd4e8afebd262b7b1b1eabfbcd
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=a66ed048a32fd1cd4e8afebd262b7b1b1eabfbcd

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Mon Dec 10 12:47:13 2012 +0100

msvcrt: Fixed mktime and _mktime64 implementation.

---

 dlls/msvcrt/time.c |  165 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 142 insertions(+), 23 deletions(-)

diff --git a/dlls/msvcrt/time.c b/dlls/msvcrt/time.c
index 27f93b1..e484bf4 100644
--- a/dlls/msvcrt/time.c
+++ b/dlls/msvcrt/time.c
@@ -52,20 +52,6 @@ static inline int IsLeapYear(int Year)
     return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0);
 }
 
-static inline void msvcrt_tm_to_unix( struct tm *dest, const struct MSVCRT_tm *src )
-{
-    memset( dest, 0, sizeof(*dest) );
-    dest->tm_sec   = src->tm_sec;
-    dest->tm_min   = src->tm_min;
-    dest->tm_hour  = src->tm_hour;
-    dest->tm_mday  = src->tm_mday;
-    dest->tm_mon   = src->tm_mon;
-    dest->tm_year  = src->tm_year;
-    dest->tm_wday  = src->tm_wday;
-    dest->tm_yday  = src->tm_yday;
-    dest->tm_isdst = src->tm_isdst;
-}
-
 static inline void unix_tm_to_msvcrt( struct MSVCRT_tm *dest, const struct tm *src )
 {
     memset( dest, 0, sizeof(*dest) );
@@ -177,6 +163,57 @@ void CDECL MSVCRT__tzset(void)
     _munlock(_TIME_LOCK);
 }
 
+static void _tzset_init(void)
+{
+    static BOOL init = FALSE;
+
+    if(!init) {
+        _mlock(_TIME_LOCK);
+        if(!init) {
+            MSVCRT__tzset();
+            init = TRUE;
+        }
+        _munlock(_TIME_LOCK);
+    }
+}
+
+static BOOL is_dst(const SYSTEMTIME *st)
+{
+    TIME_ZONE_INFORMATION tmp;
+    SYSTEMTIME out;
+
+    if(!MSVCRT___daylight)
+        return FALSE;
+
+    if(tzi.DaylightDate.wMonth) {
+        tmp = tzi;
+    }else if(st->wYear >= 2007) {
+        memset(&tmp, 0, sizeof(tmp));
+        tmp.StandardDate.wMonth = 11;
+        tmp.StandardDate.wDay = 1;
+        tmp.StandardDate.wHour = 2;
+        tmp.DaylightDate.wMonth = 3;
+        tmp.DaylightDate.wDay = 2;
+        tmp.DaylightDate.wHour = 2;
+    }else {
+        memset(&tmp, 0, sizeof(tmp));
+        tmp.StandardDate.wMonth = 10;
+        tmp.StandardDate.wDay = 5;
+        tmp.StandardDate.wHour = 2;
+        tmp.DaylightDate.wMonth = 4;
+        tmp.DaylightDate.wDay = 1;
+        tmp.DaylightDate.wHour = 2;
+    }
+
+    tmp.Bias = 0;
+    tmp.StandardBias = 0;
+    tmp.DaylightBias = MSVCRT__dstbias/60;
+    if(!SystemTimeToTzSpecificLocalTime(&tmp, st, &out))
+        return FALSE;
+
+    return memcmp(st, &out, sizeof(SYSTEMTIME));
+}
+
 #define SECSPERDAY        86400
 /* 1601 to 1970 is 369 years plus 89 leap days */
 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
@@ -184,19 +221,100 @@ void CDECL MSVCRT__tzset(void)
 #define TICKSPERMSEC      10000
 #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
 
+static MSVCRT___time64_t mktime_helper(struct MSVCRT_tm *mstm, BOOL local)
+{
+    SYSTEMTIME st;
+    FILETIME ft;
+    MSVCRT___time64_t ret = 0;
+    int i;
+    BOOL use_dst = FALSE;
+
+    ret = mstm->tm_year + mstm->tm_mon/12;
+    mstm->tm_mon %= 12;
+    if(mstm->tm_mon < 0) {
+        mstm->tm_mon += 12;
+        ret--;
+    }
+
+    if(ret<70 || ret>1100) {
+        *MSVCRT__errno() = MSVCRT_EINVAL;
+        return -1;
+    }
+
+    memset(&st, 0, sizeof(SYSTEMTIME));
+    st.wDay = 1;
+    st.wMonth = mstm->tm_mon+1;
+    st.wYear = ret+1900;
+
+    if(!SystemTimeToFileTime(&st, &ft)) {
+        *MSVCRT__errno() = MSVCRT_EINVAL;
+        return -1;
+    }
+
+    ret = ((MSVCRT___time64_t)ft.dwHighDateTime<<32)+ft.dwLowDateTime;
+    ret += (MSVCRT___time64_t)mstm->tm_sec*TICKSPERSEC;
+    ret += (MSVCRT___time64_t)mstm->tm_min*60*TICKSPERSEC;
+    ret += (MSVCRT___time64_t)mstm->tm_hour*60*60*TICKSPERSEC;
+    ret += (MSVCRT___time64_t)(mstm->tm_mday-1)*SECSPERDAY*TICKSPERSEC;
+
+    ft.dwLowDateTime = ret & 0xffffffff;
+    ft.dwHighDateTime = ret >> 32;
+    FileTimeToSystemTime(&ft, &st);
+
+    if(local) {
+        _tzset_init();
+        use_dst = is_dst(&st);
+        if((mstm->tm_isdst<=-1 && use_dst) || (mstm->tm_isdst>=1)) {
+            SYSTEMTIME tmp;
+
+            ret += (MSVCRT___time64_t)MSVCRT__dstbias*TICKSPERSEC;
+
+            ft.dwLowDateTime = ret & 0xffffffff;
+            ft.dwHighDateTime = ret >> 32;
+            FileTimeToSystemTime(&ft, &tmp);
+
+            if(!is_dst(&tmp)) {
+                st = tmp;
+                use_dst = FALSE;
+            }else {
+                use_dst = TRUE;
+            }
+        }else if(mstm->tm_isdst==0 && use_dst) {
+            ret -= (MSVCRT___time64_t)MSVCRT__dstbias*TICKSPERSEC;
+            ft.dwLowDateTime = ret & 0xffffffff;
+            ft.dwHighDateTime = ret >> 32;
+            FileTimeToSystemTime(&ft, &st);
+            ret += (MSVCRT___time64_t)MSVCRT__dstbias*TICKSPERSEC;
+        }
+        ret += (MSVCRT___time64_t)MSVCRT___timezone*TICKSPERSEC;
+    }
+
+    mstm->tm_sec = st.wSecond;
+    mstm->tm_min = st.wMinute;
+    mstm->tm_hour = st.wHour;
+    mstm->tm_mday = st.wDay;
+    mstm->tm_mon = st.wMonth-1;
+    mstm->tm_year = st.wYear-1900;
+    mstm->tm_wday = st.wDayOfWeek;
+    for(i=mstm->tm_yday=0; i<st.wMonth-1; i++)
+        mstm->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i];
+    mstm->tm_yday += st.wDay-1;
+    mstm->tm_isdst = use_dst ? 1 : 0;
+
+    if(ret < TICKS_1601_TO_1970) {
+        *MSVCRT__errno() = MSVCRT_EINVAL;
+        return -1;
+    }
+    ret = (ret-TICKS_1601_TO_1970)/TICKSPERSEC;
+    return ret;
+}
+
 /**********************************************************************
  *		_mktime64 (MSVCRT.@)
  */
 MSVCRT___time64_t CDECL MSVCRT__mktime64(struct MSVCRT_tm *mstm)
 {
-    time_t secs;
-    struct tm tm;
-
-    msvcrt_tm_to_unix( &tm, mstm );
-    secs = mktime( &tm );
-    unix_tm_to_msvcrt( mstm, &tm );
-
-    return secs < 0 ? -1 : secs;
+    return mktime_helper(mstm, TRUE);
 }
 
 /**********************************************************************
@@ -204,7 +322,8 @@ MSVCRT___time64_t CDECL MSVCRT__mktime64(struct MSVCRT_tm *mstm)
  */
 MSVCRT___time32_t CDECL MSVCRT__mktime32(struct MSVCRT_tm *mstm)
 {
-    return MSVCRT__mktime64( mstm );
+    MSVCRT___time64_t ret = MSVCRT__mktime64( mstm );
+    return ret == (MSVCRT___time32_t)ret ? ret : -1;
 }
 
 /**********************************************************************




More information about the wine-cvs mailing list