//////////////////////////////////////////////////////////////////////
|
//
|
// 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 <math.h>
|
//#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;
|
}
|