]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/datetimefmt.cpp
Return NULL from wxWindow::GetCapture() when the capture is being lost.
[wxWidgets.git] / src / common / datetimefmt.cpp
index f53e183dade438a9e8a6bd3fcd84ea0ba3df0e85..485502505018c2c6bd2681b5ee2207ffb76a0711 100644 (file)
@@ -4,7 +4,6 @@
 // Author:      Vadim Zeitlin
 // Modified by:
 // Created:     11.05.99
-// RCS-ID:      $Id$
 // Copyright:   (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
 //              parts of code taken from sndcal library by Scott E. Lee:
 //
@@ -34,7 +33,7 @@
 #if !defined(wxUSE_DATETIME) || wxUSE_DATETIME
 
 #ifndef WX_PRECOMP
-    #ifdef __WXMSW__
+    #ifdef __WINDOWS__
         #include "wx/msw/wrapwin.h"
     #endif
     #include "wx/string.h"
@@ -46,7 +45,6 @@
 #endif // WX_PRECOMP
 
 #include "wx/thread.h"
-#include "wx/tokenzr.h"
 
 #include <ctype.h>
 
 #endif
 
 #include "wx/datetime.h"
+#include "wx/time.h"
 
 // ============================================================================
 // implementation of wxDateTime
 // ============================================================================
 
 // ----------------------------------------------------------------------------
-// wxDateTime to/from text representations
+// helpers shared between datetime.cpp and datetimefmt.cpp
+// ----------------------------------------------------------------------------
+
+extern void InitTm(struct tm& tm);
+
+extern wxString CallStrftime(const wxString& format, const tm* tm);
+
+// ----------------------------------------------------------------------------
+// constants (see also datetime.cpp)
+// ----------------------------------------------------------------------------
+
+static const int DAYS_PER_WEEK = 7;
+
+static const int HOURS_PER_DAY = 24;
+
+static const int SEC_PER_MIN = 60;
+
+static const int MIN_PER_HOUR = 60;
+
+// ----------------------------------------------------------------------------
+// parsing helpers
 // ----------------------------------------------------------------------------
 
-wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
+namespace
 {
-    wxCHECK_MSG( !format.empty(), wxEmptyString,
-                 _T("NULL format in wxDateTime::Format") );
 
+// 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
     // 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
+    // strftime() or if we use non standard specifiers (notice that "%z" is
+    // special because it is de facto standard under Unix but is not supported
+    // under Windows)
+#ifdef wxHAS_STRFTIME
     time_t time = GetTicks();
 
-    if ( (time != (time_t)-1) && !wxStrstr(format, _T("%l")) )
+    if ( (time != (time_t)-1) && !wxStrstr(format, wxT("%l"))
+#ifdef __WINDOWS__
+            && !wxStrstr(format, wxT("%z"))
+#endif
+       )
     {
         // use strftime()
         struct tm tmstruct;
         struct tm *tm;
-        if ( tz.GetOffset() == -GetTimeZone() )
+        if ( tz.GetOffset() == -wxGetTimeZone() )
         {
             // we are working with local time
             tm = wxLocaltime_r(&time, &tmstruct);
 
             // should never happen
-            wxCHECK_MSG( tm, wxEmptyString, _T("wxLocaltime_r() failed") );
+            wxCHECK_MSG( tm, wxEmptyString, wxT("wxLocaltime_r() failed") );
         }
         else
         {
@@ -104,7 +361,7 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                 tm = wxGmtime_r(&time, &tmstruct);
 
                 // should never happen
-                wxCHECK_MSG( tm, wxEmptyString, _T("wxGmtime_r() failed") );
+                wxCHECK_MSG( tm, wxEmptyString, wxT("wxGmtime_r() failed") );
             }
             else
             {
@@ -118,7 +375,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
@@ -127,12 +384,11 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
 
     // used for calls to strftime() when we only deal with time
     struct tm tmTimeOnly;
+    memset(&tmTimeOnly, 0, sizeof(tmTimeOnly));
     tmTimeOnly.tm_hour = tm.hour;
     tmTimeOnly.tm_min = tm.min;
     tmTimeOnly.tm_sec = tm.sec;
-    tmTimeOnly.tm_wday = 0;
-    tmTimeOnly.tm_yday = 0;
-    tmTimeOnly.tm_mday = 1;         // any date will do
+    tmTimeOnly.tm_mday = 1;         // any date will do, use 1976-01-01
     tmTimeOnly.tm_mon = 0;
     tmTimeOnly.tm_year = 76;
     tmTimeOnly.tm_isdst = 0;        // no DST, we adjust for tz ourselves
@@ -140,7 +396,7 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
     wxString tmp, res, fmt;
     for ( wxString::const_iterator p = format.begin(); p != format.end(); ++p )
     {
-        if ( *p != _T('%') )
+        if ( *p != wxT('%') )
         {
             // copy as is
             res += *p;
@@ -151,17 +407,18 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
         // set the default format
         switch ( (*++p).GetValue() )
         {
-            case _T('Y'):               // year has 4 digits
-                fmt = _T("%04d");
+            case wxT('Y'):               // year has 4 digits
+            case wxT('z'):               // time zone as well
+                fmt = wxT("%04d");
                 break;
 
-            case _T('j'):               // day of year has 3 digits
-            case _T('l'):               // milliseconds have 3 digits
-                fmt = _T("%03d");
+            case wxT('j'):               // day of year has 3 digits
+            case wxT('l'):               // milliseconds have 3 digits
+                fmt = wxT("%03d");
                 break;
 
-            case _T('w'):               // week day as number has only one
-                fmt = _T("%d");
+            case wxT('w'):               // week day as number has only one
+                fmt = wxT("%d");
                 break;
 
             default:
@@ -169,7 +426,7 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                 // the format is "%02d" (for all the rest) or we have the
                 // field width preceding the format in which case it will
                 // override the default format anyhow
-                fmt = _T("%02d");
+                fmt = wxT("%02d");
         }
 
         bool restart = true;
@@ -180,22 +437,22 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
             // start of the format specification
             switch ( (*p).GetValue() )
             {
-                case _T('a'):       // a weekday name
-                case _T('A'):
+                case wxT('a'):       // a weekday name
+                case wxT('A'):
                     // second parameter should be true for abbreviated names
                     res += GetWeekDayName(tm.GetWeekDay(),
-                                          *p == _T('a') ? Name_Abbr : Name_Full);
+                                          *p == wxT('a') ? Name_Abbr : Name_Full);
                     break;
 
-                case _T('b'):       // a month name
-                case _T('B'):
+                case wxT('b'):       // a month name
+                case wxT('B'):
                     res += GetMonthName(tm.mon,
-                                        *p == _T('b') ? Name_Abbr : Name_Full);
+                                        *p == wxT('b') ? Name_Abbr : Name_Full);
                     break;
 
-                case _T('c'):       // locale default date and time  representation
-                case _T('x'):       // locale default date representation
-#ifdef HAVE_STRFTIME
+                case wxT('c'):       // locale default date and time  representation
+                case wxT('x'):       // locale default date representation
+#ifdef wxHAS_STRFTIME
                     //
                     // the problem: there is no way to know what do these format
                     // specifications correspond to for the current locale.
@@ -256,7 +513,7 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                         // (indirectly) set the year correctly
                         while ( (nLostWeekDays % 7) != 0 )
                         {
-                            nLostWeekDays += year++ % 4 ? 1 : 2;
+                            nLostWeekDays += (year++ % 4) ? 1 : 2;
                         }
 
                         // finally move the year below 2000 so that the 2-digit
@@ -266,7 +523,7 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                             year -= 28;
 
                         wxASSERT_MSG( year >= 1970 && year < 2000,
-                                      _T("logic error in wxDateTime::Format") );
+                                      wxT("logic error in wxDateTime::Format") );
 
 
                         // use strftime() to format the same date but in supported
@@ -287,8 +544,8 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                         tmAdjusted.tm_mon = tm.mon;
                         tmAdjusted.tm_year = year - 1900;
                         tmAdjusted.tm_isdst = 0; // no DST, already adjusted
-                        wxString str = CallStrftime(*p == _T('c') ? _T("%c")
-                                                                  : _T("%x"),
+                        wxString str = CallStrftime(*p == wxT('c') ? wxT("%c")
+                                                                  : wxT("%x"),
                                                     &tmAdjusted);
 
                         // now replace the replacement year with the real year:
@@ -311,22 +568,22 @@ 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)
+                case wxT('d'):       // day of a month (01-31)
                     res += wxString::Format(fmt, tm.mday);
                     break;
 
-                case _T('H'):       // hour in 24h format (00-23)
+                case wxT('H'):       // hour in 24h format (00-23)
                     res += wxString::Format(fmt, tm.hour);
                     break;
 
-                case _T('I'):       // hour in 12h format (01-12)
+                case wxT('I'):       // hour in 12h format (01-12)
                     {
                         // 24h -> 12h, 0h -> 12h too
                         int hour12 = tm.hour > 12 ? tm.hour - 12
@@ -335,76 +592,108 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                     }
                     break;
 
-                case _T('j'):       // day of the year
+                case wxT('j'):       // day of the year
                     res += wxString::Format(fmt, GetDayOfYear(tz));
                     break;
 
-                case _T('l'):       // milliseconds (NOT STANDARD)
+                case wxT('l'):       // milliseconds (NOT STANDARD)
                     res += wxString::Format(fmt, GetMillisecond(tz));
                     break;
 
-                case _T('m'):       // month as a number (01-12)
+                case wxT('m'):       // month as a number (01-12)
                     res += wxString::Format(fmt, tm.mon + 1);
                     break;
 
-                case _T('M'):       // minute as a decimal number (00-59)
+                case wxT('M'):       // minute as a decimal number (00-59)
                     res += wxString::Format(fmt, tm.min);
                     break;
 
-                case _T('p'):       // AM or PM string
-#ifdef HAVE_STRFTIME
-                    res += CallStrftime(_T("%p"), &tmTimeOnly);
-#else // !HAVE_STRFTIME
+                case wxT('p'):       // AM or PM string
+#ifdef wxHAS_STRFTIME
+                    res += CallStrftime(wxT("%p"), &tmTimeOnly);
+#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)
+                case wxT('S'):       // second as a decimal number (00-61)
                     res += wxString::Format(fmt, tm.sec);
                     break;
 
-                case _T('U'):       // week number in the year (Sunday 1st week day)
+                case wxT('U'):       // week number in the year (Sunday 1st week day)
                     res += wxString::Format(fmt, GetWeekOfYear(Sunday_First, tz));
                     break;
 
-                case _T('W'):       // week number in the year (Monday 1st week day)
+                case wxT('W'):       // week number in the year (Monday 1st week day)
                     res += wxString::Format(fmt, GetWeekOfYear(Monday_First, tz));
                     break;
 
-                case _T('w'):       // weekday as a number (0-6), Sunday = 0
+                case wxT('w'):       // weekday as a number (0-6), Sunday = 0
                     res += wxString::Format(fmt, tm.GetWeekDay());
                     break;
 
-                // case _T('x'): -- handled with "%c"
+                // case wxT('x'): -- handled with "%c"
 
-                case _T('X'):       // locale default time representation
+                case wxT('X'):       // locale default time representation
                     // just use strftime() to format the time for us
-#ifdef HAVE_STRFTIME
-                    res += CallStrftime(_T("%X"), &tmTimeOnly);
-#else // !HAVE_STRFTIME
+#ifdef wxHAS_STRFTIME
+                    res += CallStrftime(wxT("%X"), &tmTimeOnly);
+#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)
+                case wxT('y'):       // year without century (00-99)
                     res += wxString::Format(fmt, tm.year % 100);
                     break;
 
-                case _T('Y'):       // year with century
+                case wxT('Y'):       // year with century
                     res += wxString::Format(fmt, tm.year);
                     break;
 
-                case _T('Z'):       // timezone name
-#ifdef HAVE_STRFTIME
-                    res += CallStrftime(_T("%Z"), &tmTimeOnly);
+                case wxT('z'):       // time zone as [-+]HHMM
+                    {
+                        int ofs = tz.GetOffset();
+
+                        // The time zone offset does not include the DST, but
+                        // we do need to take it into account when showing the
+                        // time in the local time zone to the user.
+                        if ( ofs == -wxGetTimeZone() && IsDST() == 1 )
+                        {
+                            // FIXME: As elsewhere in wxDateTime, we assume
+                            // that the DST is always 1 hour, but this is not
+                            // true in general.
+                            ofs += 3600;
+                        }
+
+                        if ( ofs < 0 )
+                        {
+                            res += '-';
+                            ofs = -ofs;
+                        }
+                        else
+                        {
+                            res += '+';
+                        }
+
+                        // Converts seconds to HHMM representation.
+                        res += wxString::Format(fmt,
+                                                100*(ofs/3600) + (ofs/60)%60);
+                    }
+                    break;
+
+                case wxT('Z'):       // timezone name
+#ifdef wxHAS_STRFTIME
+                    res += CallStrftime(wxT("%Z"), &tmTimeOnly);
 #endif
                     break;
 
                 default:
                     // is it the format width?
-                    fmt.Empty();
-                    while ( *p == _T('-') || *p == _T('+') ||
-                            *p == _T(' ') || wxIsdigit(*p) )
+                    for ( fmt.clear();
+                          *p == wxT('-') || *p == wxT('+') ||
+                            *p == wxT(' ') || wxIsdigit(*p);
+                          ++p )
                     {
                         fmt += *p;
                     }
@@ -412,8 +701,8 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                     if ( !fmt.empty() )
                     {
                         // we've only got the flags and width so far in fmt
-                        fmt.Prepend(_T('%'));
-                        fmt.Append(_T('d'));
+                        fmt.Prepend(wxT('%'));
+                        fmt.Append(wxT('d'));
 
                         restart = true;
 
@@ -421,19 +710,19 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                     }
 
                     // no, it wasn't the width
-                    wxFAIL_MSG(_T("unknown format specificator"));
+                    wxFAIL_MSG(wxT("unknown format specifier"));
 
                     // fall through and just copy it nevertheless
 
-                case _T('%'):       // a percent sign
+                case wxT('%'):       // a percent sign
                     res += *p;
                     break;
 
                 case 0:             // the end of string
-                    wxFAIL_MSG(_T("missing format at the end of string"));
+                    wxFAIL_MSG(wxT("missing format at the end of string"));
 
                     // just put the '%' which was the last char in format
-                    res += _T('%');
+                    res += wxT('%');
                     break;
             }
         }
@@ -448,226 +737,149 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
 //
 // this function is "strict" by design - it must reject anything except true
 // RFC822 time specs.
-//
-// TODO a great candidate for using reg exps
-const char *
+bool
 wxDateTime::ParseRfc822Date(const wxString& date, wxString::const_iterator *end)
 {
-    // TODO: rewrite using iterators instead of wxChar pointers
-    const wxStringCharType *p = date.wx_str();
-    const wxStringCharType *comma = wxStrchr(p, wxS(','));
-    if ( comma )
-    {
-        // the part before comma is the weekday
-
-        // skip it for now - we don't use but might check that it really
-        // corresponds to the specfied date
-        p = comma + 1;
-
-        if ( *p != _T(' ') )
-        {
-            wxLogDebug(_T("no space after weekday in RFC822 time spec"));
-
-            return NULL;
-        }
-
-        p++; // skip space
-    }
-
-    // the following 1 or 2 digits are the day number
+    const wxString::const_iterator pEnd = date.end();
+    wxString::const_iterator p = date.begin();
+
+    // 1. week day
+    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
+
+    // 2. separating comma
+    if ( *p++ != ',' || *p++ != ' ' )
+        return false;
+
+    // 3. day number
     if ( !wxIsdigit(*p) )
-    {
-        wxLogDebug(_T("day number expected in RFC822 time spec, none found"));
+        return false;
 
-        return NULL;
-    }
-
-    wxDateTime_t day = (wxDateTime_t)(*p++ - _T('0'));
+    wxDateTime_t day = (wxDateTime_t)(*p++ - '0');
     if ( wxIsdigit(*p) )
     {
         day *= 10;
-        day = (wxDateTime_t)(day + (*p++ - _T('0')));
-    }
-
-    if ( *p++ != _T(' ') )
-    {
-        return NULL;
+        day = (wxDateTime_t)(day + (*p++ - '0'));
     }
 
-    // the following 3 letters specify the month
-    wxString monName(p, 3);
-    Month mon;
-    if ( monName == _T("Jan") )
-        mon = Jan;
-    else if ( monName == _T("Feb") )
-        mon = Feb;
-    else if ( monName == _T("Mar") )
-        mon = Mar;
-    else if ( monName == _T("Apr") )
-        mon = Apr;
-    else if ( monName == _T("May") )
-        mon = May;
-    else if ( monName == _T("Jun") )
-        mon = Jun;
-    else if ( monName == _T("Jul") )
-        mon = Jul;
-    else if ( monName == _T("Aug") )
-        mon = Aug;
-    else if ( monName == _T("Sep") )
-        mon = Sep;
-    else if ( monName == _T("Oct") )
-        mon = Oct;
-    else if ( monName == _T("Nov") )
-        mon = Nov;
-    else if ( monName == _T("Dec") )
-        mon = Dec;
-    else
-    {
-        wxLogDebug(_T("Invalid RFC 822 month name '%s'"), monName.c_str());
-
-        return NULL;
-    }
+    if ( *p++ != ' ' )
+        return false;
 
-    p += 3;
+    // 4. month name
+    const Month mon = GetMonthFromName(p, pEnd, Name_Abbr, DateLang_English);
+    if ( mon == Inv_Month )
+        return false;
 
-    if ( *p++ != _T(' ') )
-    {
-        return NULL;
-    }
+    if ( *p++ != ' ' )
+        return false;
 
-    // next is the year
+    // 5. year
     if ( !wxIsdigit(*p) )
-    {
-        // no year?
-        return NULL;
-    }
+        return false;
 
-    int year = *p++ - _T('0');
-
-    if ( !wxIsdigit(*p) )
-    {
-        // should have at least 2 digits in the year
-        return NULL;
-    }
+    int year = *p++ - '0';
+    if ( !wxIsdigit(*p) ) // should have at least 2 digits in the year
+        return false;
 
     year *= 10;
-    year += *p++ - _T('0');
+    year += *p++ - '0';
 
     // is it a 2 digit year (as per original RFC 822) or a 4 digit one?
     if ( wxIsdigit(*p) )
     {
         year *= 10;
-        year += *p++ - _T('0');
+        year += *p++ - '0';
 
         if ( !wxIsdigit(*p) )
         {
             // no 3 digit years please
-            return NULL;
+            return false;
         }
 
         year *= 10;
-        year += *p++ - _T('0');
+        year += *p++ - '0';
     }
 
-    if ( *p++ != _T(' ') )
-    {
-        return NULL;
-    }
+    if ( *p++ != ' ' )
+        return false;
 
-    // time is in the format hh:mm:ss and seconds are optional
+    // 6. time in hh:mm:ss format with seconds being optional
     if ( !wxIsdigit(*p) )
-    {
-        return NULL;
-    }
+        return false;
 
-    wxDateTime_t hour = (wxDateTime_t)(*p++ - _T('0'));
+    wxDateTime_t hour = (wxDateTime_t)(*p++ - '0');
 
     if ( !wxIsdigit(*p) )
-    {
-        return NULL;
-    }
+        return false;
 
     hour *= 10;
-    hour = (wxDateTime_t)(hour + (*p++ - _T('0')));
+    hour = (wxDateTime_t)(hour + (*p++ - '0'));
 
-    if ( *p++ != _T(':') )
-    {
-        return NULL;
-    }
+    if ( *p++ != ':' )
+        return false;
 
     if ( !wxIsdigit(*p) )
-    {
-        return NULL;
-    }
+        return false;
 
-    wxDateTime_t min = (wxDateTime_t)(*p++ - _T('0'));
+    wxDateTime_t min = (wxDateTime_t)(*p++ - '0');
 
     if ( !wxIsdigit(*p) )
-    {
-        return NULL;
-    }
+        return false;
 
     min *= 10;
-    min = (wxDateTime_t)(min + *p++ - _T('0'));
+    min += (wxDateTime_t)(*p++ - '0');
 
     wxDateTime_t sec = 0;
-    if ( *p == _T(':') )
+    if ( *p == ':' )
     {
         p++;
         if ( !wxIsdigit(*p) )
-        {
-            return NULL;
-        }
+            return false;
 
-        sec = (wxDateTime_t)(*p++ - _T('0'));
+        sec = (wxDateTime_t)(*p++ - '0');
 
         if ( !wxIsdigit(*p) )
-        {
-            return NULL;
-        }
+            return false;
 
         sec *= 10;
-        sec = (wxDateTime_t)(sec + *p++ - _T('0'));
+        sec += (wxDateTime_t)(*p++ - '0');
     }
 
-    if ( *p++ != _T(' ') )
-    {
-        return NULL;
-    }
+    if ( *p++ != ' ' )
+        return false;
 
-    // and now the interesting part: the timezone
-    int offset wxDUMMY_INITIALIZE(0);
-    if ( *p == _T('-') || *p == _T('+') )
+    // 7. now the interesting part: the timezone
+    int offset = 0; // just to suppress warnings
+    if ( *p == '-' || *p == '+' )
     {
         // the explicit offset given: it has the form of hhmm
-        bool plus = *p++ == _T('+');
+        bool plus = *p++ == '+';
 
         if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) )
-        {
-            return NULL;
-        }
+            return false;
+
 
         // hours
-        offset = MIN_PER_HOUR*(10*(*p - _T('0')) + (*(p + 1) - _T('0')));
+        offset = MIN_PER_HOUR*(10*(*p - '0') + (*(p + 1) - '0'));
 
         p += 2;
 
         if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) )
-        {
-            return NULL;
-        }
+            return false;
 
         // minutes
-        offset += 10*(*p - _T('0')) + (*(p + 1) - _T('0'));
+        offset += 10*(*p - '0') + (*(p + 1) - '0');
 
         if ( !plus )
-        {
             offset = -offset;
-        }
 
         p += 2;
     }
-    else
+    else // not numeric
     {
         // the symbolic timezone given: may be either military timezone or one
         // of standard abbreviations
@@ -682,47 +894,39 @@ wxDateTime::ParseRfc822Date(const wxString& date, wxString::const_iterator *end)
                 +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, 0
             };
 
-            if ( *p < _T('A') || *p > _T('Z') || *p == _T('J') )
-            {
-                wxLogDebug(_T("Invalid militaty timezone '%c'"), *p);
-
-                return NULL;
-            }
+            if ( *p < wxT('A') || *p > wxT('Z') || *p == wxT('J') )
+                return false;
 
-            offset = offsets[*p++ - _T('A')];
+            offset = offsets[*p++ - 'A'];
         }
         else
         {
             // abbreviation
-            wxString tz = p;
-            if ( tz == _T("UT") || tz == _T("UTC") || tz == _T("GMT") )
+            const wxString tz(p, date.end());
+            if ( tz == wxT("UT") || tz == wxT("UTC") || tz == wxT("GMT") )
                 offset = 0;
-            else if ( tz == _T("AST") )
+            else if ( tz == wxT("AST") )
                 offset = AST - GMT0;
-            else if ( tz == _T("ADT") )
+            else if ( tz == wxT("ADT") )
                 offset = ADT - GMT0;
-            else if ( tz == _T("EST") )
+            else if ( tz == wxT("EST") )
                 offset = EST - GMT0;
-            else if ( tz == _T("EDT") )
+            else if ( tz == wxT("EDT") )
                 offset = EDT - GMT0;
-            else if ( tz == _T("CST") )
+            else if ( tz == wxT("CST") )
                 offset = CST - GMT0;
-            else if ( tz == _T("CDT") )
+            else if ( tz == wxT("CDT") )
                 offset = CDT - GMT0;
-            else if ( tz == _T("MST") )
+            else if ( tz == wxT("MST") )
                 offset = MST - GMT0;
-            else if ( tz == _T("MDT") )
+            else if ( tz == wxT("MDT") )
                 offset = MDT - GMT0;
-            else if ( tz == _T("PST") )
+            else if ( tz == wxT("PST") )
                 offset = PST - GMT0;
-            else if ( tz == _T("PDT") )
+            else if ( tz == wxT("PDT") )
                 offset = PDT - GMT0;
             else
-            {
-                wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p);
-
-                return NULL;
-            }
+                return false;
 
             p += tz.length();
         }
@@ -731,184 +935,45 @@ wxDateTime::ParseRfc822Date(const wxString& date, wxString::const_iterator *end)
         offset *= MIN_PER_HOUR;
     }
 
+
     // the spec was correct, construct the date from the values we found
     Set(day, mon, year, hour, min, sec);
     MakeFromTimezone(TimeZone::Make(offset*SEC_PER_MIN));
 
-    const size_t endpos = p - date.wx_str();
     if ( end )
-        *end = date.begin() + endpos;
+        *end = p;
 
-    return date.c_str() + endpos;
+    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()
+const char* wxDateTime::ParseRfc822Date(const char* date)
 {
-    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('%');
-                            }
+    wxString::const_iterator end;
+    wxString dateStr(date);
+    if ( !ParseRfc822Date(dateStr, &end) )
+        return NULL;
 
-                            fmtWX += *p;
-                        }
-                }
+    return date + dateStr.IterOffsetInMBStr(end);
+}
 
-                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
+const wchar_t* wxDateTime::ParseRfc822Date(const wchar_t* date)
+{
+    wxString::const_iterator end;
+    wxString dateStr(date);
+    if ( !ParseRfc822Date(dateStr, &end) )
+        return NULL;
 
-    return fmtWX;
+    return date + (end - dateStr.begin());
 }
 
-#endif // __WINDOWS__
-
-const char *
+bool
 wxDateTime::ParseFormat(const wxString& date,
                         const wxString& format,
                         const wxDateTime& dateDef,
-                        wxString::const_iterator *end)
+                        wxString::const_iterator *endParse)
 {
-    wxCHECK_MSG( !format.empty(), NULL, "format can't be empty" );
+    wxCHECK_MSG( !format.empty(), false, "format can't be empty" );
+    wxCHECK_MSG( endParse, false, "end iterator pointer must be specified" );
 
     wxString str;
     unsigned long num;
@@ -927,6 +992,8 @@ wxDateTime::ParseFormat(const wxString& date,
     bool hourIsIn12hFormat = false, // or in 24h one?
          isPM = false;              // AM by default
 
+    bool haveTimeZone = false;
+
     // and the value of the items we have (init them to get rid of warnings)
     wxDateTime_t msec = 0,
                  sec = 0,
@@ -937,17 +1004,19 @@ wxDateTime::ParseFormat(const wxString& date,
                  mday = 0;
     wxDateTime::Month mon = Inv_Month;
     int year = 0;
+    long timeZone = 0;  // time zone in seconds as expected in Tm structure
 
-    const wxStringCharType *input = date.wx_str();
+    wxString::const_iterator input = date.begin();
+    const wxString::const_iterator end = date.end();
     for ( wxString::const_iterator fmt = format.begin(); fmt != format.end(); ++fmt )
     {
-        if ( *fmt != _T('%') )
+        if ( *fmt != wxT('%') )
         {
             if ( wxIsspace(*fmt) )
             {
                 // 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++;
                 }
@@ -956,10 +1025,10 @@ 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 NULL;
+                    return false;
                 }
             }
 
@@ -974,7 +1043,7 @@ wxDateTime::ParseFormat(const wxString& date,
         while ( wxIsdigit(*++fmt) )
         {
             width *= 10;
-            width += *fmt - _T('0');
+            width += *fmt - '0';
         }
 
         // the default widths for the various fields
@@ -982,16 +1051,16 @@ wxDateTime::ParseFormat(const wxString& date,
         {
             switch ( (*fmt).GetValue() )
             {
-                case _T('Y'):               // year has 4 digits
+                case wxT('Y'):               // year has 4 digits
                     width = 4;
                     break;
 
-                case _T('j'):               // day of year has 3 digits
-                case _T('l'):               // milliseconds have 3 digits
+                case wxT('j'):               // day of year has 3 digits
+                case wxT('l'):               // milliseconds have 3 digits
                     width = 3;
                     break;
 
-                case _T('w'):               // week day as number has only one
+                case wxT('w'):               // week day as number has only one
                     width = 1;
                     break;
 
@@ -1004,54 +1073,69 @@ wxDateTime::ParseFormat(const wxString& date,
         // then the format itself
         switch ( (*fmt).GetValue() )
         {
-            case _T('a'):       // a weekday name
-            case _T('A'):
+            case wxT('a'):       // a weekday name
+            case wxT('A'):
                 {
-                    int flag = *fmt == _T('a') ? Name_Abbr : Name_Full;
-                    wday = GetWeekDayFromName(GetAlphaToken(input), flag);
+                    wday = GetWeekDayFromName
+                           (
+                            input, end,
+                            *fmt == 'a' ? Name_Abbr : Name_Full,
+                            DateLang_Local
+                           );
                     if ( wday == Inv_WeekDay )
                     {
                         // no match
-                        return NULL;
+                        return false;
                     }
                 }
                 haveWDay = true;
                 break;
 
-            case _T('b'):       // a month name
-            case _T('B'):
+            case wxT('b'):       // a month name
+            case wxT('B'):
                 {
-                    int flag = *fmt == _T('b') ? Name_Abbr : Name_Full;
-                    mon = GetMonthFromName(GetAlphaToken(input), flag);
+                    mon = GetMonthFromName
+                          (
+                            input, end,
+                            *fmt == 'b' ? Name_Abbr : Name_Full,
+                            DateLang_Local
+                          );
                     if ( mon == Inv_Month )
                     {
                         // no match
-                        return NULL;
+                        return false;
                     }
                 }
                 haveMon = true;
                 break;
 
-            case _T('c'):       // locale default date and time  representation
+            case wxT('c'):       // locale default date and time  representation
                 {
                     wxDateTime dt;
 
-                    const wxString inc(input);
+#if wxUSE_INTL
+                    const wxString
+                        fmtDateTime = wxLocale::GetInfo(wxLOCALE_DATE_TIME_FMT);
+                    if ( !fmtDateTime.empty() )
+                        dt = ParseFormatAt(input, end, fmtDateTime);
+#endif // wxUSE_INTL
+                    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"));
+                    }
 
-                    // 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) )
+                    if ( !dt.IsValid() )
                     {
-                        // we've tried everything and still no match
-                        return NULL;
+                        // and finally also the two generic date/time formats
+                        dt = ParseFormatAt(input, end, wxS("%x %X"), wxS("%X %x"));
                     }
 
-                    Tm tm = dt.GetTm();
+                    if ( !dt.IsValid() )
+                        return false;
 
-                    haveDay = haveMon = haveYear =
-                    haveHour = haveMin = haveSec = true;
+                    const Tm tm = dt.GetTm();
 
                     hour = tm.hour;
                     min = tm.min;
@@ -1061,16 +1145,18 @@ wxDateTime::ParseFormat(const wxString& date,
                     mon = tm.mon;
                     mday = tm.mday;
 
-                    input += endc - inc.begin();
+                    haveDay = haveMon = haveYear =
+                    haveHour = haveMin = haveSec = true;
                 }
                 break;
 
-            case _T('d'):       // day of a month (01-31)
-                if ( !GetNumericToken(width, input, &num) ||
+            case wxT('d'):       // day of a month (01-31)
+            case 'e':           // day of a month (1-31) (GNU extension)
+                if ( !GetNumericToken(width, input, end, &num) ||
                         (num > 31) || (num < 1) )
                 {
                     // no match
-                    return NULL;
+                    return false;
                 }
 
                 // we can't check whether the day range is correct yet, will
@@ -1079,22 +1165,23 @@ wxDateTime::ParseFormat(const wxString& date,
                 mday = (wxDateTime_t)num;
                 break;
 
-            case _T('H'):       // hour in 24h format (00-23)
-                if ( !GetNumericToken(width, input, &num) || (num > 23) )
+            case wxT('H'):       // hour in 24h format (00-23)
+                if ( !GetNumericToken(width, input, end, &num) || (num > 23) )
                 {
                     // no match
-                    return NULL;
+                    return false;
                 }
 
                 haveHour = true;
                 hour = (wxDateTime_t)num;
                 break;
 
-            case _T('I'):       // hour in 12h format (01-12)
-                if ( !GetNumericToken(width, input, &num) || !num || (num > 12) )
+            case wxT('I'):       // hour in 12h format (01-12)
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        !num || (num > 12) )
                 {
                     // no match
-                    return NULL;
+                    return false;
                 }
 
                 haveHour = true;
@@ -1102,207 +1189,189 @@ wxDateTime::ParseFormat(const wxString& date,
                 hour = (wxDateTime_t)(num % 12);        // 12 should be 0
                 break;
 
-            case _T('j'):       // day of the year
-                if ( !GetNumericToken(width, input, &num) || !num || (num > 366) )
+            case wxT('j'):       // day of the year
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        !num || (num > 366) )
                 {
                     // no match
-                    return NULL;
+                    return false;
                 }
 
                 haveYDay = true;
                 yday = (wxDateTime_t)num;
                 break;
 
-            case _T('l'):       // milliseconds (0-999)
-                if ( !GetNumericToken(width, input, &num) )
-                    return NULL;
+            case wxT('l'):       // milliseconds (0-999)
+                if ( !GetNumericToken(width, input, end, &num) )
+                    return false;
 
                 haveMsec = true;
                 msec = (wxDateTime_t)num;
                 break;
 
-            case _T('m'):       // month as a number (01-12)
-                if ( !GetNumericToken(width, input, &num) || !num || (num > 12) )
+            case wxT('m'):       // month as a number (01-12)
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        !num || (num > 12) )
                 {
                     // no match
-                    return NULL;
+                    return false;
                 }
 
                 haveMon = true;
                 mon = (Month)(num - 1);
                 break;
 
-            case _T('M'):       // minute as a decimal number (00-59)
-                if ( !GetNumericToken(width, input, &num) || (num > 59) )
+            case wxT('M'):       // minute as a decimal number (00-59)
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        (num > 59) )
                 {
                     // no match
-                    return NULL;
+                    return false;
                 }
 
                 haveMin = true;
                 min = (wxDateTime_t)num;
                 break;
 
-            case _T('p'):       // AM or PM string
+            case wxT('p'):       // AM or PM string
                 {
-                    wxString am, pm, token = GetAlphaToken(input);
-
+                    wxString am, pm;
                     GetAmPmStrings(&am, &pm);
-                    if (am.empty() && pm.empty())
-                        return NULL;  // no am/pm strings defined
-                    if ( token.CmpNoCase(pm) == 0 )
+
+                    // we can never match %p in locales which don't use AM/PM
+                    if ( am.empty() || pm.empty() )
+                        return false;
+
+                    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 )
                     {
-                        // no match
-                        return NULL;
+                        input += am.length();
+                    }
+                    else // no match
+                    {
+                        return false;
                     }
                 }
                 break;
 
-            case _T('r'):       // time as %I:%M:%S %p
+            case wxT('r'):       // time as %I:%M:%S %p
                 {
                     wxDateTime dt;
-                    input = dt.ParseFormat(input, wxS("%I:%M:%S %p"));
-                    if ( !input )
-                    {
-                        // no match
-                        return NULL;
-                    }
+                    if ( !dt.ParseFormat(wxString(input, end),
+                                         wxS("%I:%M:%S %p"), &input) )
+                        return false;
 
                     haveHour = haveMin = haveSec = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                     sec = tm.sec;
                 }
                 break;
 
-            case _T('R'):       // time as %H:%M
+            case wxT('R'):       // time as %H:%M
                 {
-                    wxDateTime dt;
-                    input = dt.ParseFormat(input, wxS("%H:%M"));
-                    if ( !input )
-                    {
-                        // no match
-                        return NULL;
-                    }
+                    const wxDateTime
+                        dt = ParseFormatAt(input, end, wxS("%H:%M"));
+                    if ( !dt.IsValid() )
+                        return false;
 
-                    haveHour = haveMin = true;
+                    haveHour =
+                    haveMin = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                 }
                 break;
 
-            case _T('S'):       // second as a decimal number (00-61)
-                if ( !GetNumericToken(width, input, &num) || (num > 61) )
+            case wxT('S'):       // second as a decimal number (00-61)
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        (num > 61) )
                 {
                     // no match
-                    return NULL;
+                    return false;
                 }
 
                 haveSec = true;
                 sec = (wxDateTime_t)num;
                 break;
 
-            case _T('T'):       // time as %H:%M:%S
+            case wxT('T'):       // time as %H:%M:%S
                 {
-                    wxDateTime dt;
-                    input = dt.ParseFormat(input, _T("%H:%M:%S"));
-                    if ( !input )
-                    {
-                        // no match
-                        return NULL;
-                    }
+                    const wxDateTime
+                        dt = ParseFormatAt(input, end, wxS("%H:%M:%S"));
+                    if ( !dt.IsValid() )
+                        return false;
 
-                    haveHour = haveMin = haveSec = true;
+                    haveHour =
+                    haveMin =
+                    haveSec = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                     sec = tm.sec;
                 }
                 break;
 
-            case _T('w'):       // weekday as a number (0-6), Sunday = 0
-                if ( !GetNumericToken(width, input, &num) || (wday > 6) )
+            case wxT('w'):       // weekday as a number (0-6), Sunday = 0
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        (wday > 6) )
                 {
                     // no match
-                    return NULL;
+                    return false;
                 }
 
                 haveWDay = true;
                 wday = (WeekDay)num;
                 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
+            case wxT('x'):       // locale default date representation
                 {
-                    struct tm tm;
-
-                    const wxStringCharType *
-                        result = CallStrptime(input, "%x", &tm);
-                    if ( result )
-                    {
-                        input = result;
-
-                        haveDay = haveMon = haveYear = true;
-
-                        year = 1900 + tm.tm_year;
-                        mon = (Month)tm.tm_mon;
-                        mday = tm.tm_mday;
-
-                        break;
-                    }
-                }
-#endif // HAVE_STRPTIME
-
-                {
-                    wxDateTime dt;
-                    wxString fmtDate,
-                             fmtDateAlt;
-
-#ifdef __WINDOWS__
-                    // The above doesn't work for all locales, try to query
-                    // Windows for the right way of formatting the date:
-                    fmtDate = GetLocaleDateFormat();
+#if wxUSE_INTL
+                    wxString
+                        fmtDate = wxLocale::GetInfo(wxLOCALE_SHORT_DATE_FMT),
+                        fmtDateAlt = wxLocale::GetInfo(wxLOCALE_LONG_DATE_FMT);
+#else // !wxUSE_INTL
+                    wxString fmtDate, fmtDateAlt;
+#endif // wxUSE_INTL/!wxUSE_INTL
                     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 wxString indate(input);
-                    wxString::const_iterator endDate;
-                    if ( !dt.ParseFormat(indate, fmtDate, &endDate) )
+                    wxDateTime
+                        dt = ParseFormatAt(input, end, fmtDate, fmtDateAlt);
+
+                    if ( !dt.IsValid() )
                     {
-                        // try another one if we have it
-                        if ( fmtDateAlt.empty() ||
-                                !dt.ParseFormat(indate, fmtDateAlt, &endDate) )
-                        {
-                            return NULL;
-                        }
+                        // try with short years too
+                        fmtDate.Replace("%Y","%y");
+                        fmtDateAlt.Replace("%Y","%y");
+                        dt = ParseFormatAt(input, end, fmtDate, fmtDateAlt);
+
+                        if ( !dt.IsValid() )
+                            return false;
                     }
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
 
                     haveDay =
                     haveMon =
@@ -1311,71 +1380,49 @@ wxDateTime::ParseFormat(const wxString& date,
                     year = tm.year;
                     mon = tm.mon;
                     mday = tm.mday;
-
-                    input += endDate - indate.begin();
                 }
 
                 break;
 
-            case _T('X'):       // locale default time representation
-#ifdef HAVE_STRPTIME
-                {
-                    // use strptime() to do it for us (FIXME !Unicode friendly)
-                    struct tm tm;
-                    input = CallStrptime(input, "%X", &tm);
-                    if ( !input )
-                    {
-                        return NULL;
-                    }
-
-                    haveHour = haveMin = haveSec = true;
-
-                    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
+            case wxT('X'):       // locale default time representation
                 {
-                    // 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
-                    wxDateTime dt;
-
-                    const wxStringCharType *
-                        result = dt.ParseFormat(input, wxS("%T"));
-                    if ( !result )
+#if wxUSE_INTL
+                    wxString fmtTime = wxLocale::GetInfo(wxLOCALE_TIME_FMT),
+                             fmtTimeAlt;
+#else // !wxUSE_INTL
+                    wxString fmtTime, fmtTimeAlt;
+#endif // wxUSE_INTL/!wxUSE_INTL
+                    if ( fmtTime.empty() )
                     {
-                        result = dt.ParseFormat(input, wxS("%r"));
+                        // 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";
                     }
 
-                    if ( !result )
-                    {
-                        // no match
-                        return NULL;
-                    }
+                    const wxDateTime
+                        dt = ParseFormatAt(input, end, fmtTime, fmtTimeAlt);
+                    if ( !dt.IsValid() )
+                        return false;
 
                     haveHour =
                     haveMin =
                     haveSec = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                     sec = tm.sec;
-
-                    input = result;
                 }
-#endif // HAVE_STRPTIME/!HAVE_STRPTIME
                 break;
 
-            case _T('y'):       // year without century (00-99)
-                if ( !GetNumericToken(width, input, &num) || (num > 99) )
+            case wxT('y'):       // year without century (00-99)
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        (num > 99) )
                 {
                     // no match
-                    return NULL;
+                    return false;
                 }
 
                 haveYear = true;
@@ -1385,36 +1432,73 @@ wxDateTime::ParseFormat(const wxString& date,
                 year = (num > 30 ? 1900 : 2000) + (wxDateTime_t)num;
                 break;
 
-            case _T('Y'):       // year with century
-                if ( !GetNumericToken(width, input, &num) )
+            case wxT('Y'):       // year with century
+                if ( !GetNumericToken(width, input, end, &num) )
                 {
                     // no match
-                    return NULL;
+                    return false;
                 }
 
                 haveYear = true;
                 year = (wxDateTime_t)num;
                 break;
 
-            case _T('Z'):       // timezone name
-                wxFAIL_MSG(_T("TODO"));
+            case wxT('z'):
+                {
+                    // check that we have something here at all
+                    if ( input == end )
+                        return false;
+
+                    // and then check that it's either plus or minus sign
+                    bool minusFound;
+                    if ( *input == wxT('-') )
+                        minusFound = true;
+                    else if ( *input == wxT('+') )
+                        minusFound = false;
+                    else
+                        return false;   // no match
+
+                    // here should follow 4 digits HHMM
+                    ++input;
+                    unsigned long tzHourMin;
+                    if ( !GetNumericToken(4, input, end, &tzHourMin) )
+                        return false;   // no match
+
+                    const unsigned hours = tzHourMin / 100;
+                    const unsigned minutes = tzHourMin % 100;
+
+                    if ( hours > 12 || minutes > 59 )
+                        return false;   // bad format
+
+                    timeZone = 3600*hours + 60*minutes;
+                    if ( minusFound )
+                        timeZone = -timeZone;
+
+                    haveTimeZone = true;
+                }
+                break;
+
+            case wxT('Z'):       // timezone name
+                // FIXME: currently we just ignore everything that looks like a
+                //        time zone here
+                GetAlphaToken(input, end);
                 break;
 
-            case _T('%'):       // a percent sign
-                if ( *input++ != _T('%') )
+            case wxT('%'):       // a percent sign
+                if ( input == end || *input++ != wxT('%') )
                 {
                     // no match
-                    return NULL;
+                    return false;
                 }
                 break;
 
             case 0:             // the end of string
-                wxFAIL_MSG(_T("unexpected format end"));
+                wxFAIL_MSG(wxT("unexpected format end"));
 
                 // fall through
 
             default:            // not a known format spec
-                return NULL;
+                return false;
         }
     }
 
@@ -1454,23 +1538,15 @@ wxDateTime::ParseFormat(const wxString& date,
     //      also always ignore the week day
     if ( haveDay )
     {
-        if ( mday > GetNumOfDaysInMonth(tm.year, tm.mon) )
-        {
-            wxLogDebug(_T("bad month day in wxDateTime::ParseFormat"));
-
-            return NULL;
-        }
+        if ( mday > GetNumberOfDays(tm.mon, tm.year) )
+            return false;
 
         tm.mday = mday;
     }
     else if ( haveYDay )
     {
         if ( yday > GetNumberOfDays(tm.year) )
-        {
-            wxLogDebug(_T("bad year day in wxDateTime::ParseFormat"));
-
-            return NULL;
-        }
+            return false;
 
         Tm tm2 = wxDateTime(1, Jan, tm.year).SetToYearDay(yday).GetTm();
 
@@ -1507,28 +1583,57 @@ wxDateTime::ParseFormat(const wxString& date,
 
     Set(tm);
 
+    // If a time zone was specified and it is not the local time zone, we need
+    // to shift the time accordingly.
+    //
+    // Note that avoiding the call to MakeFromTimeZone is necessary to avoid
+    // DST problems.
+    if ( haveTimeZone && timeZone != -wxGetTimeZone() )
+        MakeFromTimezone(timeZone);
+
     // finally check that the week day is consistent -- if we had it
     if ( haveWDay && GetWeekDay() != wday )
-    {
-        wxLogDebug(_T("inconsistsnet week day in wxDateTime::ParseFormat()"));
+        return false;
+
+    *endParse = input;
 
+    return true;
+}
+
+const char*
+wxDateTime::ParseFormat(const char* date,
+                        const wxString& format,
+                        const wxDateTime& dateDef)
+{
+    wxString::const_iterator end;
+    wxString dateStr(date);
+    if ( !ParseFormat(dateStr, format, dateDef, &end) )
         return NULL;
-    }
 
-    const size_t endpos = input - date.wx_str();
-    if ( end )
-        *end = date.begin() + endpos;
+    return date + dateStr.IterOffsetInMBStr(end);
+}
 
-    return date.c_str() + endpos;
+const wchar_t*
+wxDateTime::ParseFormat(const wchar_t* date,
+                        const wxString& format,
+                        const wxDateTime& dateDef)
+{
+    wxString::const_iterator end;
+    wxString dateStr(date);
+    if ( !ParseFormat(dateStr, format, dateDef, &end) )
+        return NULL;
+
+    return date + (end - dateStr.begin());
 }
 
-const char *
+bool
 wxDateTime::ParseDateTime(const wxString& date, wxString::const_iterator *end)
 {
-    // Set to current day and hour, so strings like '14:00' becomes today at
-    // 14, not some other random date
-    wxDateTime dtDate = wxDateTime::Today();
-    wxDateTime dtTime = wxDateTime::Today();
+    wxCHECK_MSG( end, false, "end iterator pointer must be specified" );
+
+    wxDateTime
+        dtDate,
+        dtTime;
 
     wxString::const_iterator
         endTime,
@@ -1545,7 +1650,7 @@ wxDateTime::ParseDateTime(const wxString& date, wxString::const_iterator *end)
 
         const wxString timestr(endDate, date.end());
         if ( !dtTime.ParseTime(timestr, &endTime) )
-            return NULL;
+            return false;
 
         endBoth = endDate + (endTime - timestr.begin());
     }
@@ -1553,14 +1658,14 @@ wxDateTime::ParseDateTime(const wxString& date, wxString::const_iterator *end)
     {
         // check if we have a time followed by a date
         if ( !dtTime.ParseTime(date, &endTime) )
-            return NULL;
+            return false;
 
         while ( endTime != date.end() && wxIsspace(*endTime) )
             ++endTime;
 
         const wxString datestr(endTime, date.end());
         if ( !dtDate.ParseDate(datestr, &endDate) )
-            return NULL;
+            return false;
 
         endBoth = endTime + (endDate - datestr.begin());
     }
@@ -1569,22 +1674,45 @@ wxDateTime::ParseDateTime(const wxString& date, wxString::const_iterator *end)
         dtTime.GetHour(), dtTime.GetMinute(), dtTime.GetSecond(),
         dtTime.GetMillisecond());
 
-    // Return endpoint of scan
-    if ( end )
-        *end = endBoth;
+    *end = endBoth;
+
+    return true;
+}
+
+const char* wxDateTime::ParseDateTime(const char* date)
+{
+    wxString::const_iterator end;
+    wxString dateStr(date);
+    if ( !ParseDateTime(dateStr, &end) )
+        return NULL;
+
+    return date + dateStr.IterOffsetInMBStr(end);
+}
+
+const wchar_t* wxDateTime::ParseDateTime(const wchar_t* date)
+{
+    wxString::const_iterator end;
+    wxString dateStr(date);
+    if ( !ParseDateTime(dateStr, &end) )
+        return NULL;
 
-    return date.c_str() + (endBoth - date.begin());
+    return date + (end - dateStr.begin());
 }
 
-const char *
+bool
 wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
 {
+    wxCHECK_MSG( end, false, "end iterator pointer must be specified" );
+
     // this is a simplified version of ParseDateTime() which understands only
     // "today" (for wxDate compatibility) and digits only otherwise (and not
     // all esoteric constructions ParseDateTime() knows about)
 
-    const wxStringCharType *p = date.wx_str();
-    while ( wxIsspace(*p) )
+    const wxString::const_iterator pBegin = date.begin();
+    const wxString::const_iterator pEnd = date.end();
+
+    wxString::const_iterator p = pBegin;
+    while ( p != pEnd && wxIsspace(*p) )
         p++;
 
     // some special cases
@@ -1599,31 +1727,32 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
         { wxTRANSLATE("tomorrow"),          1 },
     };
 
+    const size_t lenRest = pEnd - p;
     for ( size_t n = 0; n < WXSIZEOF(literalDates); n++ )
     {
         const wxString dateStr = wxGetTranslation(literalDates[n].str);
         size_t len = dateStr.length();
-        if ( wxStrlen(p) >= len )
-        {
-            wxString str(p, len);
-            if ( str.CmpNoCase(dateStr) == 0 )
-            {
-                // nothing can follow this, so stop here
-                p += len;
 
-                int dayDiffFromToday = literalDates[n].dayDiffFromToday;
-                *this = Today();
-                if ( dayDiffFromToday )
-                {
-                    *this += wxDateSpan::Days(dayDiffFromToday);
-                }
+        if ( len > lenRest )
+            continue;
 
-                const size_t endpos = p - date.wx_str();
+        const wxString::const_iterator pEndStr = p + len;
+        if ( wxString(p, pEndStr).CmpNoCase(dateStr) == 0 )
+        {
+            // nothing can follow this, so stop here
+
+            p = pEndStr;
 
-                if ( end )
-                    *end = date.begin() + endpos;
-                return date.c_str() + endpos;
+            int dayDiffFromToday = literalDates[n].dayDiffFromToday;
+            *this = Today();
+            if ( dayDiffFromToday )
+            {
+                *this += wxDateSpan::Days(dayDiffFromToday);
             }
+
+            *end = pEndStr;
+
+            return true;
         }
     }
 
@@ -1638,6 +1767,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;
@@ -1645,18 +1776,23 @@ 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(p, dateDelimiters);
-    while ( tok.HasMoreTokens() )
+    while ( p != pEnd )
     {
-        wxString token = tok.GetNextToken();
-        if ( !token )
+        // skip white space and date delimiters
+        if ( wxStrchr(".,/-\t\r\n ", *p) )
+        {
+            ++p;
             continue;
+        }
+
+        // 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;
 
-        // is it a number?
+        // 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
 
@@ -1682,7 +1818,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
                     );
 
@@ -1720,6 +1856,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
             else if ( isMonth )
             {
                 haveMon = true;
+                monWasNumeric = true;
 
                 mon = (Month)(val - 1);
             }
@@ -1727,26 +1864,29 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
         else // not a number
         {
             // be careful not to overwrite the current mon value
-            Month mon2 = GetMonthFromName(token, Name_Full | Name_Abbr);
+            Month mon2 = GetMonthFromName
+                         (
+                            pCopy, pEnd,
+                            Name_Full | Name_Abbr,
+                            DateLang_Local | DateLang_English
+                         );
             if ( mon2 != Inv_Month )
             {
                 // 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;
@@ -1755,14 +1895,17 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
             }
             else // not a valid month name
             {
-                WeekDay wday2 = GetWeekDayFromName(token, Name_Full | Name_Abbr);
+                WeekDay wday2 = GetWeekDayFromName
+                                (
+                                    pCopy, pEnd,
+                                    Name_Full | Name_Abbr,
+                                    DateLang_Local | DateLang_English
+                                );
                 if ( wday2 != Inv_WeekDay )
                 {
                     // a week day
                     if ( haveWDay )
-                    {
                         break;
-                    }
 
                     wday = wday2;
 
@@ -1771,7 +1914,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
                 else // not a valid weekday name
                 {
                     // try the ordinals
-                    static const char *ordinals[] =
+                    static const char *const ordinals[] =
                     {
                         wxTRANSLATE("first"),
                         wxTRANSLATE("second"),
@@ -1800,8 +1943,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;
                         }
                     }
@@ -1828,17 +1974,14 @@ 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
     // parse - in any case, see if we can construct a date from what we have
     if ( !haveDay && !haveWDay )
-    {
-        wxLogDebug(_T("ParseDate: no day, no weekday hence no date."));
-
-        return NULL;
-    }
+        return false;
 
     if ( haveWDay && (haveMon || haveYear || haveDay) &&
          !(haveDay && haveMon && haveYear) )
@@ -1846,7 +1989,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
         // 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 NULL;
+        return false;
     }
 
     if ( !haveWDay && haveYear && !(haveDay && haveMon) )
@@ -1860,7 +2003,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;
 
@@ -1872,12 +2015,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
         }
 
         if ( !haveMon )
-        {
-            // 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 NULL;
-        }
+            return false;
     }
 
     if ( !haveMon )
@@ -1894,8 +2032,8 @@ 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) )
-            return NULL;
+        if ( day > GetNumberOfDays(mon, year) )
+            return false;
 
         Set(day, mon, year);
 
@@ -1903,12 +2041,7 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
         {
             // check that it is really the same
             if ( GetWeekDay() != wday )
-            {
-                // inconsistency detected
-                wxLogDebug(_T("ParseDate: inconsistent day/weekday."));
-
-                return NULL;
-            }
+                return false;
         }
     }
     else // haveWDay
@@ -1918,30 +2051,41 @@ 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;
 
-    const size_t endpos = p - date.wx_str();
-    if ( end )
-        *end = date.begin() + endpos;
+    return true;
+}
+
+const char* wxDateTime::ParseDate(const char* date)
+{
+    wxString::const_iterator end;
+    wxString dateStr(date);
+    if ( !ParseDate(dateStr, &end) )
+        return NULL;
+
+    return date + dateStr.IterOffsetInMBStr(end);
+}
+
+const wchar_t* wxDateTime::ParseDate(const wchar_t* date)
+{
+    wxString::const_iterator end;
+    wxString dateStr(date);
+    if ( !ParseDate(dateStr, &end) )
+        return NULL;
 
-    return date.c_str() + endpos;
+    return date + (end - dateStr.begin());
 }
 
-const char *
+bool
 wxDateTime::ParseTime(const wxString& time, wxString::const_iterator *end)
 {
+    wxCHECK_MSG( end, false, "end iterator pointer must be specified" );
+
     // first try some extra things
     static const struct
     {
         const char *name;
-        wxDateTime_t  hour;
+        wxDateTime_t hour;
     } stdTimes[] =
     {
         { wxTRANSLATE("noon"),      12 },
@@ -1951,28 +2095,29 @@ wxDateTime::ParseTime(const wxString& time, wxString::const_iterator *end)
 
     for ( size_t n = 0; n < WXSIZEOF(stdTimes); n++ )
     {
-        wxString timeString = wxGetTranslation(stdTimes[n].name);
-        size_t len = timeString.length();
-        if ( timeString.CmpNoCase(wxString(time, len)) == 0 )
+        const wxString timeString = wxGetTranslation(stdTimes[n].name);
+        if ( timeString.CmpNoCase(wxString(time, timeString.length())) == 0 )
         {
             // casts required by DigitalMars
             Set(stdTimes[n].hour, wxDateTime_t(0), wxDateTime_t(0));
 
             if ( end )
-                *end = time.begin() + len;
+                *end = time.begin() + timeString.length();
 
-            return time.c_str() + len;
+            return true;
         }
     }
 
     // try all time formats we may think about in the order from longest to
     // shortest
-    static const char *timeFormats[] =
+    static const char *const timeFormats[] =
     {
         "%I:%M:%S %p",  // 12hour with AM/PM
         "%H:%M:%S",     // could be the same or 24 hour one so try it too
         "%I:%M %p",     // 12hour with AM/PM but without seconds
-        "%H:%M:%S",     // and a possibly 24 hour version without seconds
+        "%H:%M",        // and a possibly 24 hour version without seconds
+        "%I %p",        // just hour with AM/AM
+        "%H",           // just hour in 24 hour version
         "%X",           // possibly something from above or maybe something
                         // completely different -- try it last
 
@@ -1981,12 +2126,31 @@ wxDateTime::ParseTime(const wxString& time, wxString::const_iterator *end)
 
     for ( size_t nFmt = 0; nFmt < WXSIZEOF(timeFormats); nFmt++ )
     {
-        const char *result = ParseFormat(time, timeFormats[nFmt], end);
-        if ( result )
-            return result;
+        if ( ParseFormat(time, timeFormats[nFmt], end) )
+            return true;
     }
 
-    return NULL;
+    return false;
+}
+
+const char* wxDateTime::ParseTime(const char* date)
+{
+    wxString::const_iterator end;
+    wxString dateStr(date);
+    if ( !ParseTime(dateStr, &end) )
+        return NULL;
+
+    return date + dateStr.IterOffsetInMBStr(end);
+}
+
+const wchar_t* wxDateTime::ParseTime(const wchar_t* date)
+{
+    wxString::const_iterator end;
+    wxString dateStr(date);
+    if ( !ParseTime(dateStr, &end) )
+        return NULL;
+
+    return date + (end - dateStr.begin());
 }
 
 // ----------------------------------------------------------------------------
@@ -2057,7 +2221,7 @@ wxString wxTimeSpan::Format(const wxString& format) const
     }
 
     wxCHECK_MSG( !format.empty(), wxEmptyString,
-                 _T("NULL format in wxTimeSpan::Format") );
+                 wxT("NULL format in wxTimeSpan::Format") );
 
     wxString str;
     str.Alloc(format.length());
@@ -2082,10 +2246,10 @@ wxString wxTimeSpan::Format(const wxString& format) const
     {
         wxChar ch = *pch;
 
-        if ( ch == _T('%') )
+        if ( ch == wxT('%') )
         {
             // the start of the format specification of the printf() below
-            wxString fmtPrefix(_T('%'));
+            wxString fmtPrefix(wxT('%'));
 
             // the number
             long n;
@@ -2097,16 +2261,16 @@ wxString wxTimeSpan::Format(const wxString& format) const
             switch ( ch )
             {
                 default:
-                    wxFAIL_MSG( _T("invalid format character") );
+                    wxFAIL_MSG( wxT("invalid format character") );
                     // fall through
 
-                case _T('%'):
+                case wxT('%'):
                     str += ch;
 
                     // skip the part below switch
                     continue;
 
-                case _T('D'):
+                case wxT('D'):
                     n = GetDays();
                     if ( partBiggest < Part_Day )
                     {
@@ -2118,12 +2282,12 @@ wxString wxTimeSpan::Format(const wxString& format) const
                     }
                     break;
 
-                case _T('E'):
+                case wxT('E'):
                     partBiggest = Part_Week;
                     n = GetWeeks();
                     break;
 
-                case _T('H'):
+                case wxT('H'):
                     n = GetHours();
                     if ( partBiggest < Part_Hour )
                     {
@@ -2137,7 +2301,7 @@ wxString wxTimeSpan::Format(const wxString& format) const
                     digits = 2;
                     break;
 
-                case _T('l'):
+                case wxT('l'):
                     n = GetMilliseconds().ToLong();
                     if ( partBiggest < Part_MSec )
                     {
@@ -2149,7 +2313,7 @@ wxString wxTimeSpan::Format(const wxString& format) const
                     digits = 3;
                     break;
 
-                case _T('M'):
+                case wxT('M'):
                     n = GetMinutes();
                     if ( partBiggest < Part_Min )
                     {
@@ -2163,7 +2327,7 @@ wxString wxTimeSpan::Format(const wxString& format) const
                     digits = 2;
                     break;
 
-                case _T('S'):
+                case wxT('S'):
                     n = GetSeconds().ToLong();
                     if ( partBiggest < Part_Sec )
                     {
@@ -2180,10 +2344,10 @@ wxString wxTimeSpan::Format(const wxString& format) const
 
             if ( digits )
             {
-                fmtPrefix << _T("0") << digits;
+                fmtPrefix << wxT("0") << digits;
             }
 
-            str += wxString::Format(fmtPrefix + _T("ld"), n);
+            str += wxString::Format(fmtPrefix + wxT("ld"), n);
         }
         else
         {