X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/54e660f85e8525cc0d0cb0ca7a5c01f931e3ed62..711f12ef2ea0c37d65b3170f78f4705ee85d0c40:/src/common/datetimefmt.cpp diff --git a/src/common/datetimefmt.cpp b/src/common/datetimefmt.cpp index dae6e0f1a8..3ecb11b15e 100644 --- a/src/common/datetimefmt.cpp +++ b/src/common/datetimefmt.cpp @@ -63,6 +63,16 @@ // implementation of wxDateTime // ============================================================================ +// ---------------------------------------------------------------------------- +// helpers shared between datetime.cpp and datetimefmt.cpp +// ---------------------------------------------------------------------------- + +extern void InitTm(struct tm& tm); + +extern int GetTimeZone(); + +extern wxString CallStrftime(const wxString& format, const tm* tm); + // ---------------------------------------------------------------------------- // constants (see also datetime.cpp) // ---------------------------------------------------------------------------- @@ -79,8 +89,40 @@ static const int MIN_PER_HOUR = 60; // parsing helpers // ---------------------------------------------------------------------------- -// see datetime.cpp: -wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month); +#ifdef HAVE_STRPTIME + +#if wxUSE_UNIX && !defined(HAVE_STRPTIME_DECL) + // configure detected that we had strptime() but not its declaration, + // provide it ourselves + extern "C" char *strptime(const char *, const char *, struct tm *); +#endif + +// Unicode-friendly strptime() wrapper +static const wxStringCharType * +CallStrptime(const wxStringCharType *input, const char *fmt, tm *tm) +{ + // the problem here is that strptime() returns pointer into the string we + // passed to it while we're really interested in the pointer into the + // original, Unicode, string so we try to transform the pointer back +#if wxUSE_UNICODE_WCHAR + wxCharBuffer inputMB(wxConvertWX2MB(input)); +#else // ASCII + const char * const inputMB = input; +#endif // Unicode/Ascii + + const char *result = strptime(inputMB, fmt, tm); + if ( !result ) + return NULL; + +#if wxUSE_UNICODE_WCHAR + // FIXME: this is wrong in presence of surrogates &c + return input + (result - inputMB.data()); +#else // ASCII + return result; +#endif // Unicode/Ascii +} + +#endif // HAVE_STRPTIME // return the month if the string is a month name or Inv_Month otherwise static wxDateTime::Month GetMonthFromName(const wxString& name, int flags) @@ -142,13 +184,6 @@ static wxDateTime::WeekDay GetWeekDayFromName(const wxString& name, int flags) return wd; } -/* static */ -struct tm *wxDateTime::GetTmNow(struct tm *tmstruct) -{ - time_t t = GetTimeNow(); - return wxLocaltime_r(&t, tmstruct); -} - // scans all digits (but no more than len) and returns the resulting number static bool GetNumericToken(size_t len, const wxStringCharType*& p, @@ -1154,30 +1189,62 @@ wxDateTime::ParseFormat(const wxString& date, const wxString inc(input); - // try the format which corresponds to ctime() output first - wxString::const_iterator endc; - if ( !dt.ParseFormat(inc, wxS("%a %b %d %H:%M:%S %Y"), &endc) && - !dt.ParseFormat(inc, wxS("%x %X"), &endc) && - !dt.ParseFormat(inc, wxS("%X %x"), &endc) ) + // NOTE: %c is locale-dependent; try strptime +#ifdef HAVE_STRPTIME + struct tm tm; + + // try using strptime() -- it may fail even if the input is + // correct but the date is out of range, so we will fall back + // to our generic code anyhow + const wxStringCharType * + result = CallStrptime(input, "%c", &tm); + if ( result ) { - // we've tried everything and still no match - return NULL; - } + haveDay = haveMon = haveYear = + haveHour = haveMin = haveSec = true; - Tm tm = dt.GetTm(); + hour = tm.tm_hour; + min = tm.tm_min; + sec = tm.tm_sec; - haveDay = haveMon = haveYear = - haveHour = haveMin = haveSec = true; + year = 1900 + tm.tm_year; + mon = (Month)tm.tm_mon; + mday = tm.tm_mday; + + input = result; // proceed where strptime() ended + } + else + { + // strptime() failed; try generic heuristic code +#endif // HAVE_STRPTIME - hour = tm.hour; - min = tm.min; - sec = tm.sec; + // try the format which corresponds to ctime() output first + wxString::const_iterator endc; + if ( !dt.ParseFormat(inc, wxS("%a %b %d %H:%M:%S %Y"), &endc) && + !dt.ParseFormat(inc, wxS("%x %X"), &endc) && + !dt.ParseFormat(inc, wxS("%X %x"), &endc) ) + { + // we've tried everything and still no match + return NULL; + } - year = tm.year; - mon = tm.mon; - mday = tm.mday; + Tm tm = dt.GetTm(); + + haveDay = haveMon = haveYear = + haveHour = haveMin = haveSec = true; + + hour = tm.hour; + min = tm.min; + sec = tm.sec; - input += endc - inc.begin(); + year = tm.year; + mon = tm.mon; + mday = tm.mday; + + input += endc - inc.begin(); +#ifdef HAVE_STRPTIME + } +#endif // HAVE_STRPTIME } break; @@ -1262,6 +1329,13 @@ wxDateTime::ParseFormat(const wxString& date, case _T('p'): // AM or PM string { wxString am, pm, token = GetAlphaToken(input); + + // some locales have empty AM/PM tokens and thus when formatting + // dates with the %p specifier nothing is generated; when trying to + // parse them back, we get an empty token here... but that's not + // an error. + if (token.empty()) + break; GetAmPmStrings(&am, &pm); if (am.empty() && pm.empty()) @@ -1570,7 +1644,7 @@ wxDateTime::ParseFormat(const wxString& date, // also always ignore the week day if ( haveDay ) { - if ( mday > GetNumOfDaysInMonth(tm.year, tm.mon) ) + if ( mday > GetNumberOfDays(tm.mon, tm.year) ) { wxLogDebug(_T("bad month day in wxDateTime::ParseFormat")); @@ -1798,7 +1872,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) // dates like 2/29/1976 which would be rejected otherwise wxDateTime_t max_days = (wxDateTime_t)( haveMon - ? GetNumOfDaysInMonth(haveYear ? year : 1976, mon) + ? GetNumberOfDays(mon, haveYear ? year : 1976) : 31 ); @@ -1976,7 +2050,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) mon = (wxDateTime::Month)(day - 1); // we're in the current year then - if ( (year > 0) && (year <= (int)GetNumOfDaysInMonth(Inv_Year, mon)) ) + if ( (year > 0) && (year <= (int)GetNumberOfDays(mon, Inv_Year)) ) { day = (wxDateTime_t)year; @@ -2010,7 +2084,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end) { // 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) ) + if ( day > GetNumberOfDays(mon, year) ) return NULL; Set(day, mon, year);