datetime.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,201 行 · 第 1/5 页
CPP
2,201 行
tm1.tm_min = minute;
tm1.tm_sec = second;
// and the DST in case it changes on this date
struct tm tm2(tm1);
mktime(&tm2);
if ( tm2.tm_isdst != tm1.tm_isdst )
tm1.tm_isdst = tm2.tm_isdst;
(void)Set(tm1);
// and finally adjust milliseconds
return SetMillisecond(millisec);
}
wxDateTime& wxDateTime::Set(wxDateTime_t day,
Month month,
int year,
wxDateTime_t hour,
wxDateTime_t minute,
wxDateTime_t second,
wxDateTime_t millisec)
{
wxDATETIME_CHECK( hour < 24 &&
second < 62 &&
minute < 60 &&
millisec < 1000,
_T("Invalid time in wxDateTime::Set()") );
ReplaceDefaultYearMonthWithCurrent(&year, &month);
wxDATETIME_CHECK( (0 < day) && (day <= GetNumberOfDays(month, year)),
_T("Invalid date in wxDateTime::Set()") );
// the range of time_t type (inclusive)
static const int yearMinInRange = 1970;
static const int yearMaxInRange = 2037;
// test only the year instead of testing for the exact end of the Unix
// time_t range - it doesn't bring anything to do more precise checks
if ( year >= yearMinInRange && year <= yearMaxInRange )
{
// use the standard library version if the date is in range - this is
// probably more efficient than our code
struct tm tm;
tm.tm_year = year - 1900;
tm.tm_mon = month;
tm.tm_mday = day;
tm.tm_hour = hour;
tm.tm_min = minute;
tm.tm_sec = second;
tm.tm_isdst = -1; // mktime() will guess it
(void)Set(tm);
// and finally adjust milliseconds
if (IsValid())
SetMillisecond(millisec);
return *this;
}
else
{
// do time calculations ourselves: we want to calculate the number of
// milliseconds between the given date and the epoch
// get the JDN for the midnight of this day
m_time = GetTruncatedJDN(day, month, year);
m_time -= EPOCH_JDN;
m_time *= SECONDS_PER_DAY * TIME_T_FACTOR;
// JDN corresponds to GMT, we take localtime
Add(wxTimeSpan(hour, minute, second + GetTimeZone(), millisec));
}
return *this;
}
wxDateTime& wxDateTime::Set(double jdn)
{
// so that m_time will be 0 for the midnight of Jan 1, 1970 which is jdn
// EPOCH_JDN + 0.5
jdn -= EPOCH_JDN + 0.5;
m_time.Assign(jdn*MILLISECONDS_PER_DAY);
// JDNs always are in UTC, so we don't need any adjustments for time zone
return *this;
}
wxDateTime& wxDateTime::ResetTime()
{
Tm tm = GetTm();
if ( tm.hour || tm.min || tm.sec || tm.msec )
{
tm.msec =
tm.sec =
tm.min =
tm.hour = 0;
Set(tm);
}
return *this;
}
// ----------------------------------------------------------------------------
// DOS Date and Time Format functions
// ----------------------------------------------------------------------------
// the dos date and time value is an unsigned 32 bit value in the format:
// YYYYYYYMMMMDDDDDhhhhhmmmmmmsssss
//
// Y = year offset from 1980 (0-127)
// M = month (1-12)
// D = day of month (1-31)
// h = hour (0-23)
// m = minute (0-59)
// s = bisecond (0-29) each bisecond indicates two seconds
// ----------------------------------------------------------------------------
wxDateTime& wxDateTime::SetFromDOS(unsigned long ddt)
{
struct tm tm;
InitTm(tm);
long year = ddt & 0xFE000000;
year >>= 25;
year += 80;
tm.tm_year = year;
long month = ddt & 0x1E00000;
month >>= 21;
month -= 1;
tm.tm_mon = month;
long day = ddt & 0x1F0000;
day >>= 16;
tm.tm_mday = day;
long hour = ddt & 0xF800;
hour >>= 11;
tm.tm_hour = hour;
long minute = ddt & 0x7E0;
minute >>= 5;
tm.tm_min = minute;
long second = ddt & 0x1F;
tm.tm_sec = second * 2;
return Set(mktime(&tm));
}
unsigned long wxDateTime::GetAsDOS() const
{
unsigned long ddt;
time_t ticks = GetTicks();
struct tm *tm = localtime(&ticks);
long year = tm->tm_year;
year -= 80;
year <<= 25;
long month = tm->tm_mon;
month += 1;
month <<= 21;
long day = tm->tm_mday;
day <<= 16;
long hour = tm->tm_hour;
hour <<= 11;
long minute = tm->tm_min;
minute <<= 5;
long second = tm->tm_sec;
second /= 2;
ddt = year | month | day | hour | minute | second;
return ddt;
}
// ----------------------------------------------------------------------------
// time_t <-> broken down time conversions
// ----------------------------------------------------------------------------
wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const
{
wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
time_t time = GetTicks();
if ( time != (time_t)-1 )
{
// use C RTL functions
tm *tm;
if ( tz.GetOffset() == -GetTimeZone() )
{
// we are working with local time
tm = localtime(&time);
// should never happen
wxCHECK_MSG( tm, Tm(), _T("localtime() failed") );
}
else
{
time += (time_t)tz.GetOffset();
#if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning
int time2 = (int) time;
if ( time2 >= 0 )
#else
if ( time >= 0 )
#endif
{
tm = gmtime(&time);
// should never happen
wxCHECK_MSG( tm, Tm(), _T("gmtime() failed") );
}
else
{
tm = (struct tm *)NULL;
}
}
if ( tm )
{
// adjust the milliseconds
Tm tm2(*tm, tz);
long timeOnly = (m_time % MILLISECONDS_PER_DAY).ToLong();
tm2.msec = (wxDateTime_t)(timeOnly % 1000);
return tm2;
}
//else: use generic code below
}
// remember the time and do the calculations with the date only - this
// eliminates rounding errors of the floating point arithmetics
wxLongLong timeMidnight = m_time + tz.GetOffset() * 1000;
long timeOnly = (timeMidnight % MILLISECONDS_PER_DAY).ToLong();
// we want to always have positive time and timeMidnight to be really
// the midnight before it
if ( timeOnly < 0 )
{
timeOnly = MILLISECONDS_PER_DAY + timeOnly;
}
timeMidnight -= timeOnly;
// calculate the Gregorian date from JDN for the midnight of our date:
// this will yield day, month (in 1..12 range) and year
// actually, this is the JDN for the noon of the previous day
long jdn = (timeMidnight / MILLISECONDS_PER_DAY).ToLong() + EPOCH_JDN;
// CREDIT: code below is by Scott E. Lee (but bugs are mine)
wxASSERT_MSG( jdn > -2, _T("JDN out of range") );
// calculate the century
long temp = (jdn + JDN_OFFSET) * 4 - 1;
long century = temp / DAYS_PER_400_YEARS;
// then the year and day of year (1 <= dayOfYear <= 366)
temp = ((temp % DAYS_PER_400_YEARS) / 4) * 4 + 3;
long year = (century * 100) + (temp / DAYS_PER_4_YEARS);
long dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1;
// and finally the month and day of the month
temp = dayOfYear * 5 - 3;
long month = temp / DAYS_PER_5_MONTHS;
long day = (temp % DAYS_PER_5_MONTHS) / 5 + 1;
// month is counted from March - convert to normal
if ( month < 10 )
{
month += 3;
}
else
{
year += 1;
month -= 9;
}
// year is offset by 4800
year -= 4800;
// check that the algorithm gave us something reasonable
wxASSERT_MSG( (0 < month) && (month <= 12), _T("invalid month") );
wxASSERT_MSG( (1 <= day) && (day < 32), _T("invalid day") );
// construct Tm from these values
Tm tm;
tm.year = (int)year;
tm.mon = (Month)(month - 1); // algorithm yields 1 for January, not 0
tm.mday = (wxDateTime_t)day;
tm.msec = (wxDateTime_t)(timeOnly % 1000);
timeOnly -= tm.msec;
timeOnly /= 1000; // now we have time in seconds
tm.sec = (wxDateTime_t)(timeOnly % SEC_PER_MIN);
timeOnly -= tm.sec;
timeOnly /= SEC_PER_MIN; // now we have time in minutes
tm.min = (wxDateTime_t)(timeOnly % MIN_PER_HOUR);
timeOnly -= tm.min;
tm.hour = (wxDateTime_t)(timeOnly / MIN_PER_HOUR);
return tm;
}
wxDateTime& wxDateTime::SetYear(int year)
{
wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
Tm tm(GetTm());
tm.year = year;
Set(tm);
return *this;
}
wxDateTime& wxDateTime::SetMonth(Month month)
{
wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
Tm tm(GetTm());
tm.mon = month;
Set(tm);
return *this;
}
wxDateTime& wxDateTime::SetDay(wxDateTime_t mday)
{
wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
Tm tm(GetTm());
tm.mday = mday;
Set(tm);
return *this;
}
wxDateTime& wxDateTime::SetHour(wxDateTime_t hour)
{
wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
Tm tm(GetTm());
tm.hour = hour;
Set(tm);
return *this;
}
wxDateTime& wxDateTime::SetMinute(wxDateTime_t min)
{
wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
Tm tm(GetTm());
tm.min = min;
Set(tm);
return *this;
}
wxDateTime& wxDateTime::SetSecond(wxDateTime_t sec)
{
wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
Tm tm(GetTm());
tm.sec = sec;
Set(tm);
return *this;
}
wxDateTime& wxDateTime::SetMillisecond(wxDateTime_t millisecond)
{
wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
// we don't need to use GetTm() for this one
m_time -= m_time % 1000l;
m_time += millisecond;
return *this;
}
// ----------------------------------------------------------------------------
// wxDateTime arithmetics
// ----------------------------------------------------------------------------
wxDateTime& wxDateTime::Add(const wxDateSpan& diff)
{
Tm tm(GetTm());
tm.year += diff.GetYears();
tm.AddMonths(diff.GetMonths());
// check that the resulting date is valid
if ( tm.mday > GetNumOfDaysInMonth(tm.year, tm.mon) )
{
// We suppose that when adding one month to Jan 31 we want to get Feb
// 28 (or 29), i.e. adding a month to the last day of the month should
// give the last day of the next month which is quite logical.
//
// Unfortunately, there is no logic way to understand what should
// Jan 30 + 1 month be - Feb 28 too or Feb 27 (assuming non leap year)?
// We make it Feb 28 (last day too), but it is highly questionable.
tm.mday = GetNumOfDaysInMonth(tm.year, tm.mon);
}
tm.AddDays(diff.GetTotalDays());
Set(tm);
wxASSERT_MSG( IsSameTime(tm),
_T("Add(wxDateSpan) shouldn't modify time") );
return *this;
}
// ----------------------------------------------------------------------------
// Weekday and monthday stuff
// ----------------------------------------------------------------------------
// convert Sun, Mon, ..., Sat into 6, 0, ..., 5
static inline int ConvertWeekDayToMondayBase(int wd)
{
return wd == wxDateTime::Sun ? 6 : wd - 1;
}
/* static */
wxDateTime
wxDateTime::SetToWeekOfYear(int year, wxDateTime_t numWeek, WeekDay wd)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?