//+------------------------------------------------------------ // // File: time.cxx // // Contents: Component object model time utilities // // Functions: CoFileTimeToDosDateTime // CoDosDateTimeToFileTime // CoFileTimeNow // // History: 5-Apr-94 brucema Created // //------------------------------------------------------------- #include #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 // 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 }