#endif
#endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM
-#if wxUSE_THREADS
+#if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__)
static wxMutex timeLock;
#endif
// ----------------------------------------------------------------------------
// debugging helper: just a convenient replacement of wxCHECK()
-#define wxDATETIME_CHECK(expr, msg) \
- if ( !(expr) ) \
- { \
- wxFAIL_MSG(msg); \
- *this = wxInvalidDateTime; \
- return *this; \
- }
+#define wxDATETIME_CHECK(expr, msg) \
+ wxCHECK2_MSG(expr, *this = wxInvalidDateTime; return *this, msg)
// ----------------------------------------------------------------------------
// private classes
{
nLostWeekDays += year++ % 4 ? 1 : 2;
}
-
+
+ // Keep year below 2000 so the 2digit year number
+ // can never match the month or day of the month
+ if (year>=2000) year-=28;
// at any rate, we couldn't go further than 1988 + 9 + 28!
wxASSERT_MSG( year < 2030,
_T("logic error in wxDateTime::Format") );
- wxString strYear, strYear2;
+ wxString strYear, strYear2;
strYear.Printf(_T("%d"), year);
strYear2.Printf(_T("%d"), year % 100);
-
- // find two strings not occurring in format (this is surely
+
+ // find four strings not occurring in format (this is surely
// not the optimal way of doing it... improvements welcome!)
wxString fmt2 = format;
- wxString replacement = (wxChar)-1;
- while ( fmt2.Find(replacement) != wxNOT_FOUND )
- {
- replacement << (wxChar)-1;
- }
-
- wxString replacement2 = (wxChar)-2;
- while ( fmt2.Find(replacement) != wxNOT_FOUND )
- {
- replacement << (wxChar)-2;
- }
-
+ wxString replacement,replacement2,replacement3,replacement4;
+ for (int rnr=1; rnr<5 ; rnr++) {
+ wxString r = (wxChar)-rnr;
+ while ( fmt2.Find(r) != wxNOT_FOUND )
+ {
+ r << (wxChar)-rnr;
+ }
+
+ switch (rnr) {
+ case 1: replacement=r; break;
+ case 2: replacement2=r; break;
+ case 3: replacement3=r; break;
+ case 4: replacement4=r; break;
+ }
+ }
// replace all occurrences of year with it
bool wasReplaced = fmt2.Replace(strYear, replacement) > 0;
- if ( !wasReplaced )
- wasReplaced = fmt2.Replace(strYear2, replacement2) > 0;
+ // evaluation order ensures we always attempt the replacement.
+ wasReplaced = (fmt2.Replace(strYear2, replacement2) > 0) | wasReplaced ;
// use strftime() to format the same date but in supported
// year
&tmAdjusted);
// now replace the occurrence of 1999 with the real year
+ // we do this in two stages to stop the 2 digit year
+ // matching any substring of the 4 digit year.
+ // Any day,month hours and minutes components should be safe due
+ // to ensuring the range of the years.
wxString strYearReal, strYearReal2;
strYearReal.Printf(_T("%04d"), yearReal);
strYearReal2.Printf(_T("%02d"), yearReal % 100);
- str.Replace(strYear, strYearReal);
- str.Replace(strYear2, strYearReal2);
+ str.Replace(strYear, replacement3);
+ str.Replace(strYear2,replacement4);
+ str.Replace(replacement3, strYearReal);
+ str.Replace(replacement4, strYearReal2);
// and replace back all occurrences of replacement string
if ( wasReplaced )
}
else // may be either day or year
{
+ // use a leap year if we don't have the year yet to allow
+ // dates like 2/29/1976 which would be rejected otherwise
wxDateTime_t max_days = (wxDateTime_t)(
haveMon
- ? GetNumOfDaysInMonth(haveYear ? year : Inv_Year, mon)
+ ? GetNumOfDaysInMonth(haveYear ? year : 1976, mon)
: 31
);
{
wxLogDebug(_T("ParseDate: no day, no weekday hence no date."));
- return (wxChar *)NULL;
+ return NULL;
}
if ( haveWDay && (haveMon || haveYear || haveDay) &&
// without adjectives (which we don't support here) the week day only
// makes sense completely separately or with the full date
// specification (what would "Wed 1999" mean?)
- return (wxChar *)NULL;
+ return NULL;
}
if ( !haveWDay && haveYear && !(haveDay && haveMon) )
// if we give the year, month and day must be given too
wxLogDebug(_T("ParseDate: day and month should be specified if year is."));
- return (wxChar *)NULL;
+ return NULL;
}
}
if ( haveDay )
{
+ // normally we check the day above but the check is optimistic in case
+ // we find the day before its month/year so we have to redo it now
+ if ( day > GetNumOfDaysInMonth(year, mon) )
+ return NULL;
+
Set(day, mon, year);
if ( haveWDay )