📄 date.cpp
字号:
#include "stdafx.h"
#include "Date.h"
IMPLEMENT_SERIAL(CDate, CObject, 0)
/////////////////////////////////////////////////
// Constructors
CDate::CDate()
{
m_nYear = 0;
m_nMonth = 0;
m_nDay = 0;
// null date -- not valid as a date, but handy
}
CDate::CDate(CDate& Date)
{
m_nYear = Date.m_nYear;
m_nMonth = Date.m_nMonth;
m_nDay = Date.m_nDay;
}
CDate::CDate(CTime& Time)
{
m_nYear = Time.GetYear();
m_nMonth = Time.GetMonth();
m_nDay = Time.GetDay();
}
CDate::CDate(SWORD y, UWORD m, UWORD d):
m_nYear(y),
m_nMonth(m),
m_nDay(d)
{}
/////////////////////////////////////////////////
// Assignment operator
CDate& CDate::operator=(CDate& Date)
{
m_nYear = Date.m_nYear;
m_nMonth = Date.m_nMonth;
m_nDay = Date.m_nDay;
return *this;
}
/////////////////////////////////////////////////
// Increment & Decrement functions
void CDate::AddMonth()
{
if (m_nMonth > 11)
{
m_nMonth = 1;
m_nYear++;
}
else
m_nMonth++;
}
void CDate::SubtractMonth()
{
if (m_nMonth < 2)
{
m_nMonth = 12;
m_nYear--;
}
else
m_nMonth--;
}
void CDate::AddDay()
{
if (m_nDay < DaysInMonth())
m_nDay ++;
else
{
m_nDay = 1;
AddMonth();
}
}
void CDate::SubtractDay()
{
if (m_nDay > 1)
m_nDay--;
else
{
SubtractMonth();
m_nDay = DaysInMonth();
}
}
// prefix notation
CDate& CDate::operator++()
{
AddDay();
return *this;
}
// postfix notation
CDate& CDate::operator++(int)
{
CDate Old = *this;
AddDay();
return Old;
}
// prefix notation
CDate& CDate::operator--()
{
SubtractDay();
return *this;
}
// postfix notation
CDate& CDate::operator--(int)
{
CDate Old = *this;
SubtractDay();
return *this;
}
/////////////////////////////////////////////////
// Sum & Difference functions
CDate& CDate::operator+ (unsigned int Days)
{
UWORD DaysLeft = Days;
UWORD Days2First;
ASSERT (Days >= 0);
// If possible, bring the date to the next
// first of the month.
Days2First = DaysInMonth() - m_nDay + 1;
if ( DaysLeft > Days2First )
{
DaysLeft -= Days2First;
m_nDay = 1;
AddMonth();
}
// Remove the days a month at a time, if
// possible.
while ( DaysInMonth() <= DaysLeft )
{
DaysLeft -= DaysInMonth();
AddMonth();
}
m_nDay += DaysLeft;
return *this;
}
CDate& CDate::operator- (unsigned int Days)
{
UWORD DaysLeft = Days;
ASSERT (Days >= 0);
// If possible, bring the date to the
// last day of the previous month.
if ( DaysLeft >= m_nDay )
{
DaysLeft = DaysLeft - m_nDay;
m_nDay = 1;
SubtractDay();
}
// Remove the days a month at a time, if
// possible.
while ( DaysInMonth() <= DaysLeft )
{
DaysLeft -= DaysInMonth();
m_nDay = 1;
SubtractMonth();
}
m_nDay -= DaysLeft;
return *this;
}
int CDate::operator- (CDate& Date)
{
int Result = 0;
BOOL NegativeResult = TRUE;
CDate smallDate;
UWORD nTargetDay, nTargetMonth;
SWORD nTargetYear;
int LeapYearOffset;
// if the dates are in the same month/year
// the result is simply the difference between
// the m_nDay members
if ( (m_nYear == Date.m_nYear) &&
(m_nMonth == Date.m_nMonth) )
{
return m_nDay - Date.m_nDay;
}
// if, on the other hand, the dates are further
// apart we have to do some work ...
if (*this > Date)
{
smallDate = Date;
nTargetDay = m_nDay;
nTargetMonth = m_nMonth;
nTargetYear = m_nYear;
NegativeResult = FALSE;
}
else
{
smallDate = *this;
nTargetDay = Date.m_nDay;
nTargetMonth = Date.m_nMonth;
nTargetYear = Date.m_nYear;
}
// Move to the first of the next month so as
// to avoid any month length fluxuations
while ( smallDate.m_nDay != 1 )
{
smallDate.AddDay();
Result++;
}
// Add up the days a month at a time until
// we reach the target month.
while ( smallDate.m_nMonth != nTargetMonth )
{
Result += smallDate.DaysInMonth();
smallDate.AddMonth();
}
// Keep track of the leap year calculations
if (nTargetMonth < 3)
LeapYearOffset = 0;
else
LeapYearOffset = 1;
// Add up the days a year at a time until
// we reach the target year.
while ( smallDate.m_nYear != nTargetYear )
{
// if leap year affects calculation add 366 days
if (CDate::IsLeapYear(smallDate.m_nYear + LeapYearOffset) )
{
Result += 366;
}
// otherwise add 365
else
{
Result += 365;
}
smallDate.m_nYear++;
}
// At this point we are at the first of the target
// month and year -- so we may simply add the target
// day minus one.
Result += nTargetDay - 1;
// Result is computed absolutely but must be
// returned with a sign!
if (NegativeResult)
return -Result;
else
return Result;
}
void CDate::Subtract (CDate& Date, UWORD& Years, UWORD& Months, UWORD& Days)
{
UWORD nDayTarget;
CDate largeDate;
int nMonthCount = 0, nYearCount = 0, nDayCount = 0;
// if the dates are equal, zero the differences
if (*this == Date)
{
Years = 0;
Months = 0;
Days = 0;
return;
}
// order the two dates
if (*this > Date)
{
largeDate = *this;
nDayTarget = Date.m_nDay;
nYearCount = m_nYear - Date.m_nYear;
nMonthCount = m_nMonth - Date.m_nMonth;
}
else
{
largeDate = Date;
nDayTarget = m_nDay;
nYearCount = Date.m_nYear - m_nYear;
nMonthCount = Date.m_nMonth - m_nMonth;
}
// change largeDate's Day to the target day,
// keeping track of the counts.
if (largeDate.m_nDay >= nDayTarget)
{
while ( largeDate.m_nDay > nDayTarget )
{
largeDate.SubtractDay();
nDayCount++;
}
}
else
{
while ( largeDate.m_nDay < nDayTarget )
{
largeDate.AddDay();
nDayCount--;
}
largeDate.m_nMonth--;
nDayCount += largeDate.DaysInMonth();
nMonthCount--;
}
// adjust the counts to be in proper form
if ( nMonthCount < 0 )
{
nMonthCount += 12;
nYearCount--;
}
Days = nDayCount;
Years = nYearCount;
Months = nMonthCount;
}
void CDate::Add (SWORD Years, SWORD Months, SWORD Days)
{
// first add the years -- no problems here
m_nYear += Years;
if (Months < 0)
{
// if Months is negative perform subtraction
// decrementing the year as necessary
Months = abs(Months);
while (m_nMonth <= (UWORD)Months)
{
Months -= 12;
m_nYear--;
}
m_nMonth -= Months;
}
else if (Months > 0)
{
// if Months is positive perform addition
// incrementing the year as necessary
m_nMonth += Months;
while (m_nMonth > 12)
{
m_nMonth -= 12;
m_nYear++;
}
}
// make sure the day is valid
if (m_nDay > DaysInMonth())
m_nDay = DaysInMonth();
if (Days == 0)
return;
if (Days < 0)
for (int i = 1; i <= abs(Days); i++)
SubtractDay();
else
for (int i = 1; i <= Days; i++)
AddDay();
}
/////////////////////////////////////////////////
// Comparison operators
BOOL CDate::operator== (CDate& Date)
{
return (m_nYear == Date.m_nYear) &&
(m_nMonth == Date.m_nMonth) &&
(m_nDay == Date.m_nDay);
}
BOOL CDate::operator!= (CDate& Date)
{
return ( !(operator==(Date)) );
}
BOOL CDate::operator> (CDate& Date)
{
if (m_nYear == Date.m_nYear)
if (m_nMonth == Date.m_nMonth)
return m_nDay > Date.m_nDay;
else
return m_nMonth > Date.m_nMonth;
else
return m_nYear > Date.m_nYear;
}
BOOL CDate::operator>= (CDate& Date)
{
return ( !(operator<(Date)) );
}
BOOL CDate::operator< (CDate& Date)
{
if (m_nYear == Date.m_nYear)
if (m_nMonth == Date.m_nMonth)
return m_nDay < Date.m_nDay;
else
return m_nMonth < Date.m_nMonth;
else
return m_nYear < Date.m_nYear;
}
BOOL CDate::operator<= (CDate& Date)
{
return ( !(operator>(Date)) );
}
/////////////////////////////////////////////////
// Miscelaneous support functions
BOOL CDate::IsValid()
{
// IsValid is aka Vali_Date
if (m_nMonth < 1 || m_nMonth > 12)
return FALSE;
if (m_nDay > 0 && m_nDay <= DaysInMonth())
return TRUE;
else
return FALSE;
// note that a null date is not valid
}
void CDate::MakeValid()
{
if (m_nMonth < 1)
m_nMonth = 1;
// Note that m_nMonth can't be less than 0
// since UWORD is unsigned
// cycle any excess months into years
while (m_nMonth > 12)
{
m_nMonth -= 12;
m_nYear++;
}
// clip the days to fit in the month
if (m_nDay < 1)
m_nDay = 1;
else if (m_nDay > DaysInMonth())
m_nDay = DaysInMonth();
}
int CDate::IsLeapYear(SWORD y)
{
// Perform standard leap year calculations
// leap years occur on years divisible by 4 ...
if (y % 4 != 0)
return FALSE;
else
{
// ... unless it抯 a century year ...
if (y % 100 != 0)
return TRUE;
// ... where it must be divisible by 400
else if (y % 400 != 0)
return FALSE;
else
return TRUE;
}
}
UWORD CDate::DaysInMonth()
{
switch (m_nMonth)
{
case 2:
if (IsLeapYear(m_nYear))
return 29;
else
return 28;
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return 31;
}
}
/////////////////////////////////////////////////
// Format functions
CString CDate::DateString (const char* Format)
{
const BuffLen = 128;
CString S = "NULL DATE";
if (*this == CDate())
return S;
char* pszS = S.GetBuffer(BuffLen);
struct tm Date = {0,0,0,m_nDay,m_nMonth-1,m_nYear-1900,0,0,0};
strftime(pszS, BuffLen-1, Format, &Date);
S.ReleaseBuffer();
return S;
}
BOOL CDate::StringToDate (const char* strDate)
{
CString S = strDate, tempS;
const char* Months[] =
{"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
int Numbers[3];
const char* NumSet = "0123456789";
int Pos;
int Month = 0;
S.MakeUpper();
for (int i = 0; i < 12; i++)
{
Pos = S.Find(Months[i]);
if (Pos > 0)
Month = i+1;
}
// Parse strDate looking for numbers that may
// coorespond to date values.
i = 0;
while (!S.IsEmpty())
{
tempS = S.SpanIncluding(NumSet);
if (tempS.IsEmpty())
{
S = S.Right(S.GetLength()-1);
}
else
{
Numbers[i] = atoi(tempS);
i++;
if (i>2)
break;
S = S.Right(S.GetLength()-tempS.GetLength());
}
}
CDate testDate;
if (Month)
testDate = CDate(Numbers[1], Month, Numbers[0]);
else
testDate = CDate(Numbers[2], Numbers[0], Numbers[1]);
// two-digit dates are automatically converted to
// twentieth century dates.
if (testDate.m_nYear < 100)
testDate.m_nYear += 1900;
if (testDate.IsValid())
{
*this = testDate;
return TRUE;
}
else
return FALSE;
}
/////////////////////////////////////////////////
// Debug function overrides
#ifdef _DEBUG
void CDate::Dump(CDumpContext& dc) const
{
// first call the ancestor's Dump()
CObject::Dump(dc);
dc << "Year: " << m_nYear << " Month: " << m_nMonth
<< " Day: " << m_nDay << "\n";
}
void CDate::AssertValid() const
{
CDate* pD = (CDate*)this;
// first call the ancestor's AssertValid()
CObject::AssertValid();
// if date is null, don't halt the program
// a null date is valid in this sense
if ( pD->operator==(CDate()) )
return;
ASSERT(pD->IsValid());
}
#endif
void CDate::Serialize( CArchive& ar)
{
// serialize the base class first
CObject::Serialize( ar );
// convert m_nYear to a CArchive-friendly type
long y = (long)m_nYear;
if ( ar.IsStoring() )
ar << y << m_nMonth << m_nDay;
else
{
ar >> y >> m_nMonth >> m_nDay;
m_nYear = (int)y;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -