datetime.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,201 行 · 第 1/5 页
CPP
2,201 行
{
wxASSERT_MSG( numWeek > 0,
_T("invalid week number: weeks are counted from 1") );
// Jan 4 always lies in the 1st week of the year
wxDateTime dt(4, Jan, year);
dt.SetToWeekDayInSameWeek(wd);
dt += wxDateSpan::Weeks(numWeek - 1);
return dt;
}
// use a separate function to avoid warnings about using deprecated
// SetToTheWeek in GetWeek below
static wxDateTime
SetToTheWeek(int year,
wxDateTime::wxDateTime_t numWeek,
wxDateTime::WeekDay weekday,
wxDateTime::WeekFlags flags)
{
// Jan 4 always lies in the 1st week of the year
wxDateTime dt(4, wxDateTime::Jan, year);
dt.SetToWeekDayInSameWeek(weekday, flags);
dt += wxDateSpan::Weeks(numWeek - 1);
return dt;
}
bool wxDateTime::SetToTheWeek(wxDateTime_t numWeek,
WeekDay weekday,
WeekFlags flags)
{
int year = GetYear();
*this = ::SetToTheWeek(year, numWeek, weekday, flags);
if ( GetYear() != year )
{
// oops... numWeek was too big
return false;
}
return true;
}
wxDateTime wxDateTime::GetWeek(wxDateTime_t numWeek,
WeekDay weekday,
WeekFlags flags) const
{
return ::SetToTheWeek(GetYear(), numWeek, weekday, flags);
}
wxDateTime& wxDateTime::SetToLastMonthDay(Month month,
int year)
{
// take the current month/year if none specified
if ( year == Inv_Year )
year = GetYear();
if ( month == Inv_Month )
month = GetMonth();
return Set(GetNumOfDaysInMonth(year, month), month, year);
}
wxDateTime& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday, WeekFlags flags)
{
wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") );
int wdayDst = weekday,
wdayThis = GetWeekDay();
if ( wdayDst == wdayThis )
{
// nothing to do
return *this;
}
if ( flags == Default_First )
{
flags = GetCountry() == USA ? Sunday_First : Monday_First;
}
// the logic below based on comparing weekday and wdayThis works if Sun (0)
// is the first day in the week, but breaks down for Monday_First case so
// we adjust the week days in this case
if ( flags == Monday_First )
{
if ( wdayThis == Sun )
wdayThis += 7;
if ( wdayDst == Sun )
wdayDst += 7;
}
//else: Sunday_First, nothing to do
// go forward or back in time to the day we want
if ( wdayDst < wdayThis )
{
return Subtract(wxDateSpan::Days(wdayThis - wdayDst));
}
else // weekday > wdayThis
{
return Add(wxDateSpan::Days(wdayDst - wdayThis));
}
}
wxDateTime& wxDateTime::SetToNextWeekDay(WeekDay weekday)
{
wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") );
int diff;
WeekDay wdayThis = GetWeekDay();
if ( weekday == wdayThis )
{
// nothing to do
return *this;
}
else if ( weekday < wdayThis )
{
// need to advance a week
diff = 7 - (wdayThis - weekday);
}
else // weekday > wdayThis
{
diff = weekday - wdayThis;
}
return Add(wxDateSpan::Days(diff));
}
wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday)
{
wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") );
int diff;
WeekDay wdayThis = GetWeekDay();
if ( weekday == wdayThis )
{
// nothing to do
return *this;
}
else if ( weekday > wdayThis )
{
// need to go to previous week
diff = 7 - (weekday - wdayThis);
}
else // weekday < wdayThis
{
diff = wdayThis - weekday;
}
return Subtract(wxDateSpan::Days(diff));
}
bool wxDateTime::SetToWeekDay(WeekDay weekday,
int n,
Month month,
int year)
{
wxCHECK_MSG( weekday != Inv_WeekDay, false, _T("invalid weekday") );
// we don't check explicitly that -5 <= n <= 5 because we will return false
// anyhow in such case - but may be should still give an assert for it?
// take the current month/year if none specified
ReplaceDefaultYearMonthWithCurrent(&year, &month);
wxDateTime dt;
// TODO this probably could be optimised somehow...
if ( n > 0 )
{
// get the first day of the month
dt.Set(1, month, year);
// get its wday
WeekDay wdayFirst = dt.GetWeekDay();
// go to the first weekday of the month
int diff = weekday - wdayFirst;
if ( diff < 0 )
diff += 7;
// add advance n-1 weeks more
diff += 7*(n - 1);
dt += wxDateSpan::Days(diff);
}
else // count from the end of the month
{
// get the last day of the month
dt.SetToLastMonthDay(month, year);
// get its wday
WeekDay wdayLast = dt.GetWeekDay();
// go to the last weekday of the month
int diff = wdayLast - weekday;
if ( diff < 0 )
diff += 7;
// and rewind n-1 weeks from there
diff += 7*(-n - 1);
dt -= wxDateSpan::Days(diff);
}
// check that it is still in the same month
if ( dt.GetMonth() == month )
{
*this = dt;
return true;
}
else
{
// no such day in this month
return false;
}
}
static inline
wxDateTime::wxDateTime_t GetDayOfYearFromTm(const wxDateTime::Tm& tm)
{
return (wxDateTime::wxDateTime_t)(gs_cumulatedDays[wxDateTime::IsLeapYear(tm.year)][tm.mon] + tm.mday);
}
wxDateTime::wxDateTime_t wxDateTime::GetDayOfYear(const TimeZone& tz) const
{
return GetDayOfYearFromTm(GetTm(tz));
}
wxDateTime::wxDateTime_t
wxDateTime::GetWeekOfYear(wxDateTime::WeekFlags flags, const TimeZone& tz) const
{
if ( flags == Default_First )
{
flags = GetCountry() == USA ? Sunday_First : Monday_First;
}
Tm tm(GetTm(tz));
wxDateTime_t nDayInYear = GetDayOfYearFromTm(tm);
int wdTarget = GetWeekDay(tz);
int wdYearStart = wxDateTime(1, Jan, GetYear()).GetWeekDay();
int week;
if ( flags == Sunday_First )
{
// FIXME: First week is not calculated correctly.
week = (nDayInYear - wdTarget + 7) / 7;
if ( wdYearStart == Wed || wdYearStart == Thu )
week++;
}
else // week starts with monday
{
// adjust the weekdays to non-US style.
wdYearStart = ConvertWeekDayToMondayBase(wdYearStart);
wdTarget = ConvertWeekDayToMondayBase(wdTarget);
// quoting from http://www.cl.cam.ac.uk/~mgk25/iso-time.html:
//
// Week 01 of a year is per definition the first week that has the
// Thursday in this year, which is equivalent to the week that
// contains the fourth day of January. In other words, the first
// week of a new year is the week that has the majority of its
// days in the new year. Week 01 might also contain days from the
// previous year and the week before week 01 of a year is the last
// week (52 or 53) of the previous year even if it contains days
// from the new year. A week starts with Monday (day 1) and ends
// with Sunday (day 7).
//
// if Jan 1 is Thursday or less, it is in the first week of this year
if ( wdYearStart < 4 )
{
// count the number of entire weeks between Jan 1 and this date
week = (nDayInYear + wdYearStart + 6 - wdTarget)/7;
// be careful to check for overflow in the next year
if ( week == 53 && tm.mday - wdTarget > 28 )
week = 1;
}
else // Jan 1 is in the last week of the previous year
{
// check if we happen to be at the last week of previous year:
if ( tm.mon == Jan && tm.mday < 8 - wdYearStart )
week = wxDateTime(31, Dec, GetYear()-1).GetWeekOfYear();
else
week = (nDayInYear + wdYearStart - 1 - wdTarget)/7;
}
}
return (wxDateTime::wxDateTime_t)week;
}
wxDateTime::wxDateTime_t wxDateTime::GetWeekOfMonth(wxDateTime::WeekFlags flags,
const TimeZone& tz) const
{
Tm tm = GetTm(tz);
wxDateTime dtMonthStart = wxDateTime(1, tm.mon, tm.year);
int nWeek = GetWeekOfYear(flags) - dtMonthStart.GetWeekOfYear(flags) + 1;
if ( nWeek < 0 )
{
// this may happen for January when Jan, 1 is the last week of the
// previous year
nWeek += IsLeapYear(tm.year - 1) ? 53 : 52;
}
return (wxDateTime::wxDateTime_t)nWeek;
}
wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday)
{
int year = GetYear();
wxDATETIME_CHECK( (0 < yday) && (yday <= GetNumberOfDays(year)),
_T("invalid year day") );
bool isLeap = IsLeapYear(year);
for ( Month mon = Jan; mon < Inv_Month; wxNextMonth(mon) )
{
// for Dec, we can't compare with gs_cumulatedDays[mon + 1], but we
// don't need it neither - because of the CHECK above we know that
// yday lies in December then
if ( (mon == Dec) || (yday <= gs_cumulatedDays[isLeap][mon + 1]) )
{
Set((wxDateTime::wxDateTime_t)(yday - gs_cumulatedDays[isLeap][mon]), mon, year);
break;
}
}
return *this;
}
// ----------------------------------------------------------------------------
// Julian day number conversion and related stuff
// ----------------------------------------------------------------------------
double wxDateTime::GetJulianDayNumber() const
{
return m_time.ToDouble() / MILLISECONDS_PER_DAY + EPOCH_JDN + 0.5;
}
double wxDateTime::GetRataDie() const
{
// March 1 of the year 0 is Rata Die day -306 and JDN 1721119.5
return GetJulianDayNumber() - 1721119.5 - 306;
}
// ----------------------------------------------------------------------------
// timezone and DST stuff
// ----------------------------------------------------------------------------
int wxDateTime::IsDST(wxDateTime::Country country) const
{
wxCHECK_MSG( country == Country_Default, -1,
_T("country support not implemented") );
// use the C RTL for the dates in the standard range
time_t timet = GetTicks();
if ( timet != (time_t)-1 )
{
tm *tm = localtime(&timet);
wxCHECK_MSG( tm, -1, _T("localtime() failed") );
return tm->tm_isdst;
}
else
{
int year = GetYear();
if ( !IsDSTApplicable(year, country) )
{
// no DST time in this year in this country
return -1;
}
return IsBetween(GetBeginDST(year, country), GetEndDST(year, country));
}
}
wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz, bool noDST)
{
long secDiff = GetTimeZone() + tz.GetOffset();
// we need to know whether DST is or not in effect for this date unless
// the test disabled by the caller
if ( !noDST && (IsDST() == 1) )
{
// FIXME we assume that the DST is always shifted by 1 hour
secDiff -= 3600;
}
return Add(wxTimeSpan::Seconds(secDiff));
}
wxDateTime& wxDateTime::MakeFromTimezone(const TimeZone& tz, bool noDST)
{
long secDiff = GetTimeZone() + tz.GetOffset();
// we need to know whether DST is or not in effect for this date unless
// the test disabled by the caller
if ( !noDST && (IsDST() == 1) )
{
// FIXME we assume that the DST is always shifted by 1 hour
secDiff -= 3600;
}
return Subtract(wxTimeSpan::Seconds(secDiff));
}
// ----------------------------------------------------------------------------
// wxDateTime to/from text representations
// ----------------------------------------------------------------------------
wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
{
wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxDateTime::Format") );
// we have to use our own implementation if the date is out of range of
// strftime() or if we use non standard specificators
time_t time = GetTicks();
if ( (time != (time_t)-1) && !wxStrstr(format, _T("%l")) )
{
// use strftime()
tm *tm;
if ( tz.GetOffset() == -GetTimeZone() )
{
// we are working with local time
tm = localtime(&time);
// should never happen
wxCHECK_MSG( tm, wxEmptyString, _T("localtime() failed") );
}
else
{
time += (int)tz.GetOffset();
#if defined(__VMS__) || defined(__WATCOMC__) /
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?