416 lines
11 KiB
C++
416 lines
11 KiB
C++
//+------------------------------------------------------------
|
|
//
|
|
// File: time.cxx
|
|
//
|
|
// Contents: Component object model time utilities
|
|
//
|
|
// Functions: CoFileTimeToDosDateTime
|
|
// CoDosDateTimeToFileTime
|
|
// CoFileTimeNow
|
|
//
|
|
// History: 5-Apr-94 brucema Created
|
|
//
|
|
//-------------------------------------------------------------
|
|
#include <ole2int.h>
|
|
|
|
#if defined (WIN32)
|
|
|
|
STDAPI_(BOOL) CoFileTimeToDosDateTime(
|
|
FILETIME FAR* lpFileTime, LPWORD lpFatDate, LPWORD lpFatTime)
|
|
{
|
|
OLETRACEIN((API_CoFileTimeToDosDateTime, PARAMFMT("lpFileTime= %tf, lpFatDate= %p, lpFatTime= %p"),
|
|
lpFileTime, lpFatDate, lpFatTime));
|
|
BOOL fRet= FALSE;
|
|
|
|
if ((lpFileTime != NULL) &&
|
|
IsValidPtrIn(lpFileTime, sizeof(*lpFileTime)) &&
|
|
IsValidPtrOut(lpFatDate, sizeof(*lpFatDate)) &&
|
|
IsValidPtrOut(lpFatTime, sizeof(*lpFatTime)))
|
|
{
|
|
fRet = FileTimeToDosDateTime(lpFileTime, lpFatDate, lpFatTime);
|
|
}
|
|
|
|
OLETRACEOUTEX((API_CoFileTimeToDosDateTime, RETURNFMT("%B"), fRet));
|
|
return fRet;
|
|
}
|
|
|
|
STDAPI_(BOOL) CoDosDateTimeToFileTime(
|
|
WORD nDosDate, WORD nDosTime, FILETIME FAR* lpFileTime)
|
|
{
|
|
OLETRACEIN((API_CoDosDateTimeToFileTime, PARAMFMT("nDosDate=%x, nDosTime=%x, lpFileTime=%p"),
|
|
nDosDate, nDosTime, lpFileTime));
|
|
|
|
BOOL fRet= FALSE;
|
|
|
|
if (IsValidPtrOut(lpFileTime, sizeof(*lpFileTime)))
|
|
{
|
|
fRet = DosDateTimeToFileTime(nDosDate, nDosTime, lpFileTime);
|
|
}
|
|
|
|
OLETRACEOUTEX((API_CoDosDateTimeToFileTime, RETURNFMT("%B"), fRet));
|
|
return fRet;
|
|
}
|
|
|
|
#else
|
|
|
|
#include <dos.h>
|
|
// 64 bit representation of 100ns units between 1-1-1601 and (excluding) 1-1-80
|
|
// in two 32 bit values (H1980:L1980) and
|
|
// in four 16 bit values (HH1980:HL1980:LH1980:LL1980)
|
|
//
|
|
#define H1980 0x01A8E79F
|
|
#define L1980 0xE1D59586
|
|
#define HH1980 0x01A8
|
|
#define HL1980 0xE79F
|
|
#define LH1980 0xE1D5
|
|
#define LL1980 0x9586
|
|
|
|
// Number of 100ns units in one second represented as one 32 bit value
|
|
//
|
|
#define ONESEC 10000000
|
|
|
|
// ONESEC0 * ONESEC1 = ONESEC both are 16 bits values
|
|
//
|
|
#define ONESEC0 4000
|
|
#define ONESEC1 2500
|
|
|
|
// Non-leap year accumulating days, excluding current month, jan is month[0]
|
|
static const UINT MonthTab[] = {0,31,59,90,120,151,181,212,243,273,304,334};
|
|
|
|
// Leap year accumulating days, excluding current month, jan is month[0]
|
|
static const UINT LeapmTab[] = {0,31,60,91,121,152,182,213,244,274,305,335};
|
|
|
|
// Accumulating days, excluding current year, year[0] is leap year
|
|
static const UINT YearTab[] = {0,366,731,1096};
|
|
|
|
// Number of days in a four years period that includes a leap year
|
|
static const UINT FourYear = 1461;
|
|
|
|
// Number of days in a 100 years period that does not start with a leap year
|
|
static const DWORD HundredYear = 36524;
|
|
|
|
// Number of days in a 400 years period (starts with a leap year)
|
|
static const DWORD FourHundredYear = 146097;
|
|
|
|
|
|
#pragma SEG(CoFileTimeToDosDateTime)
|
|
STDAPI_(BOOL) CoFileTimeToDosDateTime(
|
|
FILETIME FAR* lpFileTime, LPWORD lpFatDate, LPWORD lpFatTime)
|
|
{
|
|
DWORD Year,Month,Day,Hour,Min,Sec;
|
|
DWORD Days, Seconds;
|
|
DWORD LowNs, HighNs;
|
|
int i;
|
|
|
|
if ((lpFileTime == NULL) ||
|
|
!IsValidPtrIn(lpFileTime, sizeof(*lpFileTime)) ||
|
|
!IsValidPtrOut(lpFatDate, sizeof(*lpFatDate)) ||
|
|
!IsValidPtrOut(lpFatTime, sizeof(*lpFatTime)))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
LowNs = lpFileTime->dwLowDateTime;
|
|
HighNs = lpFileTime->dwHighDateTime;
|
|
|
|
i = 1;
|
|
|
|
// Note that the following code works because 2000 is a leap year
|
|
// and DosDate year range is 1980 - 2099
|
|
//
|
|
_asm {
|
|
mov ax,word ptr LowNs
|
|
mov bx,word ptr LowNs+2
|
|
mov cx,word ptr HighNs
|
|
mov dx,word ptr HighNs+2 ; (dx:cx:bx:ax) = time in NT format
|
|
sub ax,LL1980
|
|
sbb bx,LH1980
|
|
sbb cx,HL1980
|
|
sbb dx,HH1980 ; (dx:cx:bx:ax) = 100ns since 1-1-1980
|
|
jc cvt0 ; Before the beginning of DosDateTime
|
|
|
|
; Divide (dx:cx:bx:ax) by ONESEC.
|
|
; Note that for any time before year 2100 the bumber of 100ns
|
|
; since 1-1-1980 divided by ONESEC0 < 2^48 (that is can be stored
|
|
; in three registers) and that the result divided by ONESEC1 < 2^32
|
|
;
|
|
mov si,cx ; (dx:si:bx:ax) = 100ns since 1-1-1980
|
|
mov cx,ONESEC0
|
|
mov di,ax ; (dx:si:bx:di) = 100ns since 1-1-1980
|
|
mov ax,dx ; divide
|
|
xor dx,dx
|
|
div cx ; ax = q (should be 0) dx = r (used in next div)
|
|
or ax,ax
|
|
jnz cvt0 ; past 1-1-2100
|
|
mov ax,si
|
|
div cx ; ax = q (should be 0) dx = r (used in next div)
|
|
mov si,ax
|
|
mov ax,bx
|
|
div cx
|
|
mov bx,ax
|
|
mov ax,di
|
|
div cx
|
|
mov di,ax ; (si:bx:di) = 100ns since 1-1-1980 / ONESEC0
|
|
mov ax,si
|
|
mov cx,ONESEC1
|
|
xor dx,dx
|
|
div cx ; ax = q (should be 0) dx = r (used in next div)
|
|
or ax,ax
|
|
jnz cvt0 ; past 1-1-2100
|
|
mov ax,bx
|
|
div cx
|
|
mov word ptr Seconds+2,ax
|
|
mov ax,di
|
|
div cx
|
|
mov word ptr Seconds,ax
|
|
mov i,0 ; No error
|
|
cvt0:
|
|
}
|
|
|
|
if (i)
|
|
return FALSE;
|
|
|
|
// Min, Hour, Days since 1980
|
|
//
|
|
Sec = Seconds % 60;
|
|
Seconds /= 60;
|
|
Min = Seconds % 60;
|
|
Seconds /= 60;
|
|
Hour = Seconds % 24;
|
|
Days = Seconds / 24;
|
|
|
|
// Find year number (1980 = 0)
|
|
//
|
|
Year = (Days / FourYear) * 4;
|
|
Days %= FourYear;
|
|
|
|
for (i = 1; i < 4; i++)
|
|
if (Days < YearTab[i])
|
|
break;
|
|
|
|
i--;
|
|
Year += i;
|
|
Days -= YearTab[i];
|
|
|
|
if (Year + 1980 > 2099)
|
|
return FALSE;
|
|
|
|
// Find month (jan == 1)
|
|
//
|
|
if (Year % 4) { // Non Leap year
|
|
for (i = 1; i < 12; i++)
|
|
if (Days < MonthTab[i])
|
|
break;
|
|
|
|
Month = i;
|
|
Day = Days - MonthTab[i - 1] + 1;
|
|
}
|
|
else {
|
|
for (i = 1; i < 12; i++)
|
|
if (Days < LeapmTab[i])
|
|
break;
|
|
|
|
Month = i;
|
|
Day = Days - LeapmTab[i - 1] + 1;
|
|
}
|
|
|
|
// The Dos time and date are stored in two packed 16-bit words
|
|
// as follows:
|
|
// Date: | 9-15 Year | 5-8 Month | 0-4 Day |
|
|
// Time: | 11-15 Hour| 5-10 Min | 0-4 Sec |
|
|
// Year 1980 = 0
|
|
// Month jan = 1
|
|
// Day first = 1
|
|
// Hours 0-23
|
|
// Min 0-59
|
|
// Seconds are delinated in 2sec increments (0-29).
|
|
//
|
|
*lpFatTime= (WORD) ((Hour << 11) + (Min << 5) + Sec / 2);
|
|
*lpFatDate= (WORD) ((Year << 9) + (Month << 5) + Day);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
#pragma SEG(CoDosDateTimeToFileTime)
|
|
STDAPI_(BOOL) CoDosDateTimeToFileTime(
|
|
WORD nDosDate, WORD nDosTime, FILETIME FAR* lpFileTime)
|
|
{
|
|
DWORD Year,Month,Day,Hour,Min,Sec;
|
|
DWORD Days, Seconds;
|
|
DWORD LowNs, HighNs;
|
|
|
|
if (!IsValidPtrOut(lpFileTime, sizeof(*lpFileTime))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// Note that the following code works because 2000 is a leap year
|
|
// and DosDate year range is 1980 - 2099
|
|
//
|
|
// All operations done in Seconds, then multiply by 10^7.
|
|
//
|
|
// The Dos time and date are stored in two packed 16-bit words
|
|
// as follows:
|
|
// Date: | 9-15 Year | 5-8 Month | 0-4 Day |
|
|
// Time: | 11-15 Hour| 5-10 Min | 0-4 Sec |
|
|
// Year 1980 = 0
|
|
// Month jan = 1
|
|
// Day first = 1
|
|
// Hours 0-23
|
|
// Min 0-59
|
|
// Seconds are delinated in 2sec increments (0-29).
|
|
//
|
|
|
|
Year = ((nDosDate >> 9) & 0x0000007f);
|
|
Month = ((nDosDate >> 5) & 0x0000000f) - 1;
|
|
Day = ((nDosDate) & 0x0000001f) - 1;
|
|
|
|
Hour = ((nDosTime >> 11) & 0x0000001f);
|
|
Min = ((nDosTime >> 5) & 0x0000003f);
|
|
Sec = ((nDosTime << 1) & 0x0000003e);
|
|
|
|
if (Year < 0 || Month < 0 || Day < 0 || Hour < 0 || Min < 0 || Sec < 0 ||
|
|
Month > 11 || Day > 30 || Hour > 23 || Min > 59 || Sec > 59)
|
|
return FALSE;
|
|
|
|
if (Year + 1980 > 2099)
|
|
return FALSE;
|
|
|
|
//
|
|
// Calculate days since 1980
|
|
|
|
|
|
Days = (Year / 4) * FourYear + YearTab[Year % 4] +
|
|
((Year % 4) ? MonthTab[Month] : LeapmTab[Month]) + Day;
|
|
|
|
Seconds = ((Days * 24 + Hour) * 60 + Min) * 60 + Sec;
|
|
|
|
LowNs = L1980;
|
|
HighNs = H1980;
|
|
|
|
_asm {
|
|
mov ax,word ptr Seconds
|
|
mov bx,word ptr Seconds+2
|
|
|
|
; Multiply (bx:ax) by ONESEC.
|
|
; Note that for any time before year 2100 the bumber of seconds
|
|
; since 1-1-1980 multiplied by ONESEC0 < 2^48 (that is can be stored
|
|
; in three registers)
|
|
;
|
|
mov cx,ONESEC0
|
|
mul cx
|
|
mov di,dx
|
|
mov si,ax ; di:si = ax * ONESEC0
|
|
mov ax,bx
|
|
xor bx,bx
|
|
mul cx ; dx:ax = bx * ONESEC0
|
|
add di,ax
|
|
adc bx,dx ; bx:di:si = Seconds * ONESEC0
|
|
mov ax,si
|
|
mov cx,ONESEC1
|
|
mul cx
|
|
add word ptr LowNs,ax
|
|
adc word ptr LowNs+2,dx
|
|
adc word ptr HighNs,0
|
|
adc word ptr HighNs+2,0
|
|
mov ax,di
|
|
mul cx
|
|
add word ptr LowNs+2,ax
|
|
adc word ptr HighNs,dx
|
|
adc word ptr HighNs+2,0
|
|
mov ax,bx
|
|
mul cx
|
|
add word ptr HighNs,ax
|
|
adc word ptr HighNs+2,dx
|
|
}
|
|
|
|
lpFileTime->dwLowDateTime = LowNs;
|
|
lpFileTime->dwHighDateTime= HighNs;
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
#endif // WIN32
|
|
|
|
#pragma SEG(CoFileTimeNow)
|
|
|
|
//
|
|
// Get the current UTC time, in the FILETIME format.
|
|
//
|
|
|
|
STDAPI CoFileTimeNow(FILETIME *pfiletime )
|
|
{
|
|
|
|
// Validate the input
|
|
|
|
if (!IsValidPtrOut(pfiletime, sizeof(*pfiletime)))
|
|
{
|
|
return(E_INVALIDARG);
|
|
}
|
|
|
|
#ifdef WIN32
|
|
|
|
// Get the time in SYSTEMTIME format.
|
|
|
|
SYSTEMTIME stNow;
|
|
GetSystemTime(&stNow);
|
|
|
|
// Convert it to FILETIME format.
|
|
|
|
if( !SystemTimeToFileTime(&stNow, pfiletime) )
|
|
{
|
|
pfiletime->dwLowDateTime = 0;
|
|
pfiletime->dwHighDateTime = 0;
|
|
return( HRESULT_FROM_WIN32( GetLastError() ));
|
|
}
|
|
else
|
|
return( NOERROR );
|
|
|
|
#else // WIN32
|
|
|
|
static struct _dosdate_t date; // declared static so it will be in
|
|
static struct _dostime_t time;
|
|
|
|
WORD wDate;
|
|
WORD wTime;
|
|
DWORD dw;
|
|
BOOL fHighBitSet;
|
|
|
|
_dos_getdate( &date );
|
|
_dos_gettime( &time );
|
|
|
|
// build wDate
|
|
wDate = date.day;
|
|
wDate |= (date.month << 5);
|
|
wDate |= ((date.year - 1980) << 9);
|
|
|
|
// build wTime;
|
|
wTime = time.second / 2;
|
|
wTime |= (time.minute << 5);
|
|
wTime |= (time.hour << 11);
|
|
|
|
|
|
if (!CoDosDateTimeToFileTime( wDate, wTime, pfiletime ))
|
|
{
|
|
return E_UNSPEC;
|
|
}
|
|
|
|
// so far our resolution is only 2 seconds.
|
|
dw = (time.second % 2)*100 + time.hsecond;
|
|
dw *= 10000;
|
|
// add the difference and check for carry
|
|
|
|
fHighBitSet = (((pfiletime->dwLowDateTime)& 0x80000000) != 0);
|
|
pfiletime->dwLowDateTime += dw;
|
|
if (fHighBitSet && ((pfiletime->dwLowDateTime & 0x80000000) == 0))
|
|
{
|
|
pfiletime->dwHighDateTime++;
|
|
}
|
|
|
|
return NOERROR;
|
|
|
|
#endif // WIN32
|
|
|
|
}
|
|
|