// 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)
// ----------------------------------------------------------------------------
// 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)
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,
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;
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())
// 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"));
// 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
);
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;
{
// 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);