📄 goodtime.cpp
字号:
#include "stdafx.h"
#include "GoodTime.h"
/////////////////////////////////////////////////////////////////////////////
// CGoodTime - absolute time
CGoodTime::CGoodTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec,
int nDST)
{
struct tm atm;
#ifdef _DEBUG
memset( &atm, 0xFF, sizeof(atm) );
switch ( nMonth )
{
case 1: // January
case 3: // March
case 5: // May
case 7: // July
case 8: // August
case 10: // October
case 12: // December
ASSERT( nDay <= 31 );
break;
case 4: // April
case 6: // June
case 9: // September
case 11: // November
ASSERT( nDay <= 30 );
break;
case 2:
ASSERT( (nDay <= 28) || (IsLeapYear(nYear) && (nDay == 29)) );
break;
default: // Bad month
ASSERT(FALSE);
}
#endif
atm.tm_sec = nSec;
atm.tm_min = nMin;
atm.tm_hour = nHour;
ASSERT(nDay >= 1 && nDay <= 31);
atm.tm_mday = nDay;
ASSERT(nMonth >= 1 && nMonth <= 12);
atm.tm_mon = nMonth - 1; // tm_mon is 0 based
ASSERT(nYear >= 1900);
atm.tm_year = nYear - 1900; // tm_year is 1900 based
// Note: nDST < 0 we should adjust
atm.tm_isdst = nDST;
atm.tm_isdst = nDST;
// Set tm_yday and tm_wday
SetDays( &atm );
m_time = atm;
}
void CGoodTime::SetDays( tm *ptm )
{
int nDaysToMonth[12] = {
0,
31,
59, // Adjust for leap years later
90,
120,
151,
181,
212,
243,
273,
304,
334
};
// The month should have been OK when we were called
ASSERT( (ptm->tm_mon >= 0) && (ptm->tm_mon <= 11) );
// Set the number of days since Jan 1
ptm->tm_yday = nDaysToMonth[ptm->tm_mon] + ptm->tm_mday - 1;
// Adjust for leap years
if ( ( IsLeapYear( ptm->tm_year+1900 ) ) &&
( ptm->tm_mon > 1 ) )
{
ptm->tm_yday++;
}
// Calculate the number of days since AD 1
long nDayNum;
int nYear = ptm->tm_year + 1900;
// Approximate the number of days since 1/1/1
nDayNum = (nYear - 1) * 365;
// Add days for the leap years
nDayNum += (nYear - 1) / 4;
// Subtract years which are divisible by 100
nDayNum -= (nYear - 1) / 100;
// But replace years which are divisible by 400
nDayNum += (nYear - 1) / 400;
// This class is 1900-based, but 1582 is algorithmically significant.
ASSERT( nYear > 1582 );
// But before 1582 all centuries were leap years.
// In 1582, Pope Gregory XIII mandated that October 4 would
// be followed by October 15. This accounts for those facts.
nDayNum += 2;
// Now add the days to this point this year
nDayNum += ptm->tm_yday;
// Finally, calculate the day of the week based on what we now know.
ptm->tm_wday = (((nDayNum % 7) + 6) % 7);
}
CGoodTime::CGoodTime(WORD wDosDate, WORD wDosTime, int nDST)
{
struct tm atm;
atm.tm_sec = (wDosTime & ~0xFFE0) << 1;
atm.tm_min = (wDosTime & ~0xF800) >> 5;
atm.tm_hour = wDosTime >> 11;
atm.tm_mday = wDosDate & ~0xFFE0;
atm.tm_mon = ((wDosDate & ~0xFE00) >> 5) - 1;
atm.tm_year = (wDosDate >> 9) + 80;
// Note: nDST < 0 we should adjust
atm.tm_isdst = nDST;
// Set tm_yday and tm_wday
SetDays( &atm );
m_time = atm;
}
CGoodTime::CGoodTime(const SYSTEMTIME& sysTime, int nDST)
{
ASSERT(sysTime.wYear >= 1900);
CGoodTime timeT(
(int)sysTime.wYear, (int)sysTime.wMonth, (int)sysTime.wDay,
(int)sysTime.wHour, (int)sysTime.wMinute, (int)sysTime.wSecond,
nDST);
*this = timeT;
}
CGoodTime::CGoodTime(const FILETIME& fileTime, int nDST)
{
// first convert file time (UTC time) to local time
FILETIME localTime;
if (!FileTimeToLocalFileTime(&fileTime, &localTime))
{
memset( &m_time, 0, sizeof(m_time) );
return;
}
// then convert that time to system time
SYSTEMTIME sysTime;
if (!FileTimeToSystemTime(&localTime, &sysTime))
{
memset( &m_time, 0, sizeof(m_time) );
return;
}
// then convert the system time to a time_t (C-runtime local time)
CGoodTime timeT(sysTime, nDST);
*this = timeT;
}
CGoodTime PASCAL CGoodTime::GetCurrentTime()
// return the current system time
{
SYSTEMTIME curTime;
// Find the current system time
GetLocalTime( &curTime );
return CGoodTime(curTime, _daylight);
}
static tm s_tAdjusted;
struct tm* CGoodTime::GetGmtTm(struct tm* ptm) const
{
// Start with local time
memcpy( &s_tAdjusted, &m_time, sizeof(m_time) );
// _timezone has the number of seconds different from local time to UCT
long lAdjusted = s_tAdjusted.tm_sec + _timezone;
// Adjust the time.
if ( lAdjusted < 60 )
{
// This is probably no time zone change, but play it safe
s_tAdjusted.tm_sec = lAdjusted;
}
else
{
// Store the seconds
s_tAdjusted.tm_sec = (lAdjusted % 60);
// move to minutes
lAdjusted /= 60;
lAdjusted += s_tAdjusted.tm_min;
// Look deeper
if ( lAdjusted < 60 )
{
s_tAdjusted.tm_min = lAdjusted;
}
else
{
// Store the minutes
s_tAdjusted.tm_min = (lAdjusted % 60);
// move to hours
lAdjusted /= 60;
lAdjusted += s_tAdjusted.tm_hour;
if ( lAdjusted < 24 )
{
// Change the hours
s_tAdjusted.tm_hour = lAdjusted;
}
else
{
// Store the seconds
s_tAdjusted.tm_hour = (lAdjusted % 24);
// move to days
lAdjusted /= 24;
// We shouldn't change more than a day either way.
ASSERT( ( lAdjusted < 2 ) && ( lAdjusted > -2 ) );
// Adjust the day of the week and the day of the year
s_tAdjusted.tm_yday += lAdjusted;
if ( (s_tAdjusted.tm_wday + lAdjusted) >= 0)
{
s_tAdjusted.tm_wday += lAdjusted;
s_tAdjusted.tm_wday %= 7;
}
else
{
s_tAdjusted.tm_wday = 7 + (s_tAdjusted.tm_wday + lAdjusted);
}
// Going from Jan 1 back and Dec 31 forward is handled below
// What we just did should assure this
ASSERT( (s_tAdjusted.tm_wday >= 0) && (s_tAdjusted.tm_wday <= 6) );
// Add the current count
lAdjusted += s_tAdjusted.tm_mday;
// Find out how many days in the current month
// and the previous month
int nMaxDay;
int nMaxDayPrev;
switch ( s_tAdjusted.tm_mon )
{
case 0: // January
case 7: // August
nMaxDay = 31;
nMaxDayPrev = 31;
break;
case 4: // May
case 6: // July
case 9: // October
case 11: // December
nMaxDay = 31;
nMaxDayPrev = 30;
break;
case 2: // March
nMaxDay = 31;
if ( IsLeapYear( s_tAdjusted.tm_year + 1900 ) )
{
nMaxDayPrev = 29;
}
else
{
nMaxDayPrev = 28;
}
break;
case 3: // April
case 5: // June
case 8: // September
case 10: // November
nMaxDay = 30;
nMaxDayPrev = 31;
break;
case 1: // February made me shiver...
if ( IsLeapYear( s_tAdjusted.tm_year + 1900 ) )
{
nMaxDay = 29;
}
else
{
nMaxDay = 28;
}
nMaxDayPrev = 31;
default: // Bad month
nMaxDay = 0;
nMaxDayPrev = 0;
break;
}
// Remember, we were about to replace the day of the month
if ( lAdjusted < 1 )
{
s_tAdjusted.tm_mday = nMaxDayPrev;
if ( s_tAdjusted.tm_mon == 0 )
{
s_tAdjusted.tm_mon = 11;
s_tAdjusted.tm_year--;
s_tAdjusted.tm_yday = 365 + (IsLeapYear(s_tAdjusted.tm_year+1900)?1:0);
}
else
{
s_tAdjusted.tm_mon++;
}
}
else if ( lAdjusted > nMaxDay )
{
s_tAdjusted.tm_mday = 1;
if ( s_tAdjusted.tm_mon < 11 )
{
s_tAdjusted.tm_mon++;
}
else
{
s_tAdjusted.tm_mon = 0;
s_tAdjusted.tm_year++;
s_tAdjusted.tm_yday = 0;
}
}
else
{
s_tAdjusted.tm_mday = lAdjusted;
}
}
}
}
if ( ptm != NULL )
{
*ptm = s_tAdjusted;
}
return &s_tAdjusted;
}
BOOL CGoodTime::IsLeapYear( int nYear )
{
// This will work for years before 1900, but it won't
// work for tm_years which are 1900-based so that
// 2000 is represented as 100.
ASSERT( nYear > 1900 );
if ( (nYear % 4) != 0 )
{
// Years not divisible by four are not leap years
return FALSE;
}
else
{
// Years divisible by 4 are leap years
// Unless they are also divisible by 100
// and not divisible by 400.
// Pope Gregory XIII didn't like programmers.
if ( (nYear % 100) != 0 )
{
return TRUE;
}
else
{
if ( (nYear % 400) != 0 )
{
return FALSE;
}
else
{
return TRUE;
}
}
}
}
static tm s_time;
struct tm* CGoodTime::GetLocalTm(struct tm* ptm) const
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -