]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/datetimefmt.cpp
use the currently active event loop instead of the main one in WakeUpIdle()
[wxWidgets.git] / src / common / datetimefmt.cpp
index 8d2c62fab6779c42b0f1b1ac19efbd0f6fee2437..e6544edd235e16bb769adb1c5ce5d3ba38bdacd3 100644 (file)
@@ -46,7 +46,6 @@
 #endif // WX_PRECOMP
 
 #include "wx/thread.h"
-#include "wx/tokenzr.h"
 
 #include <ctype.h>
 
@@ -92,41 +91,41 @@ static const int MIN_PER_HOUR = 60;
 namespace
 {
 
-#ifdef HAVE_STRPTIME
+// all the functions below taking non-const wxString::const_iterator p advance
+// it until the end of the match
 
-#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
-
-// strptime() wrapper: call strptime() for the string starting at the given
-// iterator and fill output tm struct with the results and modify input to
-// point to the end of the string consumed by strptime() if successful,
-// otherwise return false and don't modify anything
-bool
-CallStrptime(const wxString& str,
-             wxString::const_iterator& p,
-             const char *fmt,
-             tm *tm)
+// 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)
 {
-    // convert from iterator to char pointer: this is simple as wxCStrData
-    // already supports this
-    const char * const start = str.c_str() + (p - str.begin());
-
-    const char * const end = strptime(start, fmt, tm);
-    if ( !end )
-        return false;
+    size_t n = 1;
+    wxString s;
+    while ( p != end && wxIsdigit(*p) )
+    {
+        s += *p++;
 
-    // convert back from char pointer to iterator: unfortunately we have no way
-    // to do it efficiently currently so create a temporary string just to
-    // compute the number of characters between start and end
-    p += wxString(start, end - start).length();
+        if ( len && ++n > len )
+            break;
+    }
 
-    return true;
+    return !s.empty() && s.ToULong(number);
 }
 
-#endif // HAVE_STRPTIME
+// 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
 {
@@ -141,8 +140,16 @@ enum
 // 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(const wxString& name, int flags, int lang)
+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) )
     {
@@ -176,13 +183,35 @@ GetMonthFromName(const wxString& name, int flags, int lang)
 
             if ( lang & DateLang_Local )
             {
-                if ( name.CmpNoCase(wxDateTime::GetMonthName(mon,
-                        wxDateTime::Name_Abbr)) == 0 )
+                // 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;
 }
 
@@ -191,8 +220,15 @@ GetMonthFromName(const wxString& name, int flags, int lang)
 // flags and lang parameters have the same meaning as for GetMonthFromName()
 // above
 wxDateTime::WeekDay
-GetWeekDayFromName(const wxString& name, int flags, int lang)
+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) )
     {
@@ -231,40 +267,10 @@ GetWeekDayFromName(const wxString& name, int flags, int lang)
         }
     }
 
-    return wd;
-}
-
-// 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;
-    }
+    if ( wd == wxDateTime::Inv_WeekDay )
+        p = pOrig;
 
-    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;
+    return wd;
 }
 
 // parses string starting at given iterator using the specified format and,
@@ -281,15 +287,13 @@ ParseFormatAt(wxString::const_iterator& p,
               // 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& fmtAlt2 = wxString())
+              const wxString& fmtAlt = wxEmptyString)
 {
     const wxString str(p, end);
     wxString::const_iterator endParse;
     wxDateTime dt;
     if ( dt.ParseFormat(str, fmt, &endParse) ||
-            (!fmtAlt.empty() && dt.ParseFormat(str, fmtAlt, &endParse)) ||
-                (!fmtAlt2.empty() && dt.ParseFormat(str, fmtAlt2, &endParse)) )
+            (!fmtAlt.empty() && dt.ParseFormat(str, fmtAlt, &endParse)) )
     {
         p += endParse - str.begin();
     }
@@ -304,14 +308,20 @@ ParseFormatAt(wxString::const_iterator& p,
 // wxDateTime to/from text representations
 // ----------------------------------------------------------------------------
 
-wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
+wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const
 {
-    wxCHECK_MSG( !format.empty(), wxEmptyString,
+    wxCHECK_MSG( !formatp.empty(), wxEmptyString,
                  _T("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
     // we have to use our own implementation if the date is out of range of
     // strftime() or if we use non standard specificators
-#ifdef HAVE_STRFTIME
+#ifdef wxHAS_STRFTIME
     time_t time = GetTicks();
 
     if ( (time != (time_t)-1) && !wxStrstr(format, _T("%l")) )
@@ -355,7 +365,7 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
         }
     }
     //else: use generic code below
-#endif // HAVE_STRFTIME
+#endif // wxHAS_STRFTIME
 
     // we only parse ANSI C format specifications here, no POSIX 2
     // complications, no GNU extensions but we do add support for a "%l" format
@@ -432,7 +442,7 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
 
                 case _T('c'):       // locale default date and time  representation
                 case _T('x'):       // locale default date representation
-#ifdef HAVE_STRFTIME
+#ifdef wxHAS_STRFTIME
                     //
                     // the problem: there is no way to know what do these format
                     // specifications correspond to for the current locale.
@@ -548,11 +558,11 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
 
                         res += str;
                     }
-#else // !HAVE_STRFTIME
+#else // !wxHAS_STRFTIME
                     // Use "%m/%d/%y %H:%M:%S" format instead
                     res += wxString::Format(wxT("%02d/%02d/%04d %02d:%02d:%02d"),
                             tm.mon+1,tm.mday, tm.year, tm.hour, tm.min, tm.sec);
-#endif // HAVE_STRFTIME/!HAVE_STRFTIME
+#endif // wxHAS_STRFTIME/!wxHAS_STRFTIME
                     break;
 
                 case _T('d'):       // day of a month (01-31)
@@ -589,11 +599,11 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                     break;
 
                 case _T('p'):       // AM or PM string
-#ifdef HAVE_STRFTIME
+#ifdef wxHAS_STRFTIME
                     res += CallStrftime(_T("%p"), &tmTimeOnly);
-#else // !HAVE_STRFTIME
+#else // !wxHAS_STRFTIME
                     res += (tmTimeOnly.tm_hour > 12) ? wxT("pm") : wxT("am");
-#endif // HAVE_STRFTIME/!HAVE_STRFTIME
+#endif // wxHAS_STRFTIME/!wxHAS_STRFTIME
                     break;
 
                 case _T('S'):       // second as a decimal number (00-61)
@@ -616,11 +626,11 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
 
                 case _T('X'):       // locale default time representation
                     // just use strftime() to format the time for us
-#ifdef HAVE_STRFTIME
+#ifdef wxHAS_STRFTIME
                     res += CallStrftime(_T("%X"), &tmTimeOnly);
-#else // !HAVE_STRFTIME
+#else // !wxHAS_STRFTIME
                     res += wxString::Format(wxT("%02d:%02d:%02d"),tm.hour, tm.min, tm.sec);
-#endif // HAVE_STRFTIME/!HAVE_STRFTIME
+#endif // wxHAS_STRFTIME/!wxHAS_STRFTIME
                     break;
 
                 case _T('y'):       // year without century (00-99)
@@ -632,7 +642,7 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                     break;
 
                 case _T('Z'):       // timezone name
-#ifdef HAVE_STRFTIME
+#ifdef wxHAS_STRFTIME
                     res += CallStrftime(_T("%Z"), &tmTimeOnly);
 #endif
                     break;
@@ -688,19 +698,17 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
 bool
 wxDateTime::ParseRfc822Date(const wxString& date, wxString::const_iterator *end)
 {
+    const wxString::const_iterator pEnd = date.end();
     wxString::const_iterator p = date.begin();
 
     // 1. week day
-    static const int WDAY_LEN = 3;
-    const wxString::const_iterator endWday = p + WDAY_LEN;
-    const wxString wday(p, endWday);
-    if ( GetWeekDayFromName(wday, Name_Abbr, DateLang_English) == Inv_WeekDay )
+    const wxDateTime::WeekDay
+        wd = GetWeekDayFromName(p, pEnd, Name_Abbr, DateLang_English);
+    if ( wd == Inv_WeekDay )
         return false;
     //else: ignore week day for now, we could also check that it really
     //      corresponds to the specified date
 
-    p = endWday;
-
     // 2. separating comma
     if ( *p++ != ',' || *p++ != ' ' )
         return false;
@@ -720,15 +728,10 @@ wxDateTime::ParseRfc822Date(const wxString& date, wxString::const_iterator *end)
         return false;
 
     // 4. month name
-    static const int MONTH_LEN = 3;
-    const wxString::const_iterator endMonth = p + MONTH_LEN;
-    const wxString monName(p, endMonth);
-    Month mon = GetMonthFromName(monName, Name_Abbr, DateLang_English);
+    const Month mon = GetMonthFromName(p, pEnd, Name_Abbr, DateLang_English);
     if ( mon == Inv_Month )
         return false;
 
-    p = endMonth;
-
     if ( *p++ != ' ' )
         return false;
 
@@ -808,7 +811,7 @@ wxDateTime::ParseRfc822Date(const wxString& date, wxString::const_iterator *end)
         return false;
 
     // 7. now the interesting part: the timezone
-    int offset wxDUMMY_INITIALIZE(0);
+    int offset = 0; // just to suppress warnings
     if ( *p == '-' || *p == '+' )
     {
         // the explicit offset given: it has the form of hhmm
@@ -901,383 +904,6 @@ wxDateTime::ParseRfc822Date(const wxString& date, wxString::const_iterator *end)
     return true;
 }
 
-#ifdef __WINDOWS__
-
-// returns the string containing strftime() format used for short dates in the
-// current locale or an empty string
-static wxString GetLocaleDateFormat()
-{
-    wxString fmtWX;
-
-    // there is no setlocale() under Windows CE, so just always query the
-    // system there
-#ifndef __WXWINCE__
-    if ( strcmp(setlocale(LC_ALL, NULL), "C") != 0 )
-#endif
-    {
-        // The locale was programatically set to non-C. We assume that this was
-        // done using wxLocale, in which case thread's current locale is also
-        // set to correct LCID value and we can use GetLocaleInfo to determine
-        // the correct formatting string:
-#ifdef __WXWINCE__
-        LCID lcid = LOCALE_USER_DEFAULT;
-#else
-        LCID lcid = GetThreadLocale();
-#endif
-        // according to MSDN 80 chars is max allowed for short date format
-        wxChar fmt[81];
-        if ( ::GetLocaleInfo(lcid, LOCALE_SSHORTDATE, fmt, WXSIZEOF(fmt)) )
-        {
-            wxChar chLast = _T('\0');
-            size_t lastCount = 0;
-            for ( const wxChar *p = fmt; /* NUL handled inside */; p++ )
-            {
-                if ( *p == chLast )
-                {
-                    lastCount++;
-                    continue;
-                }
-
-                switch ( *p )
-                {
-                    // these characters come in groups, start counting them
-                    case _T('d'):
-                    case _T('M'):
-                    case _T('y'):
-                    case _T('g'):
-                        chLast = *p;
-                        lastCount = 1;
-                        break;
-
-                    default:
-                        // first deal with any special characters we have had
-                        if ( lastCount )
-                        {
-                            switch ( chLast )
-                            {
-                                case _T('d'):
-                                    switch ( lastCount )
-                                    {
-                                        case 1: // d
-                                        case 2: // dd
-                                            // these two are the same as we
-                                            // don't distinguish between 1 and
-                                            // 2 digits for days
-                                            fmtWX += _T("%d");
-                                            break;
-
-                                        case 3: // ddd
-                                            fmtWX += _T("%a");
-                                            break;
-
-                                        case 4: // dddd
-                                            fmtWX += _T("%A");
-                                            break;
-
-                                        default:
-                                            wxFAIL_MSG( _T("too many 'd's") );
-                                    }
-                                    break;
-
-                                case _T('M'):
-                                    switch ( lastCount )
-                                    {
-                                        case 1: // M
-                                        case 2: // MM
-                                            // as for 'd' and 'dd' above
-                                            fmtWX += _T("%m");
-                                            break;
-
-                                        case 3:
-                                            fmtWX += _T("%b");
-                                            break;
-
-                                        case 4:
-                                            fmtWX += _T("%B");
-                                            break;
-
-                                        default:
-                                            wxFAIL_MSG( _T("too many 'M's") );
-                                    }
-                                    break;
-
-                                case _T('y'):
-                                    switch ( lastCount )
-                                    {
-                                        case 1: // y
-                                        case 2: // yy
-                                            fmtWX += _T("%y");
-                                            break;
-
-                                        case 4: // yyyy
-                                            fmtWX += _T("%Y");
-                                            break;
-
-                                        default:
-                                            wxFAIL_MSG( _T("wrong number of 'y's") );
-                                    }
-                                    break;
-
-                                case _T('g'):
-                                    // strftime() doesn't have era string,
-                                    // ignore this format
-                                    wxASSERT_MSG( lastCount <= 2,
-                                                  _T("too many 'g's") );
-                                    break;
-
-                                default:
-                                    wxFAIL_MSG( _T("unreachable") );
-                            }
-
-                            chLast = _T('\0');
-                            lastCount = 0;
-                        }
-
-                        // not a special character so must be just a separator,
-                        // treat as is
-                        if ( *p != _T('\0') )
-                        {
-                            if ( *p == _T('%') )
-                            {
-                                // this one needs to be escaped
-                                fmtWX += _T('%');
-                            }
-
-                            fmtWX += *p;
-                        }
-                }
-
-                if ( *p == _T('\0') )
-                    break;
-            }
-        }
-        //else: GetLocaleInfo() failed, leave fmtDate value unchanged and
-        //      try our luck with the default formats
-    }
-    //else: default C locale, default formats should work
-
-    return fmtWX;
-}
-
-#endif // __WINDOWS__
-
-#ifdef __WXOSX__
-
-#include "wx/osx/private.h"
-
-// under OSX locale formats are defined using
-// http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
-//
-// so we need a translation function, bluntly copied from the windows
-// version above and enhanced with the additional elements needed
-
-static wxString TranslateFromUnicodeFormat(const wxString& fmt)
-{
-    wxString fmtWX;
-
-    wxChar chLast = _T('\0');
-    size_t lastCount = 0;
-    for ( wxString::const_iterator p = fmt.begin(); /* end handled inside */; ++p )
-    {
-        if ( p == fmt.end() || *p == chLast )
-        {
-            lastCount++;
-            if ( p == fmt.end() )
-                break;
-
-            continue;
-        }
-
-        switch ( (*p).GetValue() )
-        {
-            // these characters come in groups, start counting them
-            case _T('d'):
-            case _T('M'):
-            case _T('y'):
-            case _T('g'):
-            case _T('h'):
-            case _T('H'):
-            case _T('m'):
-            case _T('s'):
-                chLast = *p;
-                lastCount = 1;
-                break;
-
-            default:
-                // first deal with any special characters we have had
-                if ( lastCount )
-                {
-                    switch ( chLast )
-                    {
-                        case _T('d'):
-                            switch ( lastCount )
-                            {
-                                case 1: // d
-                                case 2: // dd
-                                    // these two are the same as we
-                                    // don't distinguish between 1 and
-                                    // 2 digits for days
-                                    fmtWX += _T("%d");
-                                    break;
-
-                                case 3: // ddd
-                                    fmtWX += _T("%a");
-                                    break;
-
-                                case 4: // dddd
-                                    fmtWX += _T("%A");
-                                    break;
-
-                                default:
-                                    wxFAIL_MSG( _T("too many 'd's") );
-                            }
-                            break;
-
-                        case _T('M'):
-                            switch ( lastCount )
-                            {
-                                case 1: // M
-                                case 2: // MM
-                                    // as for 'd' and 'dd' above
-                                    fmtWX += _T("%m");
-                                    break;
-
-                                case 3:
-                                    fmtWX += _T("%b");
-                                    break;
-
-                                case 4:
-                                    fmtWX += _T("%B");
-                                    break;
-
-                                default:
-                                    wxFAIL_MSG( _T("too many 'M's") );
-                            }
-                            break;
-
-                        case _T('y'):
-                            switch ( lastCount )
-                            {
-                                case 1: // y
-                                case 2: // yy
-                                    fmtWX += _T("%y");
-                                    break;
-
-                                case 4: // yyyy
-                                    fmtWX += _T("%Y");
-                                    break;
-
-                                default:
-                                    wxFAIL_MSG( _T("wrong number of 'y's") );
-                            }
-                            break;
-
-                        case _T('H'):
-                            switch ( lastCount )
-                            {
-                                case 1: // H
-                                case 2: // HH
-                                    fmtWX += _T("%H");
-                                    break;
-
-                                default:
-                                    wxFAIL_MSG( _T("wrong number of 'H's") );
-                            }
-                            break;
-
-                       case _T('h'):
-                            switch ( lastCount )
-                            {
-                                case 1: // h
-                                case 2: // hh
-                                    fmtWX += _T("%h");
-                                    break;
-
-                                default:
-                                    wxFAIL_MSG( _T("wrong number of 'h's") );
-                            }
-                            break;
-
-                       case _T('m'):
-                            switch ( lastCount )
-                            {
-                                case 1: // m
-                                case 2: // mm
-                                    fmtWX += _T("%M");
-                                    break;
-
-                                default:
-                                    wxFAIL_MSG( _T("wrong number of 'm's") );
-                            }
-                            break;
-
-                       case _T('s'):
-                            switch ( lastCount )
-                            {
-                                case 1: // s
-                                case 2: // ss
-                                    fmtWX += _T("%S");
-                                    break;
-
-                                default:
-                                    wxFAIL_MSG( _T("wrong number of 's's") );
-                            }
-                            break;
-
-                        case _T('g'):
-                            // strftime() doesn't have era string,
-                            // ignore this format
-                            wxASSERT_MSG( lastCount <= 2,
-                                          _T("too many 'g's") );
-                            break;
-
-                        default:
-                            wxFAIL_MSG( _T("unreachable") );
-                    }
-
-                    chLast = _T('\0');
-                    lastCount = 0;
-                }
-
-                // not a special character so must be just a separator,
-                // treat as is
-                if ( *p == _T('%') )
-                {
-                    // this one needs to be escaped
-                    fmtWX += _T('%');
-                }
-
-                fmtWX += *p;
-        }
-    }
-
-    return fmtWX;
-}
-
-static wxString GetLocaleDateFormat()
-{
-    wxCFRef<CFLocaleRef> currentLocale( CFLocaleCopyCurrent() );
-
-    wxCFRef<CFDateFormatterRef> dateFormatter( CFDateFormatterCreate
-        (NULL, currentLocale, kCFDateFormatterShortStyle, kCFDateFormatterNoStyle));
-    wxCFStringRef cfs = wxCFRetain( CFDateFormatterGetFormat(dateFormatter ));
-    return TranslateFromUnicodeFormat(cfs.AsString());
-}
-
-static wxString GetLocaleFullDateFormat()
-{
-    wxCFRef<CFLocaleRef> currentLocale( CFLocaleCopyCurrent() );
-
-    wxCFRef<CFDateFormatterRef> dateFormatter( CFDateFormatterCreate
-        (NULL, currentLocale, kCFDateFormatterLongStyle, kCFDateFormatterMediumStyle));
-    wxCFStringRef cfs = wxCFRetain( CFDateFormatterGetFormat(dateFormatter ));
-    return TranslateFromUnicodeFormat(cfs.AsString());
-}
-
-
-
-#endif // __WXOSX__
-
 bool
 wxDateTime::ParseFormat(const wxString& date,
                         const wxString& format,
@@ -1325,7 +951,7 @@ wxDateTime::ParseFormat(const wxString& date,
             {
                 // a white space in the format string matches 0 or more white
                 // spaces in the input
-                while ( wxIsspace(*input) )
+                while ( input != end && wxIsspace(*input) )
                 {
                     input++;
                 }
@@ -1334,7 +960,7 @@ wxDateTime::ParseFormat(const wxString& date,
             {
                 // any other character (not whitespace, not '%') must be
                 // matched by itself in the input
-                if ( *input++ != *fmt )
+                if ( input == end || *input++ != *fmt )
                 {
                     // no match
                     return false;
@@ -1387,7 +1013,7 @@ wxDateTime::ParseFormat(const wxString& date,
                 {
                     wday = GetWeekDayFromName
                            (
-                            GetAlphaToken(input, end),
+                            input, end,
                             *fmt == 'a' ? Name_Abbr : Name_Full,
                             DateLang_Local
                            );
@@ -1405,7 +1031,7 @@ wxDateTime::ParseFormat(const wxString& date,
                 {
                     mon = GetMonthFromName
                           (
-                            GetAlphaToken(input, end),
+                            input, end,
                             *fmt == 'b' ? Name_Abbr : Name_Full,
                             DateLang_Local
                           );
@@ -1420,71 +1046,38 @@ wxDateTime::ParseFormat(const wxString& date,
 
             case _T('c'):       // locale default date and time  representation
                 {
-#ifdef HAVE_STRPTIME
-                    struct tm tm;
+                    wxDateTime dt;
 
-                    // 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
-                    if ( CallStrptime(date, input, "%c", &tm) )
-                    {
-                        hour = tm.tm_hour;
-                        min = tm.tm_min;
-                        sec = tm.tm_sec;
+                    const wxString
+                        fmtDateTime = wxLocale::GetInfo(wxLOCALE_DATE_TIME_FMT);
+                    if ( !fmtDateTime.empty() )
+                        dt = ParseFormatAt(input, end, fmtDateTime);
 
-                        year = 1900 + tm.tm_year;
-                        mon = (Month)tm.tm_mon;
-                        mday = tm.tm_mday;
+                    if ( !dt.IsValid() )
+                    {
+                        // also try the format which corresponds to ctime()
+                        // output (i.e. the "C" locale default)
+                        dt = ParseFormatAt(input, end, wxS("%a %b %d %H:%M:%S %Y"));
                     }
-                    else // strptime() failed; try generic heuristic code
-#endif // HAVE_STRPTIME
+
+                    if ( !dt.IsValid() )
                     {
-                        Tm tm;
-#ifdef __WXOSX__
-                        bool hasValidDate = false;
-                        wxString fmtDate = GetLocaleFullDateFormat();
-                        if ( !fmtDate.empty() )
-                        {
-                            const wxDateTime dt = ParseFormatAt
-                                                (
-                                                    input,
-                                                    end,
-                                                    fmtDate
-                                                );
-                            if ( dt.IsValid() )
-                            {
-                                tm = dt.GetTm();
-                                hasValidDate = true;
-                            }
-                        }
+                        // and finally also the two generic date/time formats
+                        dt = ParseFormatAt(input, end, wxS("%x %X"), wxS("%X %x"));
+                    }
 
-                        if ( !hasValidDate )
-#endif // __WXOSX__
-                        {
-                            // try the format which corresponds to ctime() output
-                            // first, then the generic date/time formats
-                            const wxDateTime dt = ParseFormatAt
-                                                (
-                                                    input,
-                                                    end,
-                                                    wxS("%a %b %d %H:%M:%S %Y"),
-                                                    wxS("%x %X"),
-                                                    wxS("%X %x")
-                                                );
-                            if ( !dt.IsValid() )
-                                return false;
-                            tm = dt.GetTm();
-                        }
+                    if ( !dt.IsValid() )
+                        return false;
 
+                    const Tm tm = dt.GetTm();
 
-                        hour = tm.hour;
-                        min = tm.min;
-                        sec = tm.sec;
+                    hour = tm.hour;
+                    min = tm.min;
+                    sec = tm.sec;
 
-                        year = tm.year;
-                        mon = tm.mon;
-                        mday = tm.mday;
-                    }
+                    year = tm.year;
+                    mon = tm.mon;
+                    mday = tm.mday;
 
                     haveDay = haveMon = haveYear =
                     haveHour = haveMin = haveSec = true;
@@ -1575,25 +1168,25 @@ wxDateTime::ParseFormat(const wxString& date,
 
             case _T('p'):       // AM or PM string
                 {
-                    wxString am, pm, token = GetAlphaToken(input, end);
+                    wxString am, pm;
+                    GetAmPmStrings(&am, &pm);
 
-                    // 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;
+                    // we can never match %p in locales which don't use AM/PM
+                    if ( am.empty() || pm.empty() )
+                        return false;
 
-                    GetAmPmStrings(&am, &pm);
-                    if (am.empty() && pm.empty())
-                        return false;  // no am/pm strings defined
-                    if ( token.CmpNoCase(pm) == 0 )
+                    const size_t pos = input - date.begin();
+                    if ( date.compare(pos, pm.length(), pm) == 0 )
                     {
                         isPM = true;
+                        input += pm.length();
                     }
-                    else if ( token.CmpNoCase(am) != 0 )
+                    else if ( date.compare(pos, am.length(), am) == 0 )
+                    {
+                        input += am.length();
+                    }
+                    else // no match
                     {
-                        // no match
                         return false;
                     }
                 }
@@ -1608,7 +1201,7 @@ wxDateTime::ParseFormat(const wxString& date,
 
                     haveHour = haveMin = haveSec = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                     sec = tm.sec;
@@ -1625,7 +1218,7 @@ wxDateTime::ParseFormat(const wxString& date,
                     haveHour =
                     haveMin = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                 }
@@ -1654,7 +1247,7 @@ wxDateTime::ParseFormat(const wxString& date,
                     haveMin =
                     haveSec = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                     sec = tm.sec;
@@ -1674,77 +1267,41 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('x'):       // locale default date representation
-#ifdef HAVE_STRPTIME
-                // 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
-                {
-                    struct tm tm;
-
-                    if ( CallStrptime(date, input, "%x", &tm) )
-                    {
-                        haveDay = haveMon = haveYear = true;
-
-                        year = 1900 + tm.tm_year;
-                        mon = (Month)tm.tm_mon;
-                        mday = tm.tm_mday;
-
-                        break;
-                    }
-                }
-#endif // HAVE_STRPTIME
-
                 {
-                    wxString fmtDate,
-                             fmtDateAlt;
+                    wxString
+                        fmtDate = wxLocale::GetInfo(wxLOCALE_SHORT_DATE_FMT),
+                        fmtDateAlt = wxLocale::GetInfo(wxLOCALE_LONG_DATE_FMT);
 
-#if defined( __WINDOWS__ ) || defined( __WXOSX__ )
-                    // The above doesn't work for all locales, try to query
-                    // the OS for the right way of formatting the date:
-                    fmtDate = GetLocaleDateFormat();
                     if ( fmtDate.empty() )
-#endif // __WINDOWS__
                     {
                         if ( IsWestEuropeanCountry(GetCountry()) ||
                              GetCountry() == Russia )
                         {
-                            fmtDate = _T("%d/%m/%y");
-                            fmtDateAlt = _T("%m/%d/%y");
+                            fmtDate = wxS("%d/%m/%Y");
+                            fmtDateAlt = wxS("%m/%d/%Y");
                          }
                         else // assume USA
                         {
-                            fmtDate = _T("%m/%d/%y");
-                            fmtDateAlt = _T("%d/%m/%y");
+                            fmtDate = wxS("%m/%d/%Y");
+                            fmtDateAlt = wxS("%d/%m/%Y");
                         }
                     }
 
-                    const wxDateTime
-                        dt = ParseFormatAt(input, end,
-                                           fmtDate, fmtDateAlt);
-                    Tm tm;
+                    wxDateTime
+                        dt = ParseFormatAt(input, end, fmtDate, fmtDateAlt);
 
                     if ( !dt.IsValid() )
                     {
-                        wxString fmtDateLong = fmtDate;
-                        wxString fmtDateLongAlt = fmtDateAlt;
-
+                        // try with short years too
+                        fmtDate.Replace("%Y","%y");
+                        fmtDateAlt.Replace("%Y","%y");
+                        dt = ParseFormatAt(input, end, fmtDate, fmtDateAlt);
 
-                        if ( !fmtDateLong.empty() )
-                        {
-                            fmtDateLong.Replace("%y","%Y");
-                            fmtDateLongAlt.Replace("%y","%Y");
-                            const wxDateTime dtLong = ParseFormatAt(input, end,
-                                           fmtDateLong, fmtDateLongAlt);
-                            if ( !dtLong.IsValid() )
-                                return false;
-
-                            tm = dtLong.GetTm();
-                        }
-                        else
+                        if ( !dt.IsValid() )
                             return false;
                     }
-                    else
-                        tm = dt.GetTm();
+
+                    const Tm tm = dt.GetTm();
 
                     haveDay =
                     haveMon =
@@ -1758,29 +1315,21 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('X'):       // locale default time representation
-#ifdef HAVE_STRPTIME
                 {
-                    // use strptime() to do it for us (FIXME !Unicode friendly)
-                    struct tm tm;
-                    if ( !CallStrptime(date, input, "%X", &tm) )
-                        return false;
+                    wxString fmtTime = wxLocale::GetInfo(wxLOCALE_TIME_FMT),
+                             fmtTimeAlt;
 
-                    haveHour = haveMin = haveSec = true;
+                    if ( fmtTime.empty() )
+                    {
+                        // try to parse what follows as "%H:%M:%S" and, if this
+                        // fails, as "%I:%M:%S %p" - this should catch the most
+                        // common cases
+                        fmtTime = "%T";
+                        fmtTimeAlt = "%r";
+                    }
 
-                    hour = tm.tm_hour;
-                    min = tm.tm_min;
-                    sec = tm.tm_sec;
-                }
-#else // !HAVE_STRPTIME
-                // TODO under Win32 we can query the LOCALE_ITIME system
-                //      setting which says whether the default time format is
-                //      24 or 12 hour
-                {
-                    // try to parse what follows as "%H:%M:%S" and, if this
-                    // fails, as "%I:%M:%S %p" - this should catch the most
-                    // common cases
                     const wxDateTime
-                        dt = ParseFormatAt(input, end, "%T", "%r");
+                        dt = ParseFormatAt(input, end, fmtTime, fmtTimeAlt);
                     if ( !dt.IsValid() )
                         return false;
 
@@ -1788,12 +1337,11 @@ wxDateTime::ParseFormat(const wxString& date,
                     haveMin =
                     haveSec = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                     sec = tm.sec;
                 }
-#endif // HAVE_STRPTIME/!HAVE_STRPTIME
                 break;
 
             case _T('y'):       // year without century (00-99)
@@ -1823,7 +1371,9 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('Z'):       // timezone name
-                wxFAIL_MSG(_T("TODO"));
+                // FIXME: currently we just ignore everything that looks like a
+                //        time zone here
+                GetAlphaToken(input, end);
                 break;
 
             case _T('%'):       // a percent sign
@@ -1998,6 +1548,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
     // all esoteric constructions ParseDateTime() knows about)
 
     const wxString::const_iterator pBegin = date.begin();
+    const wxString::const_iterator pEnd = date.end();
 
     wxString::const_iterator p = pBegin;
     while ( wxIsspace(*p) )
@@ -2015,7 +1566,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
         { wxTRANSLATE("tomorrow"),          1 },
     };
 
-    const size_t lenRest = date.end() - p;
+    const size_t lenRest = pEnd - p;
     for ( size_t n = 0; n < WXSIZEOF(literalDates); n++ )
     {
         const wxString dateStr = wxGetTranslation(literalDates[n].str);
@@ -2055,6 +1606,8 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
          haveMon = false,       // the month?
          haveYear = false;      // the year?
 
+    bool monWasNumeric = false; // was month specified as a number?
+
     // and the value of the items we have (init them to get rid of warnings)
     WeekDay wday = Inv_WeekDay;
     wxDateTime_t day = 0;
@@ -2062,18 +1615,22 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
     int year = 0;
 
     // tokenize the string
-    size_t nPosCur = 0;
-    static const wxStringCharType *dateDelimiters = wxS(".,/-\t\r\n ");
-    wxStringTokenizer tok(wxString(p, date.end()), dateDelimiters);
-    while ( tok.HasMoreTokens() )
+    while ( p != pEnd )
     {
-        wxString token = tok.GetNextToken();
-        if ( !token )
-            continue;
+        // skip white space and date delimiters
+        while ( wxStrchr(".,/-\t\r\n ", *p) )
+        {
+            ++p;
+        }
 
-        // is it a number?
+        // modify copy of the iterator as we're not sure if the next token is
+        // still part of the date at all
+        wxString::const_iterator pCopy = p;
+
+        // we can have either alphabetic or numeric token, start by testing if
+        // it's the latter
         unsigned long val;
-        if ( token.ToULong(&val) )
+        if ( GetNumericToken(10 /* max length */, pCopy, pEnd, &val) )
         {
             // guess what this number is
 
@@ -2137,6 +1694,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
             else if ( isMonth )
             {
                 haveMon = true;
+                monWasNumeric = true;
 
                 mon = (Month)(val - 1);
             }
@@ -2146,7 +1704,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
             // be careful not to overwrite the current mon value
             Month mon2 = GetMonthFromName
                          (
-                            token,
+                            pCopy, pEnd,
                             Name_Full | Name_Abbr,
                             DateLang_Local | DateLang_English
                          );
@@ -2155,20 +1713,18 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
                 // it's a month
                 if ( haveMon )
                 {
-                    // but we already have a month - maybe we guessed wrong?
-                    if ( !haveDay )
-                    {
-                        // no need to check in month range as always < 12, but
-                        // the days are counted from 1 unlike the months
-                        day = (wxDateTime_t)(mon + 1);
-                        haveDay = true;
-                    }
-                    else
-                    {
-                        // could possible be the year (doesn't the year come
-                        // before the month in the japanese format?) (FIXME)
+                    // but we already have a month - maybe we guessed wrong
+                    // when we had interpreted that numeric value as a month
+                    // and it was the day number instead?
+                    if ( haveDay || !monWasNumeric )
                         break;
-                    }
+
+                    // assume we did and change our mind: reinterpret the month
+                    // value as a day (notice that there is no need to check
+                    // that it is valid as month values are always < 12, but
+                    // the days are counted from 1 unlike the months)
+                    day = (wxDateTime_t)(mon + 1);
+                    haveDay = true;
                 }
 
                 mon = mon2;
@@ -2179,7 +1735,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
             {
                 WeekDay wday2 = GetWeekDayFromName
                                 (
-                                    token,
+                                    pCopy, pEnd,
                                     Name_Full | Name_Abbr,
                                     DateLang_Local | DateLang_English
                                 );
@@ -2187,9 +1743,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
                 {
                     // a week day
                     if ( haveWDay )
-                    {
                         break;
-                    }
 
                     wday = wday2;
 
@@ -2227,8 +1781,11 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
                     size_t n;
                     for ( n = 0; n < WXSIZEOF(ordinals); n++ )
                     {
-                        if ( token.CmpNoCase(ordinals[n]) == 0 )
+                        const wxString ord = wxGetTranslation(ordinals[n]);
+                        const size_t len = ord.length();
+                        if ( date.compare(p - pBegin, len, ord) == 0 )
                         {
+                            p += len;
                             break;
                         }
                     }
@@ -2255,7 +1812,8 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
             }
         }
 
-        nPosCur = tok.GetPosition();
+        // advance iterator past a successfully parsed token
+        p = pCopy;
     }
 
     // either no more tokens or the scan was stopped by something we couldn't
@@ -2331,15 +1889,6 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
         SetToWeekDayInSameWeek(wday);
     }
 
-    // return the pointer to the first unparsed char
-    p += nPosCur;
-    if ( nPosCur && wxStrchr(dateDelimiters, *(p - 1)) )
-    {
-        // if we couldn't parse the token after the delimiter, put back the
-        // delimiter as well
-        p--;
-    }
-
     *end = p;
 
     return true;