+// all the functions below taking non-const wxString::const_iterator p advance
+// it until the end of the match
+
+// scans all digits (but no more than len) and returns the resulting number
+bool GetNumericToken(size_t len,
+ wxString::const_iterator& p,
+ const wxString::const_iterator& end,
+ unsigned long *number)
+{
+ size_t n = 1;
+ wxString s;
+ while ( p != end && wxIsdigit(*p) )
+ {
+ s += *p++;
+
+ if ( len && ++n > len )
+ break;
+ }
+
+ return !s.empty() && s.ToULong(number);
+}
+
+// scans all alphabetic characters and returns the resulting string
+wxString
+GetAlphaToken(wxString::const_iterator& p,
+ const wxString::const_iterator& end)
+{
+ wxString s;
+ while ( p != end && wxIsalpha(*p) )
+ {
+ s += *p++;
+ }
+
+ return s;
+}
+
+enum
+{
+ DateLang_English = 1,
+ DateLang_Local = 2
+};
+
+// return the month if the string is a month name or Inv_Month otherwise
+//
+// flags can contain wxDateTime::Name_Abbr/Name_Full or both of them and lang
+// can be either DateLang_Local (default) to interpret string as a localized
+// month name or DateLang_English to parse it as a standard English name or
+// their combination to interpret it in any way
+wxDateTime::Month
+GetMonthFromName(wxString::const_iterator& p,
+ const wxString::const_iterator& end,
+ int flags,
+ int lang)
+{
+ const wxString::const_iterator pOrig = p;
+ const wxString name = GetAlphaToken(p, end);
+ if ( name.empty() )
+ return wxDateTime::Inv_Month;
+
+ wxDateTime::Month mon;
+ for ( mon = wxDateTime::Jan; mon < wxDateTime::Inv_Month; wxNextMonth(mon) )
+ {
+ // case-insensitive comparison either one of or with both abbreviated
+ // and not versions
+ if ( flags & wxDateTime::Name_Full )
+ {
+ if ( lang & DateLang_English )
+ {
+ if ( name.CmpNoCase(wxDateTime::GetEnglishMonthName(mon,
+ wxDateTime::Name_Full)) == 0 )
+ break;
+ }
+
+ if ( lang & DateLang_Local )
+ {
+ if ( name.CmpNoCase(wxDateTime::GetMonthName(mon,
+ wxDateTime::Name_Full)) == 0 )
+ break;
+ }
+ }
+
+ if ( flags & wxDateTime::Name_Abbr )
+ {
+ if ( lang & DateLang_English )
+ {
+ if ( name.CmpNoCase(wxDateTime::GetEnglishMonthName(mon,
+ wxDateTime::Name_Abbr)) == 0 )
+ break;
+ }
+
+ if ( lang & DateLang_Local )
+ {
+ // some locales (e.g. French one) use periods for the
+ // abbreviated month names but it's never part of name so
+ // compare it specially
+ wxString nameAbbr = wxDateTime::GetMonthName(mon,
+ wxDateTime::Name_Abbr);
+ const bool hasPeriod = *nameAbbr.rbegin() == '.';
+ if ( hasPeriod )
+ nameAbbr.erase(nameAbbr.end() - 1);
+
+ if ( name.CmpNoCase(nameAbbr) == 0 )
+ {
+ if ( hasPeriod )
+ {
+ // skip trailing period if it was part of the match
+ if ( *p == '.' )
+ ++p;
+ else // no match as no matching period
+ continue;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ if ( mon == wxDateTime::Inv_Month )
+ p = pOrig;
+
+ return mon;
+}
+
+// return the weekday if the string is a weekday name or Inv_WeekDay otherwise
+//
+// flags and lang parameters have the same meaning as for GetMonthFromName()
+// above
+wxDateTime::WeekDay
+GetWeekDayFromName(wxString::const_iterator& p,
+ const wxString::const_iterator& end,
+ int flags, int lang)
+{
+ const wxString::const_iterator pOrig = p;
+ const wxString name = GetAlphaToken(p, end);
+ if ( name.empty() )
+ return wxDateTime::Inv_WeekDay;
+
+ wxDateTime::WeekDay wd;
+ for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) )
+ {
+ if ( flags & wxDateTime::Name_Full )
+ {
+ if ( lang & DateLang_English )
+ {
+ if ( name.CmpNoCase(wxDateTime::GetEnglishWeekDayName(wd,
+ wxDateTime::Name_Full)) == 0 )
+ break;
+ }
+
+ if ( lang & DateLang_Local )
+ {
+ if ( name.CmpNoCase(wxDateTime::GetWeekDayName(wd,
+ wxDateTime::Name_Full)) == 0 )
+ break;
+ }
+ }
+
+ if ( flags & wxDateTime::Name_Abbr )
+ {
+ if ( lang & DateLang_English )
+ {
+ if ( name.CmpNoCase(wxDateTime::GetEnglishWeekDayName(wd,
+ wxDateTime::Name_Abbr)) == 0 )
+ break;
+ }
+
+ if ( lang & DateLang_Local )
+ {
+ if ( name.CmpNoCase(wxDateTime::GetWeekDayName(wd,
+ wxDateTime::Name_Abbr)) == 0 )
+ break;
+ }
+ }
+ }
+
+ if ( wd == wxDateTime::Inv_WeekDay )
+ p = pOrig;
+
+ return wd;
+}
+
+// parses string starting at given iterator using the specified format and,
+// optionally, a fall back format (and optionally another one... but it stops
+// there, really)
+//
+// if unsuccessful, returns invalid wxDateTime without changing p; otherwise
+// advance p to the end of the match and returns wxDateTime containing the
+// results of the parsing
+wxDateTime
+ParseFormatAt(wxString::const_iterator& p,
+ const wxString::const_iterator& end,
+ const wxString& fmt,
+ // FIXME-VC6: using wxString() instead of wxEmptyString in the
+ // line below results in error C2062: type 'class
+ // wxString (__cdecl *)(void)' unexpected
+ const wxString& fmtAlt = wxEmptyString)
+{
+ const wxString str(p, end);
+ wxString::const_iterator endParse;
+ wxDateTime dt;
+
+ // Use a default date outside of the DST period to avoid problems with
+ // parsing the time differently depending on the today's date (which is used
+ // as the fall back date if none is explicitly specified).
+ static const wxDateTime dtDef(1, wxDateTime::Jan, 2012);
+
+ if ( dt.ParseFormat(str, fmt, dtDef, &endParse) ||
+ (!fmtAlt.empty() && dt.ParseFormat(str, fmtAlt, dtDef, &endParse)) )
+ {
+ p += endParse - str.begin();
+ }
+ //else: all formats failed
+
+ return dt;
+}
+
+} // anonymous namespace
+
+// ----------------------------------------------------------------------------
+// wxDateTime to/from text representations
+// ----------------------------------------------------------------------------
+
+wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const
+{
+ wxCHECK_MSG( !formatp.empty(), wxEmptyString,
+ wxT("NULL format in wxDateTime::Format") );
+
+ wxString format = formatp;
+#ifdef __WXOSX__
+ format.Replace("%c",wxLocale::GetInfo(wxLOCALE_DATE_TIME_FMT));
+ format.Replace("%x",wxLocale::GetInfo(wxLOCALE_SHORT_DATE_FMT));
+ format.Replace("%X",wxLocale::GetInfo(wxLOCALE_TIME_FMT));
+#endif