#include "wx/thread.h"
#include "wx/tokenzr.h"
+#include "wx/module.h"
#define wxDEFINE_TIME_CONSTANTS // before including datetime.h
+#include <ctype.h>
+
#include "wx/datetime.h"
// ----------------------------------------------------------------------------
#ifndef WX_TIMEZONE
#if defined(__BORLANDC__) || defined(__MINGW32__) || defined(__VISAGECPP__)
#define WX_TIMEZONE _timezone
+ #elif defined(__MWERKS__)
+ long wxmw_timezone = 28800;
+ #define WX_TIMEZONE wxmw_timezone ;
#else // unknown platform - try timezone
#define WX_TIMEZONE timezone
#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();
+ wxDateTimeHolidayAuthority::ms_authorities.Clear();
+ }
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxDateTimeHolidaysModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule, wxModule)
+
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
+// debugger helper: shows what the date really is
+#ifdef __WXDEBUG__
+extern const wxChar *wxDumpDate(const wxDateTime* dt)
+{
+ static wxChar buf[128];
+
+ 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)
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)
wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const
{
-#ifdef __VMS__
- int time2;
-#endif
wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
time_t time = GetTicks();
}
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 )
wxASSERT_MSG( jdn > -2, _T("JDN out of range") );
// calculate the century
- int temp = (jdn + JDN_OFFSET) * 4 - 1;
- int century = temp / DAYS_PER_400_YEARS;
+ 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;
- int year = (century * 100) + (temp / DAYS_PER_4_YEARS);
- int dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1;
+ 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;
- int month = temp / DAYS_PER_5_MONTHS;
- int day = (temp % DAYS_PER_5_MONTHS) / 5 + 1;
+ 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 )
tm.year = (int)year;
tm.mon = (Month)(month - 1); // algorithm yields 1 for January, not 0
tm.mday = (wxDateTime_t)day;
- tm.msec = timeOnly % 1000;
+ tm.msec = (wxDateTime_t)(timeOnly % 1000);
timeOnly -= tm.msec;
timeOnly /= 1000; // now we have time in seconds
- tm.sec = timeOnly % 60;
+ tm.sec = (wxDateTime_t)(timeOnly % 60);
timeOnly -= tm.sec;
timeOnly /= 60; // now we have time in minutes
- tm.min = timeOnly % 60;
+ tm.min = (wxDateTime_t)(timeOnly % 60);
timeOnly -= tm.min;
- tm.hour = timeOnly / 60;
+ tm.hour = (wxDateTime_t)(timeOnly / 60);
return tm;
}
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);
// 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)
{
// take the current month/year if none specified
- ReplaceDefaultYearMonthWithCurrent(&year, &month);
+ if ( year == Inv_Year )
+ year = GetYear();
+ if ( month == Inv_Month )
+ month = GetMonth();
return Set(GetNumOfDaysInMonth(year, month), month, year);
}
}
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));
}
}
diff = weekday - wdayThis;
}
- return Add(wxTimeSpan::Days(diff));
+ return Add(wxDateSpan::Days(diff));
}
wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday)
diff = wdayThis - weekday;
}
- return Substract(wxTimeSpan::Days(diff));
+ return Substract(wxDateSpan::Days(diff));
}
bool wxDateTime::SetToWeekDay(WeekDay weekday,
{
Tm tm = GetTm(tz);
wxDateTime dtMonthStart = wxDateTime(1, tm.mon, tm.year);
- size_t nWeek = GetWeekOfYear(flags) - dtMonthStart.GetWeekOfYear(flags) + 1;
+ 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
nWeek += IsLeapYear(tm.year - 1) ? 53 : 52;
}
- return nWeek;
+ return (wxDateTime::wxDateTime_t)nWeek;
}
wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday)
wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz, bool noDST)
{
- int secDiff = GetTimeZone() + tz.GetOffset();
+ 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
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();
}
else
{
- time += tz.GetOffset();
+ time += (int)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 )
haveHour = TRUE;
hourIsIn12hFormat = TRUE;
- hour = num % 12; // 12 should be 0
+ hour = (wxDateTime_t)(num % 12); // 12 should be 0
break;
case _T('j'): // day of the year
}
haveYear = TRUE;
- year = 1900 + num;
+ year = 1900 + (wxDateTime_t)num;
break;
case _T('Y'): // year with century
while ( wxIsspace(*p) )
p++;
- wxString today = _T("today");
- size_t len = today.length();
- if ( wxString(p, len).CmpNoCase(today) == 0 )
+ // some special cases
+ static struct
{
- // nothing can follow this, so stop here
- p += len;
+ const wxChar *str;
+ int dayDiffFromToday;
+ } literalDates[] =
+ {
+ { wxTRANSLATE("today"), 0 },
+ { wxTRANSLATE("yesterday"), -1 },
+ { wxTRANSLATE("tomorrow"), 1 },
+ };
- *this = Today();
+ for ( size_t n = 0; n < WXSIZEOF(literalDates); n++ )
+ {
+ wxString date = wxGetTranslation(literalDates[n].str);
+ size_t len = date.length();
+ if ( wxString(p, len).CmpNoCase(date) == 0 )
+ {
+ // nothing can follow this, so stop here
+ p += len;
- return p;
+ int dayDiffFromToday = literalDates[n].dayDiffFromToday;
+ *this = Today();
+ if ( dayDiffFromToday )
+ {
+ *this += wxDateSpan::Days(dayDiffFromToday);
+ }
+
+ return p;
+ }
}
// what do we have?
haveYear = TRUE;
// no roll over - 99 means 99, not 1999 for us
- year = val;
+ year = (wxDateTime_t)val;
}
else if ( isMonth )
{
haveDay = TRUE;
- day = val;
+ day = (wxDateTime_t)val;
}
}
else // not a number
return result;
}
+// ----------------------------------------------------------------------------
+// Workdays and holidays support
+// ----------------------------------------------------------------------------
+
+bool wxDateTime::IsWorkDay(Country WXUNUSED(country)) const
+{
+ return !wxDateTimeHolidayAuthority::IsHoliday(*this);
+}
+
// ============================================================================
// wxTimeSpan
// ============================================================================
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++ )
{
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 nAuth = 0; nAuth < count; nAuth++ )
+ {
+ ms_authorities[nAuth]->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();
+}
+
+