////////////////////////////////////////////////////////////////////// // // HighTime.cpp: implementation of the CHighTime and the CHighTimeSpan classes. // ////////////////////////////////////////////////////////////////////// // // CHighTime and CHighTimeSpan are two classes for high resolution time // The range is +/-29000 years and smallest step is 0.1 microsecond // They works like COleDateTime and COleDateTimeSpan. // I wrote these because MS could not write working time classes // // Author: Hakan Trygg, h.kan@home.se // Classes are not to be sold for profit. // Please send me a mail if you find it useful and using it // Revision history: // 1.0 : 12 Jan 2000 : /HT : Created // 1.1 : 19 Jan 2000 : /HT : Made it possible to use classes without MFC ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "HighTime.h" #include //#include "altcecrt.h" #define LLABS(i) (((i)<0)?-(i):(i)) ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// #define MAX_TIME_BUFFER_SIZE 128 // Constant array with months # of days of year int CHighTime::anMonthDayInYear[13] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; // Static member for getting the current time const CHighTime CHighTime::GetPresentTime(bool bLocal) { SYSTEMTIME systime; if(bLocal) ::GetLocalTime(&systime); else ::GetSystemTime(&systime); return CHighTime(systime); } // CHighTime::GetPresentTime() CHighTime::CHighTime(int nYear, int nMonth, int nDay, int nHour, int nMinute, int nSecond, int nMilli , int nMicro ,int nNano) // nMilli, nMicro & nNano default = 0 { _HighTimeFormat SrcTime; SrcTime.nYear = nYear; SrcTime.nMonth = nMonth; SrcTime.nDay = nDay; SrcTime.nHour = nHour; SrcTime.nMinute = nMinute; SrcTime.nSecond = nSecond; SrcTime.nMilli = nMilli; SrcTime.nMicro = nMicro; SrcTime.nNano = nNano; m_status = ConvertTimeToLongLong(SrcTime, m_liTime) ? valid : invalid; } // CHighTime::CHighTime() // CHighTime operators #if defined(USE_MFC) const CHighTime& CHighTime::operator=(const COleDateTime& dateSrc) { _HighTimeFormat SrcTime; SrcTime.nYear = dateSrc.GetYear(); SrcTime.nMonth = dateSrc.GetMonth(); SrcTime.nDay = dateSrc.GetDay(); SrcTime.nHour = dateSrc.GetHour(); SrcTime.nMinute = dateSrc.GetMinute(); SrcTime.nSecond = dateSrc.GetSecond(); SrcTime.nMilli = 0; SrcTime.nMicro = 0; SrcTime.nNano = 0; m_status = ConvertTimeToLongLong(SrcTime, m_liTime) ? valid : invalid; return *this; } // CHighTime::operator=() const CHighTime& CHighTime::operator=(const CTime& dateSrc) { _HighTimeFormat SrcTime; SrcTime.nYear = dateSrc.GetYear(); SrcTime.nMonth = dateSrc.GetMonth(); SrcTime.nDay = dateSrc.GetDay(); SrcTime.nHour = dateSrc.GetHour(); SrcTime.nMinute = dateSrc.GetMinute(); SrcTime.nSecond = dateSrc.GetSecond(); SrcTime.nMilli = 0; SrcTime.nMicro = 0; SrcTime.nNano = 0; m_status = ConvertTimeToLongLong(SrcTime, m_liTime) ? valid : invalid; return *this; } // CHighTime::operator=() #endif #ifdef OLEDBDECLSPEC const CHighTime& CHighTime::operator=(const DBTIMESTAMP &dateSrc) { _HighTimeFormat SrcTime; SrcTime.nYear = dateSrc.year; SrcTime.nMonth = dateSrc.month; SrcTime.nDay = dateSrc.day; SrcTime.nHour = dateSrc.hour; SrcTime.nMinute = dateSrc.minute; SrcTime.nSecond = dateSrc.second; SrcTime.nMilli = 0; SrcTime.nMicro = 0; SrcTime.nNano = 0; m_status = ConvertTimeToLongLong(SrcTime, m_liTime) ? valid : invalid; return *this; } #endif // OLEDBDECLSPEC const CHighTime& CHighTime::operator=(const SYSTEMTIME& systimeSrc) { _HighTimeFormat SrcTime; SrcTime.nYear = systimeSrc.wYear; SrcTime.nMonth = systimeSrc.wMonth; SrcTime.nDay = systimeSrc.wDay; SrcTime.nHour = systimeSrc.wHour; SrcTime.nMinute = systimeSrc.wMinute; SrcTime.nSecond = systimeSrc.wSecond; SrcTime.nMilli = systimeSrc.wMilliseconds; SrcTime.nMicro = 0; SrcTime.nNano = 0; m_status = ConvertTimeToLongLong(SrcTime, m_liTime) ? valid : invalid; return *this; } // CHighTime::operator=() const CHighTime& CHighTime::operator=(const DATE& date) { tm t; if(TmFromOleDate(date, t)) { _HighTimeFormat SrcTime; SrcTime.nYear = t.tm_year; SrcTime.nMonth = t.tm_mon; SrcTime.nDay = t.tm_mday; SrcTime.nHour = t.tm_hour; SrcTime.nMinute = t.tm_min; SrcTime.nSecond = t.tm_sec; SrcTime.nMilli = 0; SrcTime.nMicro = 0; SrcTime.nNano = 0; m_status = ConvertTimeToLongLong(SrcTime, m_liTime) ? valid : invalid; } else { SetStatus(invalid); } return *this; } const CHighTime& CHighTime::operator=(const FILETIME& filetimeSrc) { SYSTEMTIME systime; if (FileTimeToSystemTime(&filetimeSrc, &systime)) { _HighTimeFormat SrcTime; SrcTime.nYear = systime.wYear; SrcTime.nMonth = systime.wMonth; SrcTime.nDay = systime.wDay; SrcTime.nHour = systime.wHour; SrcTime.nMinute = systime.wMinute; SrcTime.nSecond = systime.wSecond; SrcTime.nMilli = systime.wMilliseconds; SrcTime.nMicro = 0; SrcTime.nNano = 0; m_status = ConvertTimeToLongLong(SrcTime, m_liTime) ? valid : invalid; } else { SetStatus(invalid); } return *this; } // CHighTime::operator=() /* const CHighTime& CHighTime::operator=(const time_t& timeSrc) { tm *pTimeSrc = localtime(&timeSrc); if (pTimeSrc) { _HighTimeFormat SrcTime; SrcTime.nYear = pTimeSrc->tm_year+1900; SrcTime.nMonth = pTimeSrc->tm_mon+1; SrcTime.nDay = pTimeSrc->tm_mday; SrcTime.nHour = pTimeSrc->tm_hour; SrcTime.nMinute = pTimeSrc->tm_min; SrcTime.nSecond = pTimeSrc->tm_sec; SrcTime.nMilli = 0; SrcTime.nMicro = 0; SrcTime.nNano = 0; m_status = ConvertTimeToLongLong(SrcTime, m_liTime) ? valid : invalid; } else { // Local time must have failed (timsSrc before 1/1/70 12am) SetStatus(invalid); ASSERT(FALSE); } return *this; } // CHighTime::operator=(time_t) */ int CHighTime::SetDateTime(int nYear, int nMonth, int nDay, int nHour, int nMinute, int nSecond, int nMilli, int nMicro, int nNano) // nMilli, nMicro & nHundredsNano default = 0 { _HighTimeFormat SrcTime; SrcTime.nYear = nYear; SrcTime.nMonth = nMonth; SrcTime.nDay = nDay; SrcTime.nHour = nHour; SrcTime.nMinute = nMinute; SrcTime.nSecond = nSecond; SrcTime.nMilli = nMilli; SrcTime.nMicro = nMicro; SrcTime.nNano = nNano; return (m_status = ConvertTimeToLongLong(SrcTime, m_liTime) ? valid : invalid) == valid; } // CHighTime::SetDateTime() // HighTime helper function, static function BOOL CHighTime::ConvertTimeToLongLong(const _HighTimeFormat &SrcTime, LARGE_INTEGER &liDestTime) { LARGE_INTEGER nDate; int iDays = SrcTime.nDay; UINT nHour = SrcTime.nHour; UINT nMinute = SrcTime.nMinute; UINT nSecond = SrcTime.nSecond; UINT nMilliSecond = SrcTime.nMilli; UINT nMicroSecond = SrcTime.nMicro; UINT nHundredsNano = (SrcTime.nNano +50) / 100; // Validate year and month if (SrcTime.nYear > 29000 || SrcTime.nYear < -29000 || SrcTime.nMonth < 1 || SrcTime.nMonth > 12) return FALSE; // Check for leap year BOOL bIsLeapYear = ((SrcTime.nYear & 3) == 0) && ((SrcTime.nYear % 100) != 0 || (SrcTime.nYear % 400) == 0); /*int nDaysInMonth = anMonthDayInYear[SrcTime.nMonth] - anMonthDayInYear[SrcTime.nMonth-1] + ((bIsLeapYear && SrcTime.nDay == 29 && SrcTime.nMonth == 2) ? 1 : 0);*/ // Adjust time and frac time nMicroSecond += nHundredsNano / 10; nHundredsNano %= 10; nMilliSecond += nMicroSecond / 1000; nMicroSecond %= 1000; nSecond +=nMilliSecond / 1000; nMilliSecond %= 1000; nMinute += nSecond / 60; nSecond %= 60; nHour += nMinute / 60; nMinute %= 60; iDays += nHour / 24; nHour %= 24; //It is a valid date; make Jan 1, 1AD be 1 nDate.QuadPart = SrcTime.nYear*365L + SrcTime.nYear/4 - SrcTime.nYear/100 + SrcTime.nYear/400 + anMonthDayInYear[SrcTime.nMonth-1] + iDays; // If leap year and it's before March, subtract 1: if (SrcTime.nMonth <= 2 && bIsLeapYear) --nDate.QuadPart; // Offset so that 01/01/1601 is 0 nDate.QuadPart -= 584754L; // Change nDate to seconds nDate.QuadPart *= 86400L; nDate.QuadPart += (nHour * 3600L) + (nMinute * 60L) + nSecond; // Change nDate to hundreds of nanoseconds nDate.QuadPart *= 10000000L; nDate.QuadPart += (nMilliSecond * 10000L) + (nMicroSecond * 10L) + nHundredsNano; liDestTime = nDate; return TRUE; } // CHighTime::ConvertTimeToLongLong() BOOL CHighTime::ConvertLongLongToTime(const LARGE_INTEGER &liSrcTime, _HighTimeFormat &DestTime) { LARGE_INTEGER nTempTime; long nDaysAbsolute; // Number of days since 1/1/0 long nSecsInDay; // Time in seconds since midnight long nMinutesInDay; // Minutes in day long n400Years; // Number of 400 year increments since 1/1/0 long n400Century; // Century within 400 year block (0,1,2 or 3) long n4Years; // Number of 4 year increments since 1/1/0 long n4Day; // Day within 4 year block // (0 is 1/1/yr1, 1460 is 12/31/yr4) long n4Yr; // Year within 4 year block (0,1,2 or 3) BOOL bLeap4 = TRUE; // TRUE if 4 year block includes leap year long nHNanosThisDay; long nMillisThisDay; nTempTime = liSrcTime; nHNanosThisDay = (long)(nTempTime.QuadPart % 10000000L); nTempTime.QuadPart /= 10000000L; nSecsInDay = (long)(nTempTime.QuadPart % 86400L); nTempTime.QuadPart /= 86400L; nDaysAbsolute = (long)(nTempTime.QuadPart); nDaysAbsolute += 584754L; // Add days from 1/1/0 to 01/01/1601 // Calculate the day of week (sun=1, mon=2...) // -1 because 1/1/0 is Sat. +1 because we want 1-based DestTime.nDayOfWeek = (int)((nDaysAbsolute - 1) % 7L) + 1; // Leap years every 4 yrs except centuries not multiples of 400. n400Years = (long)(nDaysAbsolute / 146097L); // Set nDaysAbsolute to day within 400-year block nDaysAbsolute %= 146097L; // -1 because first century has extra day n400Century = (long)((nDaysAbsolute - 1) / 36524L); // Non-leap century if (n400Century != 0) { // Set nDaysAbsolute to day within century nDaysAbsolute = (nDaysAbsolute - 1) % 36524L; // +1 because 1st 4 year increment has 1460 days n4Years = (long)((nDaysAbsolute + 1) / 1461L); if (n4Years != 0) n4Day = (long)((nDaysAbsolute + 1) % 1461L); else { bLeap4 = FALSE; n4Day = (long)nDaysAbsolute; } } else { // Leap century - not special case! n4Years = (long)(nDaysAbsolute / 1461L); n4Day = (long)(nDaysAbsolute % 1461L); } if (bLeap4) { // -1 because first year has 366 days n4Yr = (n4Day - 1) / 365; if (n4Yr != 0) n4Day = (n4Day - 1) % 365; } else { n4Yr = n4Day / 365; n4Day %= 365; } // n4Day is now 0-based day of year. Save 1-based day of year, year number DestTime.nDayOfYear = (int)n4Day + 1; DestTime.nYear = n400Years * 400 + n400Century * 100 + n4Years * 4 + n4Yr; // Handle leap year: before, on, and after Feb. 29. if (n4Yr == 0 && bLeap4) { // Leap Year if (n4Day == 59) { /* Feb. 29 */ DestTime.nMonth = 2; DestTime.nDay = 29; goto DoTime; } // Pretend it's not a leap year for month/day comp. if (n4Day >= 60) --n4Day; } // Make n4DaY a 1-based day of non-leap year and compute // month/day for everything but Feb. 29. ++n4Day; // Month number always >= n/32, so save some loop time */ for (DestTime.nMonth = (n4Day >> 5) + 1; n4Day > anMonthDayInYear[DestTime.nMonth]; DestTime.nMonth++); DestTime.nDay = (int)(n4Day - anMonthDayInYear[DestTime.nMonth-1]); DoTime: if (nSecsInDay == 0) DestTime.nHour = DestTime.nMinute = DestTime.nSecond = 0; else { DestTime.nSecond = (UINT)nSecsInDay % 60L; nMinutesInDay = nSecsInDay / 60L; DestTime.nMinute = (UINT)nMinutesInDay % 60; DestTime.nHour = (UINT)nMinutesInDay / 60; } if (nHNanosThisDay == 0) DestTime.nMilli = DestTime.nMicro = DestTime.nNano = 0; else { DestTime.nNano = (UINT)((nHNanosThisDay % 10L) * 100L); nMillisThisDay = nHNanosThisDay / 10L; DestTime.nMicro = (UINT)nMillisThisDay % 1000; DestTime.nMilli = (UINT)nMillisThisDay / 1000; } return TRUE; } // CHighTime::ConvertLongLongToTime() void CHighTime::ConvertToStandardFormat(_HighTimeFormat &tmTempHigh, tm &tmSrc) { // Convert internal tm to format expected by runtimes (sfrtime, etc) tmSrc.tm_year = tmTempHigh.nYear-1900; // year is based on 1900 tmSrc.tm_mon = tmTempHigh.nMonth-1; // month of year is 0-based tmSrc.tm_wday = tmTempHigh.nDayOfWeek-1; // day of week is 0-based tmSrc.tm_yday = tmTempHigh.nDayOfYear-1; // day of year is 0-based tmSrc.tm_mday = tmTempHigh.nDay; tmSrc.tm_hour = tmTempHigh.nHour; tmSrc.tm_min = tmTempHigh.nMinute; tmSrc.tm_sec = tmTempHigh.nSecond; tmSrc.tm_isdst = 0; } // CHighTime::ConvertToStandardFormat() int CHighTime::GetYear() const { _HighTimeFormat tmTemp; if (GetStatus() == valid && ConvertLongLongToTime(m_liTime, tmTemp)) return tmTemp.nYear; else return HIGH_DATETIME_ERROR; } // CHighTime::GetYear() int CHighTime::GetMonth() const // month of year (1 = Jan) { _HighTimeFormat tmTemp; if (GetStatus() == valid && ConvertLongLongToTime(m_liTime, tmTemp)) return tmTemp.nMonth; else return HIGH_DATETIME_ERROR; } // CHighTime::GetMonth() int CHighTime::GetDay() const // day of month (0-31) { _HighTimeFormat tmTemp; if (GetStatus() == valid && ConvertLongLongToTime(m_liTime, tmTemp)) return tmTemp.nDay; else return HIGH_DATETIME_ERROR; } // CHighTime::GetDay() int CHighTime::GetHour() const // hour in day (0-23) { _HighTimeFormat tmTemp; if (GetStatus() == valid && ConvertLongLongToTime(m_liTime, tmTemp)) return tmTemp.nHour; else return HIGH_DATETIME_ERROR; } // CHighTime::GetHour() int CHighTime::GetMinute() const // minute in hour (0-59) { _HighTimeFormat tmTemp; if (GetStatus() == valid && ConvertLongLongToTime(m_liTime, tmTemp)) return tmTemp.nMinute; else return HIGH_DATETIME_ERROR; } // CHighTime::GetMinute() int CHighTime::GetSecond() const // second in minute (0-59) { _HighTimeFormat tmTemp; if (GetStatus() == valid && ConvertLongLongToTime(m_liTime, tmTemp)) return tmTemp.nSecond; else return HIGH_DATETIME_ERROR; } // CHighTime::GetSecond() int CHighTime::GetMilliSecond() const // millisecond in minute (0-999) { _HighTimeFormat tmTemp; if (GetStatus() == valid && ConvertLongLongToTime(m_liTime, tmTemp)) return tmTemp.nMilli; else return HIGH_DATETIME_ERROR; } // CHighTime::GetMilliSecond() int CHighTime::GetMicroSecond() const // microsecond in minute (0-999) { _HighTimeFormat tmTemp; if (GetStatus() == valid && ConvertLongLongToTime(m_liTime, tmTemp)) return tmTemp.nMicro; else return HIGH_DATETIME_ERROR; } // CHighTime::GetMicroSecond() int CHighTime::GetNanoSecond() const // nanosecond in minute (0-999), step of 100ns { _HighTimeFormat tmTemp; if (GetStatus() == valid && ConvertLongLongToTime(m_liTime, tmTemp)) return tmTemp.nNano; else return HIGH_DATETIME_ERROR; } // CHighTime::GetNanoSecond() int CHighTime::GetDayOfWeek() const // 1=Sun, 2=Mon, ..., 7=Sat { _HighTimeFormat tmTemp; if (GetStatus() == valid && ConvertLongLongToTime(m_liTime, tmTemp)) return tmTemp.nDayOfWeek; else return HIGH_DATETIME_ERROR; } // CHighTime::GetDayOfWeek() int CHighTime::GetDayOfYear() const // days since start of year, Jan 1 = 1 { _HighTimeFormat tmTemp; if (GetStatus() == valid && ConvertLongLongToTime(m_liTime, tmTemp)) return tmTemp.nDayOfYear; else return HIGH_DATETIME_ERROR; } // CHighTime::GetDayOfYear() BOOL CHighTime::GetAsSystemTime(SYSTEMTIME& sysTime) const { BOOL bRetVal = FALSE; if (GetStatus() == valid) { _HighTimeFormat tmTemp; if (ConvertLongLongToTime(m_liTime, tmTemp)) { sysTime.wYear = (WORD) tmTemp.nYear; sysTime.wMonth = (WORD) tmTemp.nMonth; sysTime.wDayOfWeek = (WORD) (tmTemp.nDayOfWeek - 1); sysTime.wDay = (WORD) tmTemp.nDay; sysTime.wHour = (WORD) tmTemp.nHour; sysTime.wMinute = (WORD) tmTemp.nMinute; sysTime.wSecond = (WORD) tmTemp.nSecond; sysTime.wMilliseconds = (WORD)tmTemp.nMilli; bRetVal = TRUE; } } return bRetVal; } // CHighTime::GetAsSystemTime() // CHighTime math CHighTime CHighTime::operator+(const CHighTimeSpan &dateSpan) const { CHighTime dateResult; // Initializes m_status to valid // If either operand NULL, result NULL if (GetStatus() == null || dateSpan.GetStatus() == null) { dateResult.SetStatus(null); return dateResult; } // If either operand invalid, result invalid if (GetStatus() == invalid || dateSpan.GetStatus() == invalid) { dateResult.SetStatus(invalid); return dateResult; } // Compute the actual date difference by adding underlying dates dateResult.m_liTime.QuadPart = m_liTime.QuadPart + dateSpan.m_liSpan.QuadPart; // Validate within range //dateResult.CheckRange(); return dateResult; } // CHighTime::operator+() CHighTime CHighTime::operator-(const CHighTimeSpan &dateSpan) const { CHighTime dateResult; // Initializes m_status to valid // If either operand NULL, result NULL if (GetStatus() == null || dateSpan.GetStatus() == null) { dateResult.SetStatus(null); return dateResult; } // If either operand invalid, result invalid if (GetStatus() == invalid || dateSpan.GetStatus() == invalid) { dateResult.SetStatus(invalid); return dateResult; } // Compute the actual date difference by adding underlying dates dateResult.m_liTime.QuadPart = m_liTime.QuadPart - dateSpan.m_liSpan.QuadPart; // Validate within range //dateResult.CheckRange(); return dateResult; } // CHighTime::operator-() // CHighTimeSpan math CHighTimeSpan CHighTime::operator-(const CHighTime& date) const { CHighTimeSpan spanResult; // If either operand NULL, result NULL if (GetStatus() == null || date.GetStatus() == null) { spanResult.SetStatus(CHighTimeSpan::null); return spanResult; } // If either operand invalid, result invalid if (GetStatus() == invalid || date.GetStatus() == invalid) { spanResult.SetStatus(CHighTimeSpan::invalid); return spanResult; } spanResult.m_liSpan.QuadPart = m_liTime.QuadPart - date.m_liTime.QuadPart; return spanResult; } // CHighTime::operator-() // String helper functions int CHighTime::FindStr(LPCTSTR pszSource, LPCTSTR pszSub, int nStart) { int nLength = _tcslen(pszSource); if (nStart > nLength) return -1; // find first LPTSTR pszSearch = _tcsstr( (LPTSTR)pszSource + nStart, pszSub); // return -1 for not found return (pszSearch == NULL) ? -1 : (int)(pszSearch - pszSource); } // CHighTime::FindStr() int CHighTime::ReplaceStr(LPTSTR pszDest, int nDestSize, LPCTSTR pszMask, LPCTSTR pszSource) { int nCount, iInsertLen, iReplaceLen, iMoveLen, iDestLen; LPTSTR pSearch, pStartPos; nCount = 0; pStartPos = pszDest; while ( (pSearch = _tcsstr(pStartPos, pszMask)) != NULL) { pStartPos = pSearch + 1; ++nCount; } if (nCount > 0) { iReplaceLen = _tcslen(pszMask); iInsertLen = _tcslen(pszSource); // Can destination take the target? if ((int)_tcslen(pszDest) + nCount*(iInsertLen - iReplaceLen) > nDestSize) return 0; // no => do nothing iDestLen = _tcslen(pszDest); pStartPos = pszDest; while ( (pSearch = _tcsstr(pStartPos, pszMask)) != NULL) { iMoveLen = iDestLen - (pSearch - pszDest); if (iReplaceLen != iInsertLen ) { memmove(pSearch + (iInsertLen - iReplaceLen), pSearch, iMoveLen); iDestLen += iInsertLen - iReplaceLen; pszDest[iDestLen] = '\0'; } memcpy(pSearch, pszSource, iInsertLen); pStartPos = pSearch + 1; } } return nCount; } // CHighTime::ReplaceStr() // Formatting, Non MFC LPCTSTR CHighTime::Format(LPTSTR pBuffer, int iBufferLen, LPCTSTR pFormat) const { _HighTimeFormat tmHighTimeTemp; tm tmTemp; LPTSTR szTemp = NULL; int iPos; // If null, return empty string if (pBuffer == NULL || GetStatus() == null || iBufferLen <= 0) return NULL; if ( iBufferLen > sizeof(INVALID_DATETIME) ) return NULL; // If invalid, return DateTime resource string if (GetStatus() == invalid || !ConvertLongLongToTime(m_liTime, tmHighTimeTemp)) { _tcsncpy(pBuffer, INVALID_DATETIME, iBufferLen); return pBuffer; } if (iBufferLen <= 10) szTemp = new TCHAR[10]; else szTemp = new TCHAR[iBufferLen+1]; // Add milli, micro & nano part!!!!!! //%s for the millisecond part //%u for the microsecond part //%n for the nanosecond part _tcsncpy(pBuffer, pFormat, iBufferLen); iPos = FindStr(pBuffer, _T("%s"), 0); if (iPos >= 0) { wsprintf(szTemp,_T("%03d"),tmHighTimeTemp.nMilli); ReplaceStr(pBuffer, iBufferLen, _T("%s"), szTemp); } iPos = FindStr(pBuffer, _T("%#s"), 0); if (iPos >= 0) { wsprintf(szTemp, _T("%d"),tmHighTimeTemp.nMilli); ReplaceStr(pBuffer, iBufferLen, _T("%#s"), szTemp); } iPos = FindStr(pBuffer, _T("%u"), 0); if (iPos >= 0) { wsprintf(szTemp, _T("%03d"),tmHighTimeTemp.nMicro); ReplaceStr(pBuffer, iBufferLen, _T("%u"), szTemp); } iPos = FindStr(pBuffer, _T("%#u"), 0); if (iPos >= 0) { wsprintf(szTemp, _T("%d"),tmHighTimeTemp.nMicro); ReplaceStr(pBuffer, iBufferLen, _T("%#u"), szTemp); } iPos = FindStr(pBuffer, _T("%n"), 0); if (iPos >= 0) { wsprintf(szTemp, _T("%03d"),tmHighTimeTemp.nNano); ReplaceStr(pBuffer, iBufferLen, _T("%n"), szTemp); } iPos = FindStr(pBuffer, _T("%#n"), 0); if (iPos >= 0) { wsprintf(szTemp, _T("%d"),tmHighTimeTemp.nNano); ReplaceStr(pBuffer, iBufferLen, _T("%#n"), szTemp); } // Convert tm from internal format to standard format ConvertToStandardFormat(tmHighTimeTemp, tmTemp); // Fill in the buffer, disregard return value as it's not necessary _tcscpy(szTemp, pBuffer); // wcsftime(pBuffer, iBufferLen, szTemp, &tmTemp); delete [] szTemp; return pBuffer; } // CHighTime::Format() // formatting CString CHighTime::Format(LPCTSTR lpszFormat) const { CString szParse(lpszFormat); CString szTemp, strDate; _HighTimeFormat tmHighTimeTemp; tm tmTemp; int iPos; // If null, return empty string if (GetStatus() == null) return strDate; // If invalid, return DateTime resource string if (GetStatus() == invalid || !ConvertLongLongToTime(m_liTime, tmHighTimeTemp)) { // VERIFY(strDate.LoadString(AFX_IDS_INVALID_DATETIME)); return strDate; } // Add milli, micro & nano part!!!!!! //%s for the millisecond part //%u for the microsecond part //%n for the nanosecond part iPos = szParse.Find( _T("%s"), 0); if (iPos >= 0) { szTemp.Format(_T("%03d"),abs((int)tmHighTimeTemp.nMilli)); szParse.Replace(_T("%s"),szTemp); } iPos = szParse.Find(_T("%#s"), 0); if (iPos >= 0) { szTemp.Format(_T("%d"),abs((int)tmHighTimeTemp.nMilli)); szParse.Replace(_T("%#s"),szTemp); } iPos = szParse.Find(_T("%u"), 0); if (iPos >= 0) { szTemp.Format(_T("%03d"),abs((int)tmHighTimeTemp.nMicro)); szParse.Replace(_T("%u"),szTemp); } iPos = szParse.Find(_T("%#u"), 0); if (iPos >= 0) { szTemp.Format(_T("%d"),abs((int)tmHighTimeTemp.nMicro)); szParse.Replace(_T("%#u"),szTemp); } iPos = szParse.Find(_T("%n"), 0); if (iPos >= 0) { szTemp.Format(_T("%03d"),abs((int)tmHighTimeTemp.nNano)); szParse.Replace(_T("%n"),szTemp); } iPos = szParse.Find(_T("%#n"), 0); if (iPos >= 0) { szTemp.Format(_T("%d"),abs((int)tmHighTimeTemp.nNano)); szParse.Replace(_T("%#n"),szTemp); } // Convert tm from internal format to standard format ConvertToStandardFormat(tmHighTimeTemp, tmTemp); // Fill in the buffer, disregard return value as it's not necessary _tcsftime(strDate.GetBuffer(MAX_TIME_BUFFER_SIZE), MAX_TIME_BUFFER_SIZE, szParse.GetBuffer(szParse.GetLength()), &tmTemp); szParse.ReleaseBuffer(); strDate.ReleaseBuffer(); return strDate; } // CHighTime::Format() CString CHighTime::Format(UINT nFormatID) const { CString strFormat; strFormat.LoadString(nFormatID); return Format(strFormat); } // CHighTime::Format() CString CHighTime::Format( DWORD dwFlags, LCID lcid ) const { CString strDate; // If null, return empty string if (GetStatus() == null) return strDate; // If invalid, return DateTime resource string if (GetStatus() == invalid) { return strDate; } DATE date = (DATE)*this; BSTR bstr; if (FAILED(VarBstrFromDate(date, lcid, dwFlags, &bstr))) return strDate; strDate = bstr; SysFreeString(bstr); return strDate; } CString CHighTime::FormatGmt(LPCTSTR lpszFormat) const { CHighTime htTemp = *this; if ( htTemp.GmtTime() ) return htTemp.Format( lpszFormat ); return _T(""); } CString CHighTime::FormatGmt(UINT nFormatID) const { CString strFormat; strFormat.LoadString( nFormatID ); return FormatGmt( strFormat ); } CString CHighTime::FormatGmt( DWORD dwFlags, LCID lcid ) const { CHighTime htTemp = *this; if (htTemp.GmtTime() ) return htTemp.Format(dwFlags, lcid ); return _T(""); } #if defined(USE_MFC) // serialization #ifdef _DEBUG /*CDumpContext& AFXAPI operator<<(CDumpContext& dc, CHighTime dateSrc) { dc << "\nCHighTime Object:"; dc << "\n\tm_status = " << (long)dateSrc.m_status; dc << "\n\tdate = " << dateSrc.m_liTime.HighPart; return dc << "." << dateSrc.m_liTime.LowPart; }*/ // operator<<(CDumpContext, CHighTime) #endif // _DEBUG CArchive& AFXAPI operator<<(CArchive& ar, CHighTime dateSrc) { ar << (long)dateSrc.m_status; ar << dateSrc.m_liTime.HighPart; return ar << dateSrc.m_liTime.LowPart; } // operator<<(CArchive, CHighTime) CArchive& AFXAPI operator>>(CArchive& ar, CHighTime& dateSrc) { ar >> (long&)dateSrc.m_status; ar >> dateSrc.m_liTime.HighPart; return ar >> dateSrc.m_liTime.LowPart; } // operator>>(CArchive, CHighTime) #endif // defined(USE_MFC) // ****************************** // HighTimeSpan class // ****************************** void CHighTimeSpan::SetHighTimeSpan(long lDays, int nHours, int nMinutes, int nSeconds, int nMillis, int nMicros, int nNanos) // Milli, Micro & nano, default = 0 { int nHundredsNanos; if (nNanos >= 0) nHundredsNanos = (nNanos+50) / 100; else nHundredsNanos = (nNanos-50) / 100; nMicros += nHundredsNanos / 10; nHundredsNanos %= 10; nMillis += nMicros / 1000; nMicros %= 1000; nSeconds +=nMillis / 1000; nMillis %= 1000; nMinutes += nSeconds / 60; nSeconds %= 60; nHours += nMinutes / 60; nMinutes %= 60; lDays += nHours / 24; nHours %= 24; m_liSpan.QuadPart = lDays; m_liSpan.QuadPart *= 86400L; m_liSpan.QuadPart += (nHours * 3600L) + (nMinutes * 60) + nSeconds; m_liSpan.QuadPart *= 10000000L; m_liSpan.QuadPart += (nMillis * 10000L) + (nMicros * 10L) + nHundredsNanos; SetStatus(valid); } // CHighTimeSpan::SetHighTimeSpan() LONGLONG CHighTimeSpan::GetTotalDays() const // span in days (about -3.65e6 to 3.65e6) { LONGLONG liTemp; liTemp = m_liSpan.QuadPart / 10000000L; liTemp /= 86400L; return liTemp; } // CHighTimeSpan::GetTotalDays() LONGLONG CHighTimeSpan::GetTotalHours() const // span in hours (about -8.77e7 to 8.77e6) { LONGLONG liTemp; liTemp = m_liSpan.QuadPart / 10000000L; liTemp /= 3600L; return liTemp; } // CHighTimeSpan::GetTotalHours() LONGLONG CHighTimeSpan::GetTotalMinutes() const // span in minutes (about -5.26e9 to 5.26e9) { LONGLONG liTemp; liTemp = m_liSpan.QuadPart / 10000000L; liTemp /= 60L; return liTemp; } // CHighTimeSpan::GetTotalMinutes() LONGLONG CHighTimeSpan::GetTotalSeconds() const // span in seconds (about -3.16e11 to 3.16e11) { LONGLONG liTemp; liTemp = m_liSpan.QuadPart / 10000000L; return liTemp; } // CHighTimeSpan::GetTotalSeconds() LONGLONG CHighTimeSpan::GetTotalMilliSeconds() const // span in milliseconds { LONGLONG liTemp; liTemp = m_liSpan.QuadPart / 10000L; return liTemp; } // CHighTimeSpan::GetTotalMilliSeconds() LONGLONG CHighTimeSpan::GetTotalMicroSeconds() const // span in microseconds { LONGLONG liTemp; liTemp = m_liSpan.QuadPart / 10L; return liTemp; } // CHighTimeSpan::GetTotalMicroSeconds() LONGLONG CHighTimeSpan::GetTotalNanoSeconds() const // span in nanoseconds { LONGLONG liTemp; liTemp = m_liSpan.QuadPart * 100L; return liTemp; } // CHighTimeSpan::GetTotalNanoSeconds() int CHighTimeSpan::GetDays() const // component days in span { LONGLONG liTemp; liTemp = m_liSpan.QuadPart / 10000000L; liTemp = (liTemp / 86400L); return (int)liTemp; } // CHighTimeSpan::GetDays() int CHighTimeSpan::GetHours() const // component hours in span (-23 to 23) { LONGLONG liTemp; liTemp = m_liSpan.QuadPart / 10000000L; liTemp = (liTemp % 86400L) / 3600; return (int)liTemp; } // CHighTimeSpan::GetHours() int CHighTimeSpan::GetMinutes() const // component minutes in span (-59 to 59) { LONGLONG liTemp; liTemp = m_liSpan.QuadPart / 10000000L; liTemp = (liTemp % 3600L) / 60; return (int)liTemp; } // CHighTimeSpan::GetMinutes() int CHighTimeSpan::GetSeconds() const // component seconds in span (-59 to 59) { LONGLONG liTemp; liTemp = m_liSpan.QuadPart / 10000000L; liTemp = (liTemp % 60L); return (int)liTemp; } // CHighTimeSpan::GetSeconds() int CHighTimeSpan::GetMilliSeconds() const // component Milliseconds in span (-999 to 999) { LONGLONG liTemp; liTemp = (m_liSpan.QuadPart % 10000000L) / 10000L; return (int)liTemp; } // CHighTimeSpan::GetMilliSeconds() int CHighTimeSpan::GetMicroSeconds() const // component Microseconds in span (-999 to 999) { LONGLONG liTemp; liTemp = (m_liSpan.QuadPart % 10000L) / 10L; return (int)liTemp; } // CHighTimeSpan::GetMicroSeconds() int CHighTimeSpan::GetNanoSeconds() const // component Nanoseconds in span (-900 to 900) { LONGLONG liTemp; liTemp = (m_liSpan.QuadPart % 10) * 100L; return (int)liTemp; } // CHighTimeSpan::GetNanoSeconds() // CHighTimeSpan math CHighTimeSpan CHighTimeSpan::operator+(const CHighTimeSpan& dateSpan) const { CHighTimeSpan dateSpanTemp; // If either operand Null, result Null if (GetStatus() == null || dateSpan.GetStatus() == null) { dateSpanTemp.SetStatus(null); return dateSpanTemp; } // If either operand Invalid, result Invalid if (GetStatus() == invalid || dateSpan.GetStatus() == invalid) { dateSpanTemp.SetStatus(invalid); return dateSpanTemp; } // Add spans and validate within legal range dateSpanTemp.m_liSpan.QuadPart = m_liSpan.QuadPart + dateSpan.m_liSpan.QuadPart; return dateSpanTemp; } // CHighTimeSpan::operator+() CHighTimeSpan CHighTimeSpan::operator-(const CHighTimeSpan& dateSpan) const { CHighTimeSpan dateSpanTemp; // If either operand Null, result Null if (GetStatus() == null || dateSpan.GetStatus() == null) { dateSpanTemp.SetStatus(null); return dateSpanTemp; } // If either operand Invalid, result Invalid if (GetStatus() == invalid || dateSpan.GetStatus() == invalid) { dateSpanTemp.SetStatus(invalid); return dateSpanTemp; } // Add spans and validate within legal range dateSpanTemp.m_liSpan.QuadPart = m_liSpan.QuadPart - dateSpan.m_liSpan.QuadPart; return dateSpanTemp; } // CHighTimeSpan::operator-() // formatting LPTSTR CHighTimeSpan::Format(LPTSTR pBuffer, int iBufferLen, LPCTSTR pFormat) const { CHighTime::_HighTimeFormat tmHighTimeTemp; tm tmTemp; int iPos; LPTSTR szTemp; // If null, return empty string if (pFormat == NULL || GetStatus() == null || iBufferLen <= 0) return NULL; // If invalid, return DateTimeSpan resource string if (GetStatus() == invalid || !CHighTime::ConvertLongLongToTime(m_liSpan, tmHighTimeTemp)) { _tcsncpy(pBuffer, INVALID_DATETIME, iBufferLen); return pBuffer; } // Add milli, micro & nano part!!!!!! //%D for the Days part //%s for the millisecond part //%u for the microsecond part //%n for the nanosecond part if (iBufferLen <= 10) szTemp = new TCHAR[10]; else szTemp = new TCHAR[iBufferLen+1]; _tcsncpy(pBuffer, pFormat, iBufferLen); iPos = CHighTime::FindStr(pBuffer, _T("%D"), 0); if (iPos >= 0) { wsprintf(szTemp,_T("%0d"),LLABS(GetDays())); CHighTime::ReplaceStr(pBuffer, iBufferLen, _T("%D"), szTemp); } iPos = CHighTime::FindStr(pBuffer, _T("%#D"), 0); if (iPos >= 0) { wsprintf(szTemp,_T("%d"),LLABS(GetDays())); CHighTime::ReplaceStr(pBuffer, iBufferLen, _T("%#D"), szTemp); } iPos = CHighTime::FindStr(pBuffer, _T("%s"), 0); if (iPos >= 0) { wsprintf(szTemp,_T("%03d"),LLABS(GetMilliSeconds())); CHighTime::ReplaceStr(pBuffer, iBufferLen, _T("%s"), szTemp); } iPos = CHighTime::FindStr(pBuffer, _T("%#s"), 0); if (iPos >= 0) { wsprintf(szTemp,_T("%d"),LLABS(GetMilliSeconds())); CHighTime::ReplaceStr(pBuffer, iBufferLen, _T("%#s"), szTemp); } iPos = CHighTime::FindStr(pBuffer, _T("%u"), 0); if (iPos >= 0) { wsprintf(szTemp,_T("%03d"),LLABS(GetMicroSeconds())); CHighTime::ReplaceStr(pBuffer, iBufferLen, _T("%u"), szTemp); } iPos = CHighTime::FindStr(pBuffer, _T("%#u"), 0); if (iPos >= 0) { wsprintf(szTemp,_T("%d"),LLABS(GetMicroSeconds())); CHighTime::ReplaceStr(pBuffer, iBufferLen, _T("%#u"), szTemp); } iPos = CHighTime::FindStr(pBuffer, _T("%n"), 0); if (iPos >= 0) { wsprintf(szTemp,_T("%03d"),LLABS(GetNanoSeconds())); CHighTime::ReplaceStr(pBuffer, iBufferLen, _T("%n"), szTemp); } iPos = CHighTime::FindStr(pBuffer, _T("%#n"), 0); if (iPos >= 0) { wsprintf(szTemp,_T("%d"),LLABS(GetNanoSeconds())); CHighTime::ReplaceStr(pBuffer, iBufferLen, _T("%#n"), szTemp); } // Convert tm from internal format to standard format tmTemp.tm_year = tmHighTimeTemp.nYear-1601; // year is based on 1900 tmTemp.tm_mon = tmHighTimeTemp.nMonth-1; // month of year is 0-based tmTemp.tm_wday = tmHighTimeTemp.nDayOfWeek-1; // day of week is 0-based tmTemp.tm_yday = tmHighTimeTemp.nDayOfYear-1; // day of year is 0-based tmTemp.tm_mday = tmHighTimeTemp.nDay; tmTemp.tm_hour = tmHighTimeTemp.nHour; tmTemp.tm_min = tmHighTimeTemp.nMinute; tmTemp.tm_sec = tmHighTimeTemp.nSecond; tmTemp.tm_isdst = 0; // Fill in the buffer, disregard return value as it's not necessary _tcscpy(szTemp, pBuffer); // strftime(pBuffer, iBufferLen, szTemp, &tmTemp); delete [] szTemp; return pBuffer; } // CHighTimeSpan::Format() CString CHighTimeSpan::Format(LPCTSTR pFormat) const { CString szParse(pFormat); CString szTemp, strSpan; CHighTime::_HighTimeFormat tmHighTimeTemp; tm tmTemp; int iPos; // If null, return empty string if (pFormat == NULL || GetStatus() == null) return strSpan; // If invalid, return DateTimeSpan resource string if (GetStatus() == invalid || !CHighTime::ConvertLongLongToTime(m_liSpan, tmHighTimeTemp)) { // VERIFY(strSpan.LoadString(AFX_IDS_INVALID_DATETIMESPAN)); return strSpan; } // Add milli, micro & nano part!!!!!! //%D for the Days part //%s for the millisecond part //%u for the microsecond part //%n for the nanosecond part iPos = szParse.Find( _T("%D"), 0); if (iPos >= 0) { szTemp.Format( _T("%0d"),LLABS(GetDays())); szParse.Replace( _T("%D"),szTemp); } iPos = szParse.Find( _T("%#D"), 0); if (iPos >= 0) { szTemp.Format( _T("%d"),LLABS(GetDays())); szParse.Replace( _T("%#D"),szTemp); } iPos = szParse.Find( _T("%s"), 0); if (iPos >= 0) { szTemp.Format( _T("%03d"),LLABS(GetMilliSeconds())); szParse.Replace( _T("%s"),szTemp); } iPos = szParse.Find( _T("%#s"), 0); if (iPos >= 0) { szTemp.Format( _T("%d"),LLABS(GetMilliSeconds())); szParse.Replace( _T("%#s"),szTemp); } iPos = szParse.Find( _T("%u"), 0); if (iPos >= 0) { szTemp.Format( _T("%03d"),LLABS(GetMicroSeconds())); szParse.Replace( _T("%u"),szTemp); } iPos = szParse.Find( _T("%#u"), 0); if (iPos >= 0) { szTemp.Format( _T("%d"),LLABS(GetMicroSeconds())); szParse.Replace( _T("%#u"),szTemp); } iPos = szParse.Find( _T("%n"), 0); if (iPos >= 0) { szTemp.Format( _T("%03d"),LLABS(GetNanoSeconds())); szParse.Replace( _T("%n"),szTemp); } iPos = szParse.Find( _T("%#n"), 0); if (iPos >= 0) { szTemp.Format( _T("%d"),LLABS(GetNanoSeconds())); szParse.Replace( _T("%#n"),szTemp); } // Convert tm from internal format to standard format tmTemp.tm_year = tmHighTimeTemp.nYear-1601; // year is based on 1900 tmTemp.tm_mon = tmHighTimeTemp.nMonth-1; // month of year is 0-based tmTemp.tm_wday = tmHighTimeTemp.nDayOfWeek-1; // day of week is 0-based tmTemp.tm_yday = tmHighTimeTemp.nDayOfYear-1; // day of year is 0-based tmTemp.tm_mday = tmHighTimeTemp.nDay; tmTemp.tm_hour = tmHighTimeTemp.nHour; tmTemp.tm_min = tmHighTimeTemp.nMinute; tmTemp.tm_sec = tmHighTimeTemp.nSecond; tmTemp.tm_isdst = 0; // Fill in the buffer, disregard return value as it's not necessary // strftime(strSpan.GetBuffer(MAX_TIME_BUFFER_SIZE), MAX_TIME_BUFFER_SIZE, // szParse.GetBuffer(szParse.GetLength()), &tmTemp); szParse.ReleaseBuffer(); strSpan.ReleaseBuffer(); return strSpan; } // CHighTimeSpan::Format() CString CHighTimeSpan::Format(UINT nID) const { CString sBuffer; sBuffer.LoadString(nID); Format(sBuffer); return sBuffer; } // CHighTimeSpan::Format() #if defined(USE_MFC) // serialization #ifdef _DEBUG /*CDumpContext& AFXAPI operator<<(CDumpContext& dc, CHighTimeSpan dateSpanSrc) { dc << "\nCHighTimeSpan Object:"; dc << "\n\tm_status = " << (long)dateSpanSrc.m_status; dc << "\n\tdateSpan = " << dateSpanSrc.m_liSpan.HighPart; return dc << "." << dateSpanSrc.m_liSpan.LowPart; } */// operator<<(CDumpContext, CHighTimeSpan) #endif // _DEBUG CArchive& AFXAPI operator<<(CArchive& ar, CHighTimeSpan dateSpanSrc) { ar << (long)dateSpanSrc.m_status; ar << dateSpanSrc.m_liSpan.HighPart; return ar << dateSpanSrc.m_liSpan.LowPart; } // operator<<(CArchive, CHighTimeSpan) CArchive& AFXAPI operator>>(CArchive& ar, CHighTimeSpan& dateSpanSrc) { ar >> (long&)dateSpanSrc.m_status; ar >> dateSpanSrc.m_liSpan.HighPart; return ar >> dateSpanSrc.m_liSpan.LowPart; } // operator>>(CArchive, CHighTimeSpan) #endif // defined(USE_MFC) // Verifies will fail if the needed buffer size is too large #define MAX_TIME_BUFFER_SIZE 128 // matches that in timecore.cpp #define MIN_DATE (-657434L) // about year 100 #define MAX_DATE 2958465L // about year 9999 // Half a second, expressed in days #define HALF_SECOND (1.0/172800.0) BOOL CHighTime::TmFromOleDate(DATE dtSrc, tm &tmDest) { // The legal range does not actually span year 0 to 9999. if (dtSrc > MAX_DATE || dtSrc < MIN_DATE) // about year 100 to about 9999 return FALSE; long nDays; // Number of days since Dec. 30, 1899 long nDaysAbsolute; // Number of days since 1/1/0 long nSecsInDay; // Time in seconds since midnight long nMinutesInDay; // Minutes in day long n400Years; // Number of 400 year increments since 1/1/0 long n400Century; // Century within 400 year block (0,1,2 or 3) long n4Years; // Number of 4 year increments since 1/1/0 long n4Day; // Day within 4 year block // (0 is 1/1/yr1, 1460 is 12/31/yr4) long n4Yr; // Year within 4 year block (0,1,2 or 3) BOOL bLeap4 = TRUE; // TRUE if 4 year block includes leap year double dblDate = dtSrc; // tempory serial date // If a valid date, then this conversion should not overflow nDays = (long)dblDate; // Round to the second dblDate += ((dtSrc > 0.0) ? HALF_SECOND : -HALF_SECOND); nDaysAbsolute = (long)dblDate + 693959L; // Add days from 1/1/0 to 12/30/1899 dblDate = fabs(dblDate); nSecsInDay = (long)((dblDate - floor(dblDate)) * 86400.); // Calculate the day of week (sun=1, mon=2...) // -1 because 1/1/0 is Sat. +1 because we want 1-based tmDest.tm_wday = (int)((nDaysAbsolute - 1) % 7L) + 1; // Leap years every 4 yrs except centuries not multiples of 400. n400Years = (long)(nDaysAbsolute / 146097L); // Set nDaysAbsolute to day within 400-year block nDaysAbsolute %= 146097L; // -1 because first century has extra day n400Century = (long)((nDaysAbsolute - 1) / 36524L); // Non-leap century if (n400Century != 0) { // Set nDaysAbsolute to day within century nDaysAbsolute = (nDaysAbsolute - 1) % 36524L; // +1 because 1st 4 year increment has 1460 days n4Years = (long)((nDaysAbsolute + 1) / 1461L); if (n4Years != 0) n4Day = (long)((nDaysAbsolute + 1) % 1461L); else { bLeap4 = FALSE; n4Day = (long)nDaysAbsolute; } } else { // Leap century - not special case! n4Years = (long)(nDaysAbsolute / 1461L); n4Day = (long)(nDaysAbsolute % 1461L); } if (bLeap4) { // -1 because first year has 366 days n4Yr = (n4Day - 1) / 365; if (n4Yr != 0) n4Day = (n4Day - 1) % 365; } else { n4Yr = n4Day / 365; n4Day %= 365; } // n4Day is now 0-based day of year. Save 1-based day of year, year number tmDest.tm_yday = (int)n4Day + 1; tmDest.tm_year = n400Years * 400 + n400Century * 100 + n4Years * 4 + n4Yr; // Handle leap year: before, on, and after Feb. 29. if (n4Yr == 0 && bLeap4) { // Leap Year if (n4Day == 59) { /* Feb. 29 */ tmDest.tm_mon = 2; tmDest.tm_mday = 29; goto DoTime; } // Pretend it's not a leap year for month/day comp. if (n4Day >= 60) --n4Day; } // Make n4DaY a 1-based day of non-leap year and compute // month/day for everything but Feb. 29. ++n4Day; // Month number always >= n/32, so save some loop time */ for (tmDest.tm_mon = (n4Day >> 5) + 1; n4Day > anMonthDayInYear[tmDest.tm_mon]; tmDest.tm_mon++); tmDest.tm_mday = (int)(n4Day - anMonthDayInYear[tmDest.tm_mon-1]); DoTime: if (nSecsInDay == 0) tmDest.tm_hour = tmDest.tm_min = tmDest.tm_sec = 0; else { tmDest.tm_sec = (int)nSecsInDay % 60L; nMinutesInDay = nSecsInDay / 60L; tmDest.tm_min = (int)nMinutesInDay % 60; tmDest.tm_hour = (int)nMinutesInDay / 60; } return TRUE; } BOOL CHighTime::OleDateFromTm(WORD wYear, WORD wMonth, WORD wDay, WORD wHour, WORD wMinute, WORD wSecond, DATE& dtDest) { // Validate year and month (ignore day of week and milliseconds) if (wYear > 9999 || wMonth < 1 || wMonth > 12) return FALSE; // Check for leap year and set the number of days in the month BOOL bLeapYear = ((wYear & 3) == 0) && ((wYear % 100) != 0 || (wYear % 400) == 0); int nDaysInMonth = anMonthDayInYear[wMonth] - anMonthDayInYear[wMonth-1] + ((bLeapYear && wDay == 29 && wMonth == 2) ? 1 : 0); // Finish validating the date if (wDay < 1 || wDay > nDaysInMonth || wHour > 23 || wMinute > 59 || wSecond > 59) { return FALSE; } // Cache the date in days and time in fractional days long nDate; double dblTime; //It is a valid date; make Jan 1, 1AD be 1 nDate = wYear*365L + wYear/4 - wYear/100 + wYear/400 + anMonthDayInYear[wMonth-1] + wDay; // If leap year and it's before March, subtract 1: if (wMonth <= 2 && bLeapYear) --nDate; // Offset so that 12/30/1899 is 0 nDate -= 693959L; dblTime = (((long)wHour * 3600L) + // hrs in seconds ((long)wMinute * 60L) + // mins in seconds ((long)wSecond)) / 86400.; dtDest = (double) nDate + ((nDate >= 0) ? dblTime : -dblTime); return TRUE; } bool CHighTime::ParseDateTime(LPCTSTR lpszDate, DWORD dwFlags) { CString strDate = lpszDate; BSTR sDate = strDate.AllocSysString( ); DATE dt = 0; SCODE sc; if (FAILED(sc = VarDateFromStr(sDate, LANG_USER_DEFAULT, dwFlags, &dt))) { if (sc == DISP_E_TYPEMISMATCH) { // Can't convert string to date, set 0 and invalidate dt = 0; SetStatus(invalid); SysFreeString( sDate ); return false; } else if (sc == DISP_E_OVERFLOW) { // Can't convert string to date, set -1 and invalidate dt = -1; SetStatus(invalid); SysFreeString( sDate ); return false; } else { TRACE( _T("\nCHighTime VarDateFromStr call failed.\n\t") ); dt = -1; SetStatus(invalid); SysFreeString( sDate ); return false; } } SetStatus(valid); *this = dt; SysFreeString( sDate ); return true; } bool CHighTime::GmtTime() { FILETIME fileTimeTemp; FILETIME fileTime = *this; // If null, return empty string if (GetStatus() == null) return false; // If invalid, return DateTime resource string if (GetStatus() == invalid) { return false; } if (!LocalFileTimeToFileTime(&fileTime, &fileTimeTemp ) ) return false; *this = fileTimeTemp; return true; } bool CHighTime::LocalTime() { FILETIME fileTimeTemp; FILETIME fileTime = *this; // If null, return empty string if (GetStatus() == null) return false; // If invalid, return DateTime resource string if (GetStatus() == invalid) { return false; } if (!FileTimeToLocalFileTime(&fileTime, &fileTimeTemp ) ) return false; *this = fileTimeTemp; return true; }