X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1a8557b1430ee9e30e1cb4fb355f3be6fa38d234..db434467a143a2c847c4bcfe987f0202c2d02bf2:/src/common/datetime.cpp diff --git a/src/common/datetime.cpp b/src/common/datetime.cpp index 1f48f3022d..7598153308 100644 --- a/src/common/datetime.cpp +++ b/src/common/datetime.cpp @@ -67,6 +67,7 @@ #include "wx/string.h" #include "wx/intl.h" #include "wx/log.h" + #include "wx/module.h" #endif // WX_PRECOMP #include "wx/thread.h" @@ -99,6 +100,31 @@ #endif #endif // !WX_TIMEZONE +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class wxDateTimeHolidaysModule : public wxModule +{ +public: + virtual bool OnInit() + { + wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeWorkDays); + + return TRUE; + } + + virtual void OnExit() + { + wxDateTimeHolidayAuthority::ClearAllAuthorities(); + } + +private: + DECLARE_DYNAMIC_CLASS(wxDateTimeHolidaysModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule, wxModule) + // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -160,6 +186,18 @@ wxDateTime::Country wxDateTime::ms_country = wxDateTime::Country_Unknown; // private functions // ---------------------------------------------------------------------------- +// debugger helper: shows what the date really is +#ifdef __WXDEBUG__ +extern const wxChar *wxDumpDate(const wxDateTime* dt) +{ + static wxChar buf[20]; + + wxStrcpy(buf, dt->Format(_T("%Y-%m-%d (%a) %H:%M:%S"))); + + return buf; +} +#endif // Debug + // get the number of days in the given month of the given year static inline wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month) @@ -437,6 +475,9 @@ void wxDateTime::Tm::AddMonths(int monDiff) mon = (wxDateTime::Month)(mon + monDiff); wxASSERT_MSG( mon >= 0 && mon < MONTHS_IN_YEAR, _T("logic error") ); + + // NB: we don't check here that the resulting date is valid, this function + // is private and the caller must check it if needed } void wxDateTime::Tm::AddDays(int dayDiff) @@ -1147,9 +1188,6 @@ wxDateTime& wxDateTime::ResetTime() wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const { -#ifdef __VMS__ - int time2; -#endif wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); time_t time = GetTicks(); @@ -1167,9 +1205,9 @@ wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const } else { - time += tz.GetOffset(); + time += (time_t)tz.GetOffset(); #ifdef __VMS__ // time is unsigned so avoid warning - time2 = (int) time; + int time2 = (int) time; if ( time2 >= 0 ) #else if ( time >= 0 ) @@ -1361,6 +1399,20 @@ wxDateTime& wxDateTime::Add(const wxDateSpan& diff) 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); @@ -1375,6 +1427,23 @@ wxDateTime& wxDateTime::Add(const wxDateSpan& diff) // Weekday and monthday stuff // ---------------------------------------------------------------------------- +bool wxDateTime::SetToTheWeek(wxDateTime_t numWeek, WeekDay weekday) +{ + int year = GetYear(); + + // Jan 4 always lies in the 1st week of the year + Set(4, Jan, year); + SetToWeekDayInSameWeek(weekday) += wxDateSpan::Weeks(numWeek); + + if ( GetYear() != year ) + { + // oops... numWeek was too big + return FALSE; + } + + return TRUE; +} + wxDateTime& wxDateTime::SetToLastMonthDay(Month month, int year) { @@ -1399,11 +1468,11 @@ wxDateTime& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday) } else if ( weekday < wdayThis ) { - return Substract(wxTimeSpan::Days(wdayThis - weekday)); + return Substract(wxDateSpan::Days(wdayThis - weekday)); } else // weekday > wdayThis { - return Add(wxTimeSpan::Days(weekday - wdayThis)); + return Add(wxDateSpan::Days(weekday - wdayThis)); } } @@ -1428,7 +1497,7 @@ wxDateTime& wxDateTime::SetToNextWeekDay(WeekDay weekday) diff = weekday - wdayThis; } - return Add(wxTimeSpan::Days(diff)); + return Add(wxDateSpan::Days(diff)); } wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday) @@ -1452,7 +1521,7 @@ wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday) diff = wdayThis - weekday; } - return Substract(wxTimeSpan::Days(diff)); + return Substract(wxDateSpan::Days(diff)); } bool wxDateTime::SetToWeekDay(WeekDay weekday, @@ -1679,9 +1748,6 @@ wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz, bool noDST) wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const { -#ifdef __VMS__ - int time2; -#endif wxCHECK_MSG( format, _T(""), _T("NULL format in wxDateTime::Format") ); time_t time = GetTicks(); @@ -1701,8 +1767,8 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const { time += tz.GetOffset(); -#ifdef __VMS__ /* time is unsigned so VMS gives a warning on the original */ - time2 = (int) time; +#ifdef __VMS__ // time is unsigned so avoid the warning + int time2 = (int) time; if ( time2 >= 0 ) #else if ( time >= 0 ) @@ -3246,6 +3312,15 @@ const wxChar *wxDateTime::ParseTime(const wxChar *time) return result; } +// ---------------------------------------------------------------------------- +// Workdays and holidays support +// ---------------------------------------------------------------------------- + +bool wxDateTime::IsWorkDay(Country WXUNUSED(country)) const +{ + return !wxDateTimeHolidayAuthority::IsHoliday(*this); +} + // ============================================================================ // wxTimeSpan // ============================================================================ @@ -3271,7 +3346,7 @@ wxString wxTimeSpan::Format(const wxChar *format) const wxCHECK_MSG( format, _T(""), _T("NULL format in wxTimeSpan::Format") ); wxString str; - str.Alloc(strlen(format)); + str.Alloc(wxStrlen(format)); for ( const wxChar *pch = format; pch; pch++ ) { @@ -3331,3 +3406,121 @@ wxString wxTimeSpan::Format(const wxChar *format) const return str; } + +// ============================================================================ +// wxDateTimeHolidayAuthority and related classes +// ============================================================================ + +#include "wx/arrimpl.cpp" + +WX_DEFINE_OBJARRAY(wxDateTimeArray) + +static int wxCMPFUNC_CONV +wxDateTimeCompareFunc(wxDateTime **first, wxDateTime **second) +{ + wxDateTime dt1 = **first, + dt2 = **second; + + return dt1 == dt2 ? 0 : dt1 < dt2 ? -1 : +1; +} + +// ---------------------------------------------------------------------------- +// wxDateTimeHolidayAuthority +// ---------------------------------------------------------------------------- + +wxHolidayAuthoritiesArray wxDateTimeHolidayAuthority::ms_authorities; + +/* static */ +bool wxDateTimeHolidayAuthority::IsHoliday(const wxDateTime& dt) +{ + size_t count = ms_authorities.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( ms_authorities[n]->DoIsHoliday(dt) ) + { + return TRUE; + } + } + + return FALSE; +} + +/* static */ +size_t +wxDateTimeHolidayAuthority::GetHolidaysInRange(const wxDateTime& dtStart, + const wxDateTime& dtEnd, + wxDateTimeArray& holidays) +{ + wxDateTimeArray hol; + + holidays.Empty(); + + size_t count = ms_authorities.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + ms_authorities[n]->DoGetHolidaysInRange(dtStart, dtEnd, hol); + + WX_APPEND_ARRAY(holidays, hol); + } + + holidays.Sort(wxDateTimeCompareFunc); + + return holidays.GetCount(); +} + +/* static */ +void wxDateTimeHolidayAuthority::ClearAllAuthorities() +{ + WX_CLEAR_ARRAY(ms_authorities); +} + +/* static */ +void wxDateTimeHolidayAuthority::AddAuthority(wxDateTimeHolidayAuthority *auth) +{ + ms_authorities.Add(auth); +} + +// ---------------------------------------------------------------------------- +// wxDateTimeWorkDays +// ---------------------------------------------------------------------------- + +bool wxDateTimeWorkDays::DoIsHoliday(const wxDateTime& dt) const +{ + wxDateTime::WeekDay wd = dt.GetWeekDay(); + + return (wd == wxDateTime::Sun) || (wd == wxDateTime::Sat); +} + +size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime& dtStart, + const wxDateTime& dtEnd, + wxDateTimeArray& holidays) const +{ + if ( dtStart > dtEnd ) + { + wxFAIL_MSG( _T("invalid date range in GetHolidaysInRange") ); + + return 0u; + } + + holidays.Empty(); + + // instead of checking all days, start with the first Sat after dtStart and + // end with the last Sun before dtEnd + wxDateTime dtSatFirst = dtStart.GetNextWeekDay(wxDateTime::Sat), + dtSatLast = dtEnd.GetPrevWeekDay(wxDateTime::Sat), + dtSunFirst = dtStart.GetNextWeekDay(wxDateTime::Sun), + dtSunLast = dtEnd.GetPrevWeekDay(wxDateTime::Sun), + dt; + + for ( dt = dtSatFirst; dt <= dtSatLast; dt += wxDateSpan::Week() ) + { + holidays.Add(dt); + } + + for ( dt = dtSunFirst; dt <= dtSunLast; dt += wxDateSpan::Week() ) + { + holidays.Add(dt); + } + + return holidays.GetCount(); +}