msvcrt: Fixed mktime and _mktime64 implementation.
This commit is contained in:
parent
59776ccc99
commit
a66ed048a3
@ -52,20 +52,6 @@ static inline int IsLeapYear(int Year)
|
|||||||
return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0);
|
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 )
|
static inline void unix_tm_to_msvcrt( struct MSVCRT_tm *dest, const struct tm *src )
|
||||||
{
|
{
|
||||||
memset( dest, 0, sizeof(*dest) );
|
memset( dest, 0, sizeof(*dest) );
|
||||||
@ -177,6 +163,57 @@ void CDECL MSVCRT__tzset(void)
|
|||||||
_munlock(_TIME_LOCK);
|
_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
|
#define SECSPERDAY 86400
|
||||||
/* 1601 to 1970 is 369 years plus 89 leap days */
|
/* 1601 to 1970 is 369 years plus 89 leap days */
|
||||||
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
|
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
|
||||||
@ -184,19 +221,100 @@ void CDECL MSVCRT__tzset(void)
|
|||||||
#define TICKSPERMSEC 10000
|
#define TICKSPERMSEC 10000
|
||||||
#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
|
#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.@)
|
* _mktime64 (MSVCRT.@)
|
||||||
*/
|
*/
|
||||||
MSVCRT___time64_t CDECL MSVCRT__mktime64(struct MSVCRT_tm *mstm)
|
MSVCRT___time64_t CDECL MSVCRT__mktime64(struct MSVCRT_tm *mstm)
|
||||||
{
|
{
|
||||||
time_t secs;
|
return mktime_helper(mstm, TRUE);
|
||||||
struct tm tm;
|
|
||||||
|
|
||||||
msvcrt_tm_to_unix( &tm, mstm );
|
|
||||||
secs = mktime( &tm );
|
|
||||||
unix_tm_to_msvcrt( mstm, &tm );
|
|
||||||
|
|
||||||
return secs < 0 ? -1 : secs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
@ -204,7 +322,8 @@ MSVCRT___time64_t CDECL MSVCRT__mktime64(struct MSVCRT_tm *mstm)
|
|||||||
*/
|
*/
|
||||||
MSVCRT___time32_t CDECL MSVCRT__mktime32(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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
Loading…
x
Reference in New Issue
Block a user