Implement the non-variant date conversions correctly, without going

through 'struct tm' first. Handle negative & 'rolling' dates too.
This commit is contained in:
Jon Griffiths 2003-11-14 21:01:36 +00:00 committed by Alexandre Julliard
parent 2f558b53f1
commit 136fa03fbf

View file

@ -2,6 +2,10 @@
* VARIANT
*
* Copyright 1998 Jean-Claude Cote
* Copyright 2003 Jon Griffiths
* The alorithm for conversion from Julian days to day/month/year is based on
* that devised by Henry Fliegel, as implemented in PostgreSQL, which is
* Copyright 1994-7 Regents of the University of California
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -4206,27 +4210,427 @@ error:
return DISP_E_TYPEMISMATCH;
}
/* Date Conversions */
#define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
/* Convert a VT_DATE value to a Julian Date */
static inline int VARIANT_JulianFromDate(int dateIn)
{
int julianDays = dateIn;
julianDays -= DATE_MIN; /* Convert to + days from 1 Jan 100 AD */
julianDays += 1757585; /* Convert to + days from 23 Nov 4713 BC (Julian) */
return julianDays;
}
/* Convert a Julian Date to a VT_DATE value */
static inline int VARIANT_DateFromJulian(int dateIn)
{
int julianDays = dateIn;
julianDays -= 1757585; /* Convert to + days from 1 Jan 100 AD */
julianDays += DATE_MIN; /* Convert to +/- days from 1 Jan 1899 AD */
return julianDays;
}
/* Convert a Julian date to Day/Month/Year - from PostgreSQL */
static inline void VARIANT_DMYFromJulian(int jd, USHORT *year, USHORT *month, USHORT *day)
{
int j, i, l, n;
l = jd + 68569;
n = l * 4 / 146097;
l -= (n * 146097 + 3) / 4;
i = (4000 * (l + 1)) / 1461001;
l += 31 - (i * 1461) / 4;
j = (l * 80) / 2447;
*day = l - (j * 2447) / 80;
l = j / 11;
*month = (j + 2) - (12 * l);
*year = 100 * (n - 49) + i + l;
}
/* Convert Day/Month/Year to a Julian date - from PostgreSQL */
static inline double VARIANT_JulianFromDMY(USHORT year, USHORT month, USHORT day)
{
int m12 = (month - 14) / 12;
return ((1461 * (year + 4800 + m12)) / 4 + (367 * (month - 2 - 12 * m12)) / 12 -
(3 * ((year + 4900 + m12) / 100)) / 4 + day - 32075);
}
/* Macros for accessing DOS format date/time fields */
#define DOS_YEAR(x) (1980 + (x >> 9))
#define DOS_MONTH(x) ((x >> 5) & 0xf)
#define DOS_DAY(x) (x & 0x1f)
#define DOS_HOUR(x) (x >> 11)
#define DOS_MINUTE(x) ((x >> 5) & 0x3f)
#define DOS_SECOND(x) ((x & 0x1f) << 1)
/* Create a DOS format date/time */
#define DOS_DATE(d,m,y) (d | (m << 5) | ((y-1980) << 9))
#define DOS_TIME(h,m,s) ((s >> 1) | (m << 5) | (h << 11))
/* Roll a date forwards or backwards to correct it */
static HRESULT VARIANT_RollUdate(UDATE *lpUd)
{
static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
TRACE("Raw date: %d/%d/%d %d:%d:%d\n", lpUd->st.wDay, lpUd->st.wMonth,
lpUd->st.wYear, lpUd->st.wHour, lpUd->st.wMinute, lpUd->st.wSecond);
/* Years < 100 are treated as 1900 + year */
if (lpUd->st.wYear < 100)
lpUd->st.wYear += 1900;
if (!lpUd->st.wMonth)
{
/* Roll back to December of the previous year */
lpUd->st.wMonth = 12;
lpUd->st.wYear--;
}
else while (lpUd->st.wMonth > 12)
{
/* Roll forward the correct number of months */
lpUd->st.wYear++;
lpUd->st.wMonth -= 12;
}
if (lpUd->st.wYear > 9999 || lpUd->st.wHour > 23 ||
lpUd->st.wMinute > 59 || lpUd->st.wSecond > 59)
return E_INVALIDARG; /* Invalid values */
if (!lpUd->st.wDay)
{
/* Roll back the date one day */
if (lpUd->st.wMonth == 1)
{
/* Roll back to December 31 of the previous year */
lpUd->st.wDay = 31;
lpUd->st.wMonth = 12;
lpUd->st.wYear--;
}
else
{
lpUd->st.wMonth--; /* Previous month */
if (lpUd->st.wMonth == 2 && IsLeapYear(lpUd->st.wYear))
lpUd->st.wDay = 29; /* Februaury has 29 days on leap years */
else
lpUd->st.wDay = days[lpUd->st.wMonth]; /* Last day of the month */
}
}
else if (lpUd->st.wDay > 28)
{
int rollForward = 0;
/* Possibly need to roll the date forward */
if (lpUd->st.wMonth == 2 && IsLeapYear(lpUd->st.wYear))
rollForward = lpUd->st.wDay - 29; /* Februaury has 29 days on leap years */
else
rollForward = lpUd->st.wDay - days[lpUd->st.wMonth];
if (rollForward > 0)
{
lpUd->st.wDay = rollForward;
lpUd->st.wMonth++;
if (lpUd->st.wMonth > 12)
{
lpUd->st.wMonth = 1; /* Roll forward into January of the next year */
lpUd->st.wYear++;
}
}
}
TRACE("Rolled date: %d/%d/%d %d:%d:%d\n", lpUd->st.wDay, lpUd->st.wMonth,
lpUd->st.wYear, lpUd->st.wHour, lpUd->st.wMinute, lpUd->st.wSecond);
return S_OK;
}
/**********************************************************************
* DosDateTimeToVariantTime [OLEAUT32.14]
* Convert dos representation of time to the date and time representation
* stored in a variant.
*
* Convert a Dos format date and time into variant VT_DATE format.
*
* PARAMS
* wDosDate [I] Dos format date
* wDosTime [I] Dos format time
* pDateOut [O] Destination for VT_DATE format
*
* RETURNS
* Success: TRUE. pDateOut contains the converted time.
* Failure: FALSE, if wDosDate or wDosTime are invalid (see notes).
*
* NOTES
* - Dos format dates can only hold dates from 1-Jan-1980 to 31-Dec-2099.
* - Dos format times are accurate to only 2 second precision.
* - The format of a Dos Date is:
*| Bits Values Meaning
*| ---- ------ -------
*| 0-4 1-31 Day of the week. 0 rolls back one day. A value greater than
*| the days in the month rolls forward the extra days.
*| 5-8 1-12 Month of the year. 0 rolls back to December of the previous
*| year. 13-15 are invalid.
*| 9-15 0-119 Year based from 1980 (Max 2099). 120-127 are invalid.
* - The format of a Dos Time is:
*| Bits Values Meaning
*| ---- ------ -------
*| 0-4 0-29 Seconds/2. 30 and 31 are invalid.
*| 5-10 0-59 Minutes. 60-63 are invalid.
*| 11-15 0-23 Hours (24 hour clock). 24-32 are invalid.
*/
INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
DATE *pvtime)
double *pDateOut)
{
struct tm t;
UDATE ud;
TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
TRACE("(0x%x(%d/%d/%d),0x%x(%d:%d:%d),%p)\n",
wDosDate, DOS_YEAR(wDosDate), DOS_MONTH(wDosDate), DOS_DAY(wDosDate),
wDosTime, DOS_HOUR(wDosTime), DOS_MINUTE(wDosTime), DOS_SECOND(wDosTime),
pDateOut);
t.tm_sec = (wDosTime & 0x001f) * 2;
t.tm_min = (wDosTime & 0x07e0) >> 5;
t.tm_hour = (wDosTime & 0xf800) >> 11;
ud.st.wYear = DOS_YEAR(wDosDate);
ud.st.wMonth = DOS_MONTH(wDosDate);
if (ud.st.wYear > 2099 || ud.st.wMonth > 12)
return FALSE;
ud.st.wDay = DOS_DAY(wDosDate);
ud.st.wHour = DOS_HOUR(wDosTime);
ud.st.wMinute = DOS_MINUTE(wDosTime);
ud.st.wSecond = DOS_SECOND(wDosTime);
ud.st.wDayOfWeek = ud.st.wMilliseconds = 0;
t.tm_mday = (wDosDate & 0x001f);
t.tm_mon = (wDosDate & 0x01e0) >> 5;
t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
return !VarDateFromUdate(&ud, 0, pDateOut);
}
return TmToDATE( &t, pvtime );
/**********************************************************************
* VariantTimeToDosDateTime [OLEAUT32.13]
*
* Convert a variant format date into a Dos format date and time.
*
* dateIn [I] VT_DATE time format
* pwDosDate [O] Destination for Dos format date
* pwDosTime [O] Destination for Dos format time
*
* RETURNS
* Success: TRUE. pwDosDate and pwDosTime contains the converted values.
* Failure: FALSE, if dateIn cannot be represented in Dos format.
*
* NOTES
* See DosDateTimeToVariantTime() for Dos format details and bugs.
*/
INT WINAPI VariantTimeToDosDateTime(double dateIn, USHORT *pwDosDate, USHORT *pwDosTime)
{
UDATE ud;
TRACE("(%g,%p,%p)\n", dateIn, pwDosDate, pwDosTime);
if (FAILED(VarUdateFromDate(dateIn, 0, &ud)))
return FALSE;
if (ud.st.wYear < 1980 || ud.st.wYear > 2099)
return FALSE;
*pwDosDate = DOS_DATE(ud.st.wDay, ud.st.wMonth, ud.st.wYear);
*pwDosTime = DOS_TIME(ud.st.wHour, ud.st.wMinute, ud.st.wSecond);
TRACE("Returning 0x%x(%d/%d/%d), 0x%x(%d:%d:%d)\n",
*pwDosDate, DOS_YEAR(*pwDosDate), DOS_MONTH(*pwDosDate), DOS_DAY(*pwDosDate),
*pwDosTime, DOS_HOUR(*pwDosTime), DOS_MINUTE(*pwDosTime), DOS_SECOND(*pwDosTime));
return TRUE;
}
/***********************************************************************
* SystemTimeToVariantTime [OLEAUT32.184]
*
* Convert a System format date and time into variant VT_DATE format.
*
* PARAMS
* lpSt [I] System format date and time
* pDateOut [O] Destination for VT_DATE format date
*
* RETURNS
* Success: TRUE. *pDateOut contains the converted value.
* Failure: FALSE, if lpSt cannot be represented in VT_DATE format.
*/
INT WINAPI SystemTimeToVariantTime(LPSYSTEMTIME lpSt, double *pDateOut)
{
UDATE ud;
TRACE("(%p->%d/%d/%d %d:%d:%d,%p)\n", lpSt, lpSt->wDay, lpSt->wMonth,
lpSt->wYear, lpSt->wHour, lpSt->wMinute, lpSt->wSecond, pDateOut);
if (lpSt->wMonth > 12)
return FALSE;
memcpy(&ud.st, lpSt, sizeof(ud.st));
return !VarDateFromUdate(&ud, 0, pDateOut);
}
/***********************************************************************
* VariantTimeToSystemTime [OLEAUT32.185]
*
* Convert a variant VT_DATE into a System format date and time.
*
* PARAMS
* datein [I] Variant VT_DATE format date
* lpSt [O] Destination for System format date and time
*
* RETURNS
* Success: TRUE. *lpSt contains the converted value.
* Failure: FALSE, if dateIn is too large or small.
*/
INT WINAPI VariantTimeToSystemTime(double dateIn, LPSYSTEMTIME lpSt)
{
UDATE ud;
TRACE("(%g,%p)\n", dateIn, lpSt);
if (FAILED(VarUdateFromDate(dateIn, 0, &ud)))
return FALSE;
memcpy(lpSt, &ud.st, sizeof(ud.st));
return TRUE;
}
/***********************************************************************
* VarDateFromUdate [OLEAUT32.330]
*
* Convert an unpacked format date and time to a variant VT_DATE.
*
* PARAMS
* pUdateIn [I] Unpacked format date and time to convert
* dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
* pDateOut [O] Destination for variant VT_DATE.
*
* RETURNS
* Success: S_OK. *pDateOut contains the converted value.
* Failure: E_INVALIDARG, if pUdateIn cannot be represented in VT_DATE format.
*/
HRESULT WINAPI VarDateFromUdate(UDATE *pUdateIn, ULONG dwFlags, DATE *pDateOut)
{
UDATE ud;
double dateVal;
TRACE("(%p->%d/%d/%d %d:%d:%d:%d %d %d,0x%08lx,%p)\n", pUdateIn,
pUdateIn->st.wMonth, pUdateIn->st.wDay, pUdateIn->st.wYear,
pUdateIn->st.wHour, pUdateIn->st.wMinute, pUdateIn->st.wSecond,
pUdateIn->st.wMilliseconds, pUdateIn->st.wDayOfWeek,
pUdateIn->wDayOfYear, dwFlags, pDateOut);
memcpy(&ud, pUdateIn, sizeof(ud));
if (dwFlags & VAR_VALIDDATE)
WARN("Ignoring VAR_VALIDDATE\n");
if (FAILED(VARIANT_RollUdate(&ud)))
return E_INVALIDARG;
/* Date */
dateVal = VARIANT_DateFromJulian(VARIANT_JulianFromDMY(ud.st.wYear, ud.st.wMonth, ud.st.wDay));
/* Time */
dateVal += ud.st.wHour / 24.0;
dateVal += ud.st.wMinute / 1440.0;
dateVal += ud.st.wSecond / 86400.0;
dateVal += ud.st.wMilliseconds / 86400000.0;
TRACE("Returning %g\n", dateVal);
*pDateOut = dateVal;
return S_OK;
}
/***********************************************************************
* VarUdateFromDate [OLEAUT32.331]
*
* Convert a variant VT_DATE into an unpacked format date and time.
*
* PARAMS
* datein [I] Variant VT_DATE format date
* dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
* lpUdate [O] Destination for unpacked format date and time
*
* RETURNS
* Success: S_OK. *lpUdate contains the converted value.
* Failure: E_INVALIDARG, if dateIn is too large or small.
*/
HRESULT WINAPI VarUdateFromDate(DATE dateIn, ULONG dwFlags, UDATE *lpUdate)
{
/* Cumulative totals of days per month */
static const USHORT cumulativeDays[] =
{
0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};
double datePart, timePart;
int julianDays;
TRACE("(%g,0x%08lx,%p)\n", dateIn, dwFlags, lpUdate);
if (dateIn <= (DATE_MIN - 1.0) || dateIn >= (DATE_MAX + 1.0))
return E_INVALIDARG;
datePart = dateIn < 0.0 ? ceil(dateIn) : floor(dateIn);
/* Compensate for int truncation (always downwards) */
timePart = dateIn - datePart + 0.00000000001;
if (timePart >= 1.0)
timePart -= 0.00000000001;
/* Date */
julianDays = VARIANT_JulianFromDate(dateIn);
VARIANT_DMYFromJulian(julianDays, &lpUdate->st.wYear, &lpUdate->st.wMonth,
&lpUdate->st.wDay);
datePart = (datePart + 1.5) / 7.0;
lpUdate->st.wDayOfWeek = (datePart - floor(datePart)) * 7;
if (lpUdate->st.wDayOfWeek == 0)
lpUdate->st.wDayOfWeek = 5;
else if (lpUdate->st.wDayOfWeek == 1)
lpUdate->st.wDayOfWeek = 6;
else
lpUdate->st.wDayOfWeek -= 2;
if (lpUdate->st.wMonth > 2 && IsLeapYear(lpUdate->st.wYear))
lpUdate->wDayOfYear = 1; /* After February, in a leap year */
else
lpUdate->wDayOfYear = 0;
lpUdate->wDayOfYear += cumulativeDays[lpUdate->st.wMonth];
lpUdate->wDayOfYear += lpUdate->st.wDay;
/* Time */
timePart *= 24.0;
lpUdate->st.wHour = timePart;
timePart -= lpUdate->st.wHour;
timePart *= 60.0;
lpUdate->st.wMinute = timePart;
timePart -= lpUdate->st.wMinute;
timePart *= 60.0;
lpUdate->st.wSecond = timePart;
timePart -= lpUdate->st.wSecond;
lpUdate->st.wMilliseconds = 0;
if (timePart > 0.0005)
{
/* Round the milliseconds, adjusting the time/date forward if needed */
if (lpUdate->st.wSecond < 59)
lpUdate->st.wSecond++;
else
{
lpUdate->st.wSecond = 0;
if (lpUdate->st.wMinute < 59)
lpUdate->st.wMinute++;
else
{
lpUdate->st.wMinute = 0;
if (lpUdate->st.wHour < 23)
lpUdate->st.wHour++;
else
{
lpUdate->st.wHour = 0;
/* Roll over a whole day */
if (++lpUdate->st.wDay > 28)
VARIANT_RollUdate(lpUdate);
}
}
}
}
return S_OK;
}
#define GET_NUMBER_TEXT(fld,name) \
@ -5003,288 +5407,6 @@ HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren,
return E_NOTIMPL;
}
/**********************************************************************
* VariantTimeToDosDateTime [OLEAUT32.13]
* Convert variant representation of time to the date and time representation
* stored in dos.
*/
INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
{
struct tm t;
*wDosTime = 0;
*wDosDate = 0;
TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
if (DateToTm(pvtime, 0, &t) < 0) return 0;
*wDosTime = *wDosTime | (t.tm_sec / 2);
*wDosTime = *wDosTime | (t.tm_min << 5);
*wDosTime = *wDosTime | (t.tm_hour << 11);
*wDosDate = *wDosDate | t.tm_mday ;
*wDosDate = *wDosDate | t.tm_mon << 5;
*wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
return 1;
}
/***********************************************************************
* SystemTimeToVariantTime [OLEAUT32.184]
*/
HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime )
{
struct tm t;
TRACE(" %d/%d/%d %d:%d:%d\n",
lpSystemTime->wMonth, lpSystemTime->wDay,
lpSystemTime->wYear, lpSystemTime->wHour,
lpSystemTime->wMinute, lpSystemTime->wSecond);
if (lpSystemTime->wYear >= 1900)
{
t.tm_sec = lpSystemTime->wSecond;
t.tm_min = lpSystemTime->wMinute;
t.tm_hour = lpSystemTime->wHour;
t.tm_mday = lpSystemTime->wDay;
t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
t.tm_year = lpSystemTime->wYear;
return TmToDATE( &t, pvtime );
}
else
{
double tmpDate;
long firstDayOfNextYear;
long thisDay;
long leftInYear;
long result;
double decimalPart = 0.0;
t.tm_sec = lpSystemTime->wSecond;
t.tm_min = lpSystemTime->wMinute;
t.tm_hour = lpSystemTime->wHour;
/* Step year forward the same number of years before 1900 */
t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
t.tm_mon = lpSystemTime->wMonth - 1;
t.tm_mday = lpSystemTime->wDay;
/* Calculate date */
TmToDATE( &t, pvtime );
thisDay = (double) floor( *pvtime );
decimalPart = fmod( *pvtime, thisDay );
/* Now, calculate the same time for the first of Jan that year */
t.tm_mon = 0;
t.tm_mday = 1;
t.tm_sec = 0;
t.tm_min = 0;
t.tm_hour = 0;
t.tm_year = t.tm_year+1;
TmToDATE( &t, &tmpDate );
firstDayOfNextYear = (long) floor(tmpDate);
/* Finally since we know the size of the year, subtract the two to get
remaining time in the year */
leftInYear = firstDayOfNextYear - thisDay;
/* Now we want full years up to the year in question, and remainder of year
of the year in question */
if (isleap(lpSystemTime->wYear) ) {
TRACE("Extra day due to leap year\n");
result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
} else {
result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
}
*pvtime = (double) result + decimalPart;
TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
return 1;
}
return 0;
}
/***********************************************************************
* VariantTimeToSystemTime [OLEAUT32.185]
*/
HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME lpSystemTime )
{
double t = 0, timeofday = 0;
static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
static const BYTE Month_Code[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
/* The Century_Code is used to find the Day of the Week */
static const BYTE Century_Code[] = {0, 6, 4, 2};
struct tm r;
TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
if (vtime >= 0)
{
if (DateToTm(vtime, 0, &r ) <= 0) return 0;
lpSystemTime->wSecond = r.tm_sec;
lpSystemTime->wMinute = r.tm_min;
lpSystemTime->wHour = r.tm_hour;
lpSystemTime->wDay = r.tm_mday;
lpSystemTime->wMonth = r.tm_mon;
if (lpSystemTime->wMonth == 12)
lpSystemTime->wMonth = 1;
else
lpSystemTime->wMonth++;
lpSystemTime->wYear = r.tm_year;
}
else
{
vtime = -1*vtime;
if (DateToTm(vtime, 0, &r ) <= 0) return 0;
lpSystemTime->wSecond = r.tm_sec;
lpSystemTime->wMinute = r.tm_min;
lpSystemTime->wHour = r.tm_hour;
lpSystemTime->wMonth = 13 - r.tm_mon;
if (lpSystemTime->wMonth == 1)
lpSystemTime->wMonth = 12;
else
lpSystemTime->wMonth--;
lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
if (!isleap(lpSystemTime->wYear) )
lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
else
lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
}
if (!isleap(lpSystemTime->wYear))
{
/*
(Century_Code+Month_Code+Year_Code+Day) % 7
The century code repeats every 400 years , so the array
works out like this,
Century_Code[0] is for 16th/20th Centry
Century_Code[1] is for 17th/21th Centry
Century_Code[2] is for 18th/22th Centry
Century_Code[3] is for 19th/23th Centry
The year code is found with the formula (year + (year / 4))
the "year" must be between 0 and 99 .
The Month Code (Month_Code[1]) starts with January and
ends with December.
*/
lpSystemTime->wDayOfWeek = (
Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
Month_Code[lpSystemTime->wMonth]+
lpSystemTime->wDay) % 7;
if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
else lpSystemTime->wDayOfWeek -= 1;
}
else
{
lpSystemTime->wDayOfWeek = (
Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
Month_Code_LY[lpSystemTime->wMonth]+
lpSystemTime->wDay) % 7;
if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
else lpSystemTime->wDayOfWeek -= 1;
}
t = floor(vtime);
timeofday = vtime - t;
lpSystemTime->wMilliseconds = (timeofday
- lpSystemTime->wHour*(1/24)
- lpSystemTime->wMinute*(1/1440)
- lpSystemTime->wSecond*(1/86400) )*(1/5184000);
return 1;
}
/***********************************************************************
* VarUdateFromDate [OLEAUT32.331]
*/
HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
{
HRESULT i = 0;
static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
TRACE("DATE = %f\n", (double)datein);
i = VariantTimeToSystemTime(datein, &(pudateout->st) );
if (i)
{
pudateout->wDayOfYear = 0;
if (isleap(pudateout->st.wYear))
{
for (i =1; i<pudateout->st.wMonth; i++)
pudateout->wDayOfYear += Days_Per_Month[i];
}
else
{
for (i =1; i<pudateout->st.wMonth; i++)
pudateout->wDayOfYear += Days_Per_Month_LY[i];
}
pudateout->wDayOfYear += pudateout->st.wDay;
dwFlags = 0; /*VAR_VALIDDATE*/
}
else dwFlags = 0;
return i;
}
/***********************************************************************
* VarDateFromUdate [OLEAUT32.330]
*/
HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
ULONG dwFlags, DATE *datein)
{
HRESULT i;
double t = 0;
TRACE(" %d/%d/%d %d:%d:%d\n",
pudateout->st.wMonth, pudateout->st.wDay,
pudateout->st.wYear, pudateout->st.wHour,
pudateout->st.wMinute, pudateout->st.wSecond);
i = SystemTimeToVariantTime(&(pudateout->st), &t);
*datein = t;
if (i) return S_OK;
else return E_INVALIDARG;
}
/**********************************************************************
* VarBstrCmp [OLEAUT32.314]
*