From a66ed048a32fd1cd4e8afebd262b7b1b1eabfbcd Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Mon, 10 Dec 2012 12:47:13 +0100 Subject: [PATCH] msvcrt: Fixed mktime and _mktime64 implementation. --- dlls/msvcrt/time.c | 165 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 142 insertions(+), 23 deletions(-) diff --git a/dlls/msvcrt/time.c b/dlls/msvcrt/time.c index 27f93b1da61..e484bf4e19a 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; itm_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; } /********************************************************************** -- 2.11.4.GIT