- RtlTimeFieldsToTime should not normalize the time fields
structure. Instead return error when it is given an unormalized date. - Use better algorithms for RtlTimeToTimeFields and RtlTimeFieldsToTime. RtlTimeToTimeFields is about 3 times faster. - Add tests for RtlTimeFieldsToTime. - SystemTimeToFileTime must fail if RtlTimeFieldsToTime fails. Users of SystemTimeToFileTime must do likewise. - Remove a todo_wine from SystemTimeToFileTime tests. - Since msvcrt.mktime must accept unnormalized dates, it cannot use SystemTimeToFileTime and do the calculations itself. - Add some tests for mktime accepting unnormalized dates.
This commit is contained in:
parent
45eba51461
commit
dceae02d73
|
@ -136,7 +136,6 @@ static void test_invalid_arg()
|
|||
ok( (ft.dwHighDateTime==NEWYEAR_1980_HI) && (ft.dwLowDateTime==NEWYEAR_1980_LO),
|
||||
"filetime for 1/1/80 00:00:00 was %08lx %08lx\n", ft.dwHighDateTime, ft.dwLowDateTime);
|
||||
|
||||
todo_wine {
|
||||
/* now check SystemTimeToFileTime */
|
||||
memset(&ft,0,sizeof ft);
|
||||
|
||||
|
@ -155,16 +154,15 @@ static void test_invalid_arg()
|
|||
|
||||
/* with a bad hour */
|
||||
SETUP_1980(st)
|
||||
st.wHour = 25;
|
||||
st.wHour = 24;
|
||||
|
||||
ok( !SystemTimeToFileTime(&st, &ft), "bad hour\n");
|
||||
|
||||
/* with a bad minute */
|
||||
SETUP_1980(st)
|
||||
st.wMinute = 61;
|
||||
st.wMinute = 60;
|
||||
|
||||
ok( !SystemTimeToFileTime(&st, &ft), "bad minute\n");
|
||||
}
|
||||
}
|
||||
|
||||
void test_GetTimeZoneInformation()
|
||||
|
|
|
@ -277,7 +277,8 @@ BOOL WINAPI SetLocalTime(
|
|||
LARGE_INTEGER st, st2;
|
||||
NTSTATUS status;
|
||||
|
||||
SystemTimeToFileTime( systime, &ft );
|
||||
if( !SystemTimeToFileTime( systime, &ft ))
|
||||
return FALSE;
|
||||
st.u.LowPart = ft.dwLowDateTime;
|
||||
st.u.HighPart = ft.dwHighDateTime;
|
||||
RtlLocalTimeToSystemTime( &st, &st2 );
|
||||
|
@ -329,7 +330,8 @@ BOOL WINAPI SetSystemTime(
|
|||
LARGE_INTEGER t;
|
||||
NTSTATUS status;
|
||||
|
||||
SystemTimeToFileTime( systime, &ft );
|
||||
if( !SystemTimeToFileTime( systime, &ft ))
|
||||
return FALSE;
|
||||
t.u.LowPart = ft.dwLowDateTime;
|
||||
t.u.HighPart = ft.dwHighDateTime;
|
||||
if ((status = NtSetSystemTime(&t, NULL)))
|
||||
|
@ -820,7 +822,10 @@ BOOL WINAPI SystemTimeToFileTime( const SYSTEMTIME *syst, LPFILETIME ft )
|
|||
tf.Second = syst->wSecond;
|
||||
tf.Milliseconds = syst->wMilliseconds;
|
||||
|
||||
RtlTimeFieldsToTime(&tf, &t);
|
||||
if( !RtlTimeFieldsToTime(&tf, &t)) {
|
||||
SetLastError( ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
ft->dwLowDateTime = t.u.LowPart;
|
||||
ft->dwHighDateTime = t.u.HighPart;
|
||||
return TRUE;
|
||||
|
|
|
@ -52,7 +52,7 @@ static void test_mktime()
|
|||
{
|
||||
TIME_ZONE_INFORMATION tzinfo;
|
||||
DWORD res = GetTimeZoneInformation(&tzinfo);
|
||||
struct tm my_tm;
|
||||
struct tm my_tm, sav_tm;
|
||||
time_t nulltime, local_time;
|
||||
char TZ_env[256];
|
||||
int secs;
|
||||
|
@ -73,10 +73,71 @@ static void test_mktime()
|
|||
my_tm.tm_year = 70;
|
||||
my_tm.tm_mon = 0;
|
||||
my_tm.tm_isdst= 0;
|
||||
|
||||
sav_tm = my_tm;
|
||||
|
||||
local_time = mktime(&my_tm);
|
||||
ok(((DWORD)local_time == SECSPERDAY), "mktime returned 0x%08lx\n",(DWORD)local_time);
|
||||
/* now test some unnormalized struct tm's */
|
||||
my_tm = sav_tm;
|
||||
my_tm.tm_sec += 60;
|
||||
my_tm.tm_min -= 1;
|
||||
local_time = mktime(&my_tm);
|
||||
ok(((DWORD)local_time == SECSPERDAY), "Unnormalized mktime returned 0x%08lx\n",(DWORD)local_time);
|
||||
ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
|
||||
my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
|
||||
my_tm.tm_sec == sav_tm.tm_sec
|
||||
, "mktime returned %3d-%02d-%02d %02d:%02d expected %3d-%02d-%02d %02d:%02d.\n",
|
||||
my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
|
||||
my_tm.tm_hour,my_tm.tm_sec,
|
||||
sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
|
||||
sav_tm.tm_hour,sav_tm.tm_sec);
|
||||
my_tm = sav_tm;
|
||||
my_tm.tm_min -= 60;
|
||||
my_tm.tm_hour += 1;
|
||||
local_time = mktime(&my_tm);
|
||||
ok(((DWORD)local_time == SECSPERDAY), "Unnormalized mktime returned 0x%08lx\n",(DWORD)local_time);
|
||||
ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
|
||||
my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
|
||||
my_tm.tm_sec == sav_tm.tm_sec
|
||||
, "mktime returned %3d-%02d-%02d %02d:%02d expected %3d-%02d-%02d %02d:%02d.\n",
|
||||
my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
|
||||
my_tm.tm_hour,my_tm.tm_sec,
|
||||
sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
|
||||
sav_tm.tm_hour,sav_tm.tm_sec);
|
||||
my_tm = sav_tm;
|
||||
my_tm.tm_mon -= 12;
|
||||
my_tm.tm_year += 1;
|
||||
local_time = mktime(&my_tm);
|
||||
ok(((DWORD)local_time == SECSPERDAY), "Unnormalized mktime returned 0x%08lx\n",(DWORD)local_time);
|
||||
ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
|
||||
my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
|
||||
my_tm.tm_sec == sav_tm.tm_sec
|
||||
, "mktime returned %3d-%02d-%02d %02d:%02d expected %3d-%02d-%02d %02d:%02d.\n",
|
||||
my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
|
||||
my_tm.tm_hour,my_tm.tm_sec,
|
||||
sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
|
||||
sav_tm.tm_hour,sav_tm.tm_sec);
|
||||
my_tm = sav_tm;
|
||||
my_tm.tm_mon += 12;
|
||||
my_tm.tm_year -= 1;
|
||||
local_time = mktime(&my_tm);
|
||||
ok(((DWORD)local_time == SECSPERDAY), "Unnormalized mktime returned 0x%08lx\n",(DWORD)local_time);
|
||||
ok( my_tm.tm_year == sav_tm.tm_year && my_tm.tm_mon == sav_tm.tm_mon &&
|
||||
my_tm.tm_mday == sav_tm.tm_mday && my_tm.tm_hour == sav_tm.tm_hour &&
|
||||
my_tm.tm_sec == sav_tm.tm_sec
|
||||
, "mktime returned %3d-%02d-%02d %02d:%02d expected %3d-%02d-%02d %02d:%02d.\n",
|
||||
my_tm.tm_year,my_tm.tm_mon,my_tm.tm_mday,
|
||||
my_tm.tm_hour,my_tm.tm_sec,
|
||||
sav_tm.tm_year,sav_tm.tm_mon,sav_tm.tm_mday,
|
||||
sav_tm.tm_hour,sav_tm.tm_sec);
|
||||
/* now a bad time example */
|
||||
my_tm = sav_tm;
|
||||
my_tm.tm_year -= 1;
|
||||
local_time = mktime(&my_tm);
|
||||
ok((local_time == -1), "(bad time) mktime returned 0x%08lx\n",(DWORD)local_time);
|
||||
|
||||
my_tm = sav_tm;
|
||||
/* TEST that we are independent from the TZ variable */
|
||||
/*Argh, msvcrt doesn't have setenv() */
|
||||
_snprintf(TZ_env,255,"TZ=%s",(getenv("TZ")?getenv("TZ"):""));
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#ifdef HAVE_SYS_TIMES_H
|
||||
# include <sys/times.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
|
||||
#include "msvcrt.h"
|
||||
#include "winbase.h"
|
||||
|
@ -61,29 +62,72 @@ static struct MSVCRT_tm tm;
|
|||
*/
|
||||
MSVCRT_time_t MSVCRT_mktime(struct MSVCRT_tm *t)
|
||||
{
|
||||
MSVCRT_time_t secs;
|
||||
SYSTEMTIME st;
|
||||
FILETIME lft, uft;
|
||||
ULONGLONG time;
|
||||
MSVCRT_time_t secs;
|
||||
FILETIME lft, uft;
|
||||
ULONGLONG time;
|
||||
struct MSVCRT_tm ts;
|
||||
int cleaps, day;
|
||||
|
||||
st.wMilliseconds = 0;
|
||||
st.wSecond = t->tm_sec;
|
||||
st.wMinute = t->tm_min;
|
||||
st.wHour = t->tm_hour;
|
||||
st.wDay = t->tm_mday;
|
||||
st.wMonth = t->tm_mon + 1;
|
||||
st.wYear = t->tm_year + 1900;
|
||||
ts=*t;
|
||||
/* to prevent arithmetic overflows put constraints on some fields */
|
||||
/* whether the effective date falls in the 1970-2038 time period */
|
||||
/* will be tested later */
|
||||
/* BTW, I have no idea what limits native msvcrt has. */
|
||||
if ( ts.tm_year < 0 || ts.tm_year > 140 ||
|
||||
ts.tm_mon < -840 || ts.tm_mon > 840 ||
|
||||
ts.tm_mday < -20160 || ts.tm_mday > 20160 ||
|
||||
ts.tm_hour < -484000 || ts.tm_hour > 484000 ||
|
||||
ts.tm_min < -29000000 || ts.tm_min > 29000000 )
|
||||
return -1;
|
||||
|
||||
/* normalize the tm month fields */
|
||||
if( ts.tm_mon > 11) { ts.tm_year += ts.tm_mon / 12; ts.tm_mon %= 12; }
|
||||
if( ts.tm_mon < 0) {
|
||||
int dy = (11 - ts.tm_mon) / 12;
|
||||
ts.tm_year -= dy;
|
||||
ts.tm_mon += dy * 12;
|
||||
}
|
||||
/* now calculate a day count from the date
|
||||
* First start counting years from March. This way the leap days
|
||||
* are added at the end of the year, not somewhere in the middle.
|
||||
* Formula's become so much less complicate that way.
|
||||
* To convert: add 12 to the month numbers of Jan and Feb, and
|
||||
* take 1 from the year */
|
||||
if(ts.tm_mon < 2) {
|
||||
ts.tm_mon += 14;
|
||||
ts.tm_year += 1899;
|
||||
} else {
|
||||
ts.tm_mon += 2;
|
||||
ts.tm_year += 1900;
|
||||
}
|
||||
cleaps = (3 * (ts.tm_year / 100) + 3) / 4; /* nr of "century leap years"*/
|
||||
day = (36525 * ts.tm_year) / 100 - cleaps + /* year * dayperyr, corrected*/
|
||||
(1959 * ts.tm_mon) / 64 + /* months * daypermonth */
|
||||
ts.tm_mday - /* day of the month */
|
||||
584817 ; /* zero that on 1601-01-01 */
|
||||
/* done */
|
||||
|
||||
SystemTimeToFileTime(&st, &lft);
|
||||
LocalFileTimeToFileTime(&lft, &uft);
|
||||
/* convert to 100 ns ticks */
|
||||
time = ((((ULONGLONG) day * 24 +
|
||||
ts.tm_hour) * 60 +
|
||||
ts.tm_min) * 60 +
|
||||
ts.tm_sec ) * TICKSPERSEC;
|
||||
|
||||
lft.dwHighDateTime = (DWORD) (time >> 32);
|
||||
lft.dwLowDateTime = (DWORD) time;
|
||||
|
||||
time = ((ULONGLONG)uft.dwHighDateTime << 32) | uft.dwLowDateTime;
|
||||
secs = time / TICKSPERSEC - SECS_1601_TO_1970;
|
||||
/* compute tm_wday, tm_yday and renormalize the other fields of the
|
||||
* tm structure */
|
||||
if( MSVCRT_localtime( &secs)) *t = tm;
|
||||
LocalFileTimeToFileTime(&lft, &uft);
|
||||
|
||||
return secs;
|
||||
time = ((ULONGLONG)uft.dwHighDateTime << 32) | uft.dwLowDateTime;
|
||||
time /= TICKSPERSEC;
|
||||
if( time < SECS_1601_TO_1970 || time > (SECS_1601_TO_1970 + INT_MAX))
|
||||
return -1;
|
||||
secs = time - SECS_1601_TO_1970;
|
||||
/* compute tm_wday, tm_yday and renormalize the other fields of the
|
||||
* tm structure */
|
||||
if( MSVCRT_localtime( &secs)) *t = tm;
|
||||
|
||||
return secs;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#define SECSPERDAY 86400
|
||||
|
||||
static VOID (WINAPI *pRtlTimeToTimeFields)( const LARGE_INTEGER *liTime, PTIME_FIELDS TimeFields) ;
|
||||
static VOID (WINAPI *pRtlTimeFieldsToTime)( PTIME_FIELDS TimeFields, PLARGE_INTEGER Time) ;
|
||||
|
||||
static const int MonthLengths[2][12] =
|
||||
{
|
||||
|
@ -44,7 +45,7 @@ TIME_FIELDS tftest = {1889,12,31,23,59,59,0,0};
|
|||
|
||||
static void test_pRtlTimeToTimeFields()
|
||||
{
|
||||
LARGE_INTEGER litime ;
|
||||
LARGE_INTEGER litime , liresult;
|
||||
TIME_FIELDS tfresult;
|
||||
int i=0;
|
||||
litime.QuadPart = ((ULONGLONG)0x0144017a << 32) | 0xf0b0a980;
|
||||
|
@ -59,6 +60,12 @@ static void test_pRtlTimeToTimeFields()
|
|||
tftest.Hour, tftest.Minute,tftest.Second,
|
||||
tfresult.Year, tfresult.Month, tfresult.Day,
|
||||
tfresult.Hour, tfresult.Minute, tfresult.Second);
|
||||
/* test the inverse */
|
||||
pRtlTimeFieldsToTime( &tfresult, &liresult);
|
||||
ok( liresult.QuadPart == litime.QuadPart," TimeFieldsToTime failed on %d-%d-%d %d:%d:%d. Error is %d ticks\n",
|
||||
tfresult.Year, tfresult.Month, tfresult.Day,
|
||||
tfresult.Hour, tfresult.Minute, tfresult.Second,
|
||||
(int) (liresult.QuadPart - litime.QuadPart) );
|
||||
/* one second later is beginning of next month */
|
||||
litime.QuadPart += TICKSPERSEC ;
|
||||
pRtlTimeToTimeFields( &litime, &tfresult);
|
||||
|
@ -71,6 +78,12 @@ static void test_pRtlTimeToTimeFields()
|
|||
tftest.Month % 12 + 1, 1, 0, 0, 0,
|
||||
tfresult.Year, tfresult.Month, tfresult.Day,
|
||||
tfresult.Hour, tfresult.Minute, tfresult.Second);
|
||||
/* test the inverse */
|
||||
pRtlTimeFieldsToTime( &tfresult, &liresult);
|
||||
ok( liresult.QuadPart == litime.QuadPart," TimeFieldsToTime failed on %d-%d-%d %d:%d:%d. Error is %d ticks\n",
|
||||
tfresult.Year, tfresult.Month, tfresult.Day,
|
||||
tfresult.Hour, tfresult.Minute, tfresult.Second,
|
||||
(int) (liresult.QuadPart - litime.QuadPart) );
|
||||
/* advance to the end of the month */
|
||||
litime.QuadPart -= TICKSPERSEC ;
|
||||
if( tftest.Month == 12) {
|
||||
|
@ -89,7 +102,8 @@ START_TEST(time)
|
|||
#ifdef __WINE_WINTERNL_H
|
||||
HMODULE mod = GetModuleHandleA("ntdll.dll");
|
||||
pRtlTimeToTimeFields = (void *)GetProcAddress(mod,"RtlTimeToTimeFields");
|
||||
if (pRtlTimeToTimeFields)
|
||||
pRtlTimeFieldsToTime = (void *)GetProcAddress(mod,"RtlTimeFieldsToTime");
|
||||
if (pRtlTimeToTimeFields && pRtlTimeFieldsToTime)
|
||||
test_pRtlTimeToTimeFields();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -338,23 +338,11 @@ static const int MonthLengths[2][MONSPERYEAR] =
|
|||
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
};
|
||||
|
||||
static const int YearDays[2][MONSPERYEAR+1] =
|
||||
{
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
|
||||
static inline int IsLeapYear(int Year)
|
||||
{
|
||||
return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline void NormalizeTimeFields(CSHORT *FieldToNormalize, CSHORT *CarryField,int Modulus)
|
||||
{
|
||||
*FieldToNormalize = (CSHORT) (*FieldToNormalize - Modulus);
|
||||
*CarryField = (CSHORT) (*CarryField + 1);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* NTDLL_get_server_timeout
|
||||
*
|
||||
|
@ -420,14 +408,15 @@ VOID WINAPI RtlTimeToTimeFields(
|
|||
const LARGE_INTEGER *liTime,
|
||||
PTIME_FIELDS TimeFields)
|
||||
{
|
||||
int SecondsInDay, DeltaYear;
|
||||
int LeapYear, CurMonth;
|
||||
int SecondsInDay;
|
||||
long int cleaps, years, yearday, months;
|
||||
long int Days;
|
||||
LONGLONG Time = liTime->QuadPart;
|
||||
LONGLONG Time;
|
||||
|
||||
/* Extract millisecond from time and convert time into seconds */
|
||||
TimeFields->Milliseconds = (CSHORT) ((Time % TICKSPERSEC) / TICKSPERMSEC);
|
||||
Time = Time / TICKSPERSEC;
|
||||
TimeFields->Milliseconds =
|
||||
(CSHORT) (( liTime->QuadPart % TICKSPERSEC) / TICKSPERMSEC);
|
||||
Time = liTime->QuadPart / TICKSPERSEC;
|
||||
|
||||
/* The native version of RtlTimeToTimeFields does not take leap seconds
|
||||
* into account */
|
||||
|
@ -445,32 +434,27 @@ VOID WINAPI RtlTimeToTimeFields(
|
|||
/* compute day of week */
|
||||
TimeFields->Weekday = (CSHORT) ((EPOCHWEEKDAY + Days) % DAYSPERWEEK);
|
||||
|
||||
/* compute year */
|
||||
/* FIXME: handle calendar modifications */
|
||||
TimeFields->Year = EPOCHYEAR;
|
||||
DeltaYear = Days / DAYSPERQUADRICENTENNIUM;
|
||||
TimeFields->Year += DeltaYear * 400;
|
||||
Days -= DeltaYear * DAYSPERQUADRICENTENNIUM;
|
||||
DeltaYear = Days / DAYSPERNORMALCENTURY;
|
||||
if( DeltaYear > 3) DeltaYear = 3; /* fix 31 Dec of 2000 and every
|
||||
400 years after that */
|
||||
TimeFields->Year += DeltaYear * 100;
|
||||
Days -= DeltaYear * DAYSPERNORMALCENTURY;
|
||||
DeltaYear = Days / DAYSPERNORMALQUADRENNIUM;
|
||||
TimeFields->Year += DeltaYear * 4;
|
||||
Days -= DeltaYear * DAYSPERNORMALQUADRENNIUM;
|
||||
DeltaYear = Days / DAYSPERNORMALYEAR;
|
||||
if( DeltaYear > 3) DeltaYear = 3; /* fix 31 Dec of every leap year */
|
||||
TimeFields->Year += DeltaYear;
|
||||
Days -= DeltaYear * DAYSPERNORMALYEAR;
|
||||
|
||||
LeapYear = IsLeapYear(TimeFields->Year);
|
||||
|
||||
/* Compute month of year */
|
||||
CurMonth = 1;
|
||||
while (Days >= YearDays[LeapYear][CurMonth]) CurMonth++;
|
||||
TimeFields->Day = Days - YearDays[LeapYear][CurMonth-1] + 1;
|
||||
TimeFields->Month = CurMonth;
|
||||
/* compute year, month and day of month. */
|
||||
cleaps=( 3 * ((4 * Days + 1227) / DAYSPERQUADRICENTENNIUM) + 3 ) / 4;
|
||||
Days += 28188 + cleaps;
|
||||
years = (20 * Days - 2442) / (5 * DAYSPERNORMALQUADRENNIUM);
|
||||
yearday = Days - (years * DAYSPERNORMALQUADRENNIUM)/4;
|
||||
months = (64 * yearday) / 1959;
|
||||
/* the result is based on a year starting on March.
|
||||
* To convert take 12 from Januari and Februari and
|
||||
* increase the year by one. */
|
||||
if( months < 14 ) {
|
||||
TimeFields->Month = months - 1;
|
||||
TimeFields->Year = years + 1524;
|
||||
} else {
|
||||
TimeFields->Month = months - 13;
|
||||
TimeFields->Year = years + 1525;
|
||||
}
|
||||
/* calculation of day of month is based on the wonderful
|
||||
* sequence of INT( n * 30.6): it reproduces the
|
||||
* 31-30-31-30-31-31 month lengths exactly for small n's */
|
||||
TimeFields->Day = yearday - (1959 * months) / 64 ;
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -490,51 +474,49 @@ BOOLEAN WINAPI RtlTimeFieldsToTime(
|
|||
PTIME_FIELDS tfTimeFields,
|
||||
PLARGE_INTEGER Time)
|
||||
{
|
||||
int CurYear, DeltaYear;
|
||||
LONGLONG rcTime;
|
||||
TIME_FIELDS TimeFields = *tfTimeFields;
|
||||
|
||||
rcTime = 0;
|
||||
int month, year, cleaps, day;
|
||||
|
||||
/* FIXME: normalize the TIME_FIELDS structure here */
|
||||
while (TimeFields.Second >= SECSPERMIN)
|
||||
{ NormalizeTimeFields(&TimeFields.Second, &TimeFields.Minute, SECSPERMIN);
|
||||
}
|
||||
while (TimeFields.Minute >= MINSPERHOUR)
|
||||
{ NormalizeTimeFields(&TimeFields.Minute, &TimeFields.Hour, MINSPERHOUR);
|
||||
}
|
||||
while (TimeFields.Hour >= HOURSPERDAY)
|
||||
{ NormalizeTimeFields(&TimeFields.Hour, &TimeFields.Day, HOURSPERDAY);
|
||||
}
|
||||
while (TimeFields.Day > MonthLengths[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1])
|
||||
{ NormalizeTimeFields(&TimeFields.Day, &TimeFields.Month,
|
||||
MonthLengths[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1]);
|
||||
}
|
||||
while (TimeFields.Month > MONSPERYEAR)
|
||||
{ NormalizeTimeFields(&TimeFields.Month, &TimeFields.Year, MONSPERYEAR);
|
||||
}
|
||||
/* No, native just returns 0 (error) if the fields are not */
|
||||
if( tfTimeFields->Milliseconds< 0 || tfTimeFields->Milliseconds > 999 ||
|
||||
tfTimeFields->Second < 0 || tfTimeFields->Second > 59 ||
|
||||
tfTimeFields->Minute < 0 || tfTimeFields->Minute > 59 ||
|
||||
tfTimeFields->Hour < 0 || tfTimeFields->Hour > 23 ||
|
||||
tfTimeFields->Month < 1 || tfTimeFields->Month > 12 ||
|
||||
tfTimeFields->Day < 1 ||
|
||||
tfTimeFields->Day > MonthLengths
|
||||
[ tfTimeFields->Month ==2 || IsLeapYear(tfTimeFields->Year)]
|
||||
[ tfTimeFields->Month - 1] ||
|
||||
tfTimeFields->Year < 1601 )
|
||||
return FALSE;
|
||||
|
||||
/* FIXME: handle calendar corrections here */
|
||||
CurYear = TimeFields.Year - EPOCHYEAR;
|
||||
DeltaYear = CurYear / 400;
|
||||
CurYear -= DeltaYear * 400;
|
||||
rcTime += DeltaYear * DAYSPERQUADRICENTENNIUM;
|
||||
DeltaYear = CurYear / 100;
|
||||
CurYear -= DeltaYear * 100;
|
||||
rcTime += DeltaYear * DAYSPERNORMALCENTURY;
|
||||
DeltaYear = CurYear / 4;
|
||||
CurYear -= DeltaYear * 4;
|
||||
rcTime += DeltaYear * DAYSPERNORMALQUADRENNIUM;
|
||||
rcTime += CurYear * DAYSPERNORMALYEAR;
|
||||
rcTime += YearDays[IsLeapYear(TimeFields.Year)][TimeFields.Month - 1];
|
||||
rcTime += TimeFields.Day - 1;
|
||||
rcTime *= SECSPERDAY;
|
||||
rcTime += TimeFields.Hour * SECSPERHOUR + TimeFields.Minute * SECSPERMIN + TimeFields.Second;
|
||||
rcTime *= TICKSPERSEC;
|
||||
rcTime += TimeFields.Milliseconds * TICKSPERMSEC;
|
||||
Time->QuadPart = rcTime;
|
||||
/* now calculate a day count from the date
|
||||
* First start counting years from March. This way the leap days
|
||||
* are added at the end of the year, not somewhere in the middle.
|
||||
* Formula's become so much less complicate that way.
|
||||
* To convert: add 12 to the month numbers of Jan and Feb, and
|
||||
* take 1 from the year */
|
||||
if(tfTimeFields->Month < 3) {
|
||||
month = tfTimeFields->Month + 13;
|
||||
year = tfTimeFields->Year - 1;
|
||||
} else {
|
||||
month = tfTimeFields->Month + 1;
|
||||
year = tfTimeFields->Year;
|
||||
}
|
||||
cleaps = (3 * (year / 100) + 3) / 4; /* nr of "century leap years"*/
|
||||
day = (36525 * year) / 100 - cleaps + /* year * dayperyr, corrected */
|
||||
(1959 * month) / 64 + /* months * daypermonth */
|
||||
tfTimeFields->Day - /* day of the month */
|
||||
584817 ; /* zero that on 1601-01-01 */
|
||||
/* done */
|
||||
|
||||
Time->QuadPart = (((((LONGLONG) day * HOURSPERDAY +
|
||||
tfTimeFields->Hour) * MINSPERHOUR +
|
||||
tfTimeFields->Minute) * SECSPERMIN +
|
||||
tfTimeFields->Second ) * 1000 +
|
||||
tfTimeFields->Milliseconds ) * TICKSPERMSEC;
|
||||
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
Loading…
Reference in New Issue