X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/cf44a61c2410fab7cc9b71c5f2578296e44c28e7..4f13428c4f852674c8f8fc99af26d9486bf907db:/src/common/datetime.cpp diff --git a/src/common/datetime.cpp b/src/common/datetime.cpp index 12732e144b..0832f5379f 100644 --- a/src/common/datetime.cpp +++ b/src/common/datetime.cpp @@ -68,9 +68,10 @@ #ifndef WX_PRECOMP #include "wx/string.h" #include "wx/log.h" + #include "wx/intl.h" + #include "wx/stopwatch.h" // for wxGetLocalTimeMillis() #endif // WX_PRECOMP -#include "wx/intl.h" #include "wx/thread.h" #include "wx/tokenzr.h" #include "wx/module.h" @@ -86,7 +87,6 @@ #endif #include "wx/datetime.h" -#include "wx/stopwatch.h" // for wxGetLocalTimeMillis() const long wxDateTime::TIME_T_FACTOR = 1000l; @@ -169,7 +169,7 @@ wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter , wxFromStringCon #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 @@ -179,7 +179,7 @@ struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp) #if wxUSE_THREADS && !defined(__WINDOWS__) // No need to waste time with a mutex on windows since it's using // thread local storage for localtime anyway. - wxMutexLocker(timeLock); + wxMutexLocker locker(timeLock); #endif memcpy(temp, localtime(ticks), sizeof(struct tm)); return temp; @@ -192,7 +192,7 @@ struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp) #if wxUSE_THREADS && !defined(__WINDOWS__) // No need to waste time with a mutex on windows since it's // using thread local storage for gmtime anyway. - wxMutexLocker(timeLock); + wxMutexLocker locker(timeLock); #endif memcpy(temp, gmtime(ticks), sizeof(struct tm)); return temp; @@ -204,13 +204,8 @@ struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp) // ---------------------------------------------------------------------------- // 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 @@ -332,7 +327,6 @@ wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month) // (in seconds) static int GetTimeZone() { -#ifdef WX_GMTOFF_IN_TM // set to true when the timezone is set static bool s_timezoneSet = false; static long gmtoffset = LONG_MAX; // invalid timezone @@ -343,22 +337,22 @@ static int GetTimeZone() // just call wxLocaltime_r() instead of figuring out whether this // system supports tzset(), _tzset() or something else time_t t = 0; - struct tm *tm; - struct tm tmstruct; + struct tm tm; - tm = wxLocaltime_r(&t, &tmstruct); + wxLocaltime_r(&t, &tm); s_timezoneSet = true; +#ifdef WX_GMTOFF_IN_TM // note that GMT offset is the opposite of time zone and so to return // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM // cases we have to negate it - gmtoffset = -tm->tm_gmtoff; + gmtoffset = -tm.tm_gmtoff; +#else // !WX_GMTOFF_IN_TM + gmtoffset = WX_TIMEZONE; +#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM } return (int)gmtoffset; -#else // !WX_GMTOFF_IN_TM - return (int)WX_TIMEZONE; -#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM } // return the integral part of the JDN for the midnight of the given date (to @@ -1816,6 +1810,7 @@ wxDateTime::SetToWeekOfYear(int year, wxDateTime_t numWeek, WeekDay wd) return dt; } +#if WXWIN_COMPATIBILITY_2_6 // use a separate function to avoid warnings about using deprecated // SetToTheWeek in GetWeek below static wxDateTime @@ -1853,6 +1848,7 @@ wxDateTime wxDateTime::GetWeek(wxDateTime_t numWeek, { return ::SetToTheWeek(GetYear(), numWeek, weekday, flags); } +#endif // WXWIN_COMPATIBILITY_2_6 wxDateTime& wxDateTime::SetToLastMonthDay(Month month, int year) @@ -2408,6 +2404,9 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const 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") ); @@ -2416,25 +2415,30 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const 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 ) + wxString replacement,replacement2,replacement3,replacement4; + for (int rnr=1; rnr<5 ; rnr++) { - replacement << (wxChar)-1; - } + wxString r = (wxChar)-rnr; + while ( fmt2.Find(r) != wxNOT_FOUND ) + { + r << (wxChar)-rnr; + } - wxString replacement2 = (wxChar)-2; - while ( fmt2.Find(replacement) != wxNOT_FOUND ) - { - replacement << (wxChar)-2; + 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 @@ -2459,11 +2463,17 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const &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 ) @@ -3810,9 +3820,11 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) } 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 ); @@ -3965,7 +3977,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) { wxLogDebug(_T("ParseDate: no day, no weekday hence no date.")); - return (wxChar *)NULL; + return NULL; } if ( haveWDay && (haveMon || haveYear || haveDay) && @@ -3974,7 +3986,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) // 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) ) @@ -4004,7 +4016,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) // 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; } } @@ -4020,6 +4032,11 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date) 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 ) @@ -4217,11 +4234,14 @@ wxString wxTimeSpan::Format(const wxChar *format) const if ( ch == _T('%') ) { // the start of the format specification of the printf() below - wxString fmtPrefix = _T('%'); + wxString fmtPrefix(_T('%')); // the number long n; + // the number of digits for the format string, 0 if unused + unsigned digits = 0; + ch = *++pch; // get the format spec char switch ( ch ) { @@ -4256,6 +4276,13 @@ wxString wxTimeSpan::Format(const wxChar *format) const n = GetHours(); if ( partBiggest < Part_Hour ) { + if ( n < 0 ) + { + // the sign has already been taken into account + // when outputting the biggest part + n = -n; + } + n %= HOURS_PER_DAY; } else @@ -4263,25 +4290,31 @@ wxString wxTimeSpan::Format(const wxChar *format) const partBiggest = Part_Hour; } - fmtPrefix += _T("02"); + digits = 2; break; case _T('l'): n = GetMilliseconds().ToLong(); if ( partBiggest < Part_MSec ) { + if ( n < 0 ) + n = -n; + n %= 1000; } //else: no need to reset partBiggest to Part_MSec, it is // the least significant one anyhow - fmtPrefix += _T("03"); + digits = 3; break; case _T('M'): n = GetMinutes(); if ( partBiggest < Part_Min ) { + if ( n < 0 ) + n = -n; + n %= MIN_PER_HOUR; } else @@ -4289,13 +4322,16 @@ wxString wxTimeSpan::Format(const wxChar *format) const partBiggest = Part_Min; } - fmtPrefix += _T("02"); + digits = 2; break; case _T('S'): n = GetSeconds().ToLong(); if ( partBiggest < Part_Sec ) { + if ( n < 0 ) + n = -n; + n %= SEC_PER_MIN; } else @@ -4303,10 +4339,19 @@ wxString wxTimeSpan::Format(const wxChar *format) const partBiggest = Part_Sec; } - fmtPrefix += _T("02"); + digits = 2; break; } + if ( digits ) + { + // negative numbers need one extra position for '-' display + if ( n < 0 ) + digits++; + + fmtPrefix << _T("0") << digits; + } + str += wxString::Format(fmtPrefix + _T("ld"), n); } else