]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/datetime.cpp
use HandleWindowEvent() in Close() as it can be called from a GTK+ callback (#9565)
[wxWidgets.git] / src / common / datetime.cpp
index 009149c105ba5ac60c6dd88dbb88e4d4dcf1b83f..f6ad3f6259ab5fd94d548c220cdf7d9029b301f6 100644 (file)
 // Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
-// TODO: for $DEITY sake, someone please fix the #ifdef __WXWINCE__ everywhere,
-//       the proper way to do it is to implement (subset of) wxStrftime() for
-//       CE instead of this horror!!
-
 /*
  * Implementation notes:
  *
 #if !defined(wxUSE_DATETIME) || wxUSE_DATETIME
 
 #ifndef WX_PRECOMP
+    #ifdef __WXMSW__
+        #include "wx/msw/wrapwin.h"
+    #endif
     #include "wx/string.h"
     #include "wx/log.h"
+    #include "wx/intl.h"
+    #include "wx/stopwatch.h"           // for wxGetLocalTimeMillis()
+    #include "wx/module.h"
+    #include "wx/crt.h"
 #endif // WX_PRECOMP
 
-#include "wx/intl.h"
 #include "wx/thread.h"
 #include "wx/tokenzr.h"
-#include "wx/module.h"
 
 #include <ctype.h>
 
 #ifdef __WINDOWS__
-    #include "wx/msw/wrapwin.h"
     #include <winnls.h>
     #ifndef __WXWINCE__
         #include <locale.h>
@@ -86,7 +86,6 @@
 #endif
 
 #include "wx/datetime.h"
-#include "wx/stopwatch.h"           // for wxGetLocalTimeMillis()
 
 const long wxDateTime::TIME_T_FACTOR = 1000l;
 
@@ -94,17 +93,17 @@ const long wxDateTime::TIME_T_FACTOR = 1000l;
 
 template<> void wxStringReadValue(const wxString &s , wxDateTime &data )
 {
-    data.ParseFormat(s,wxT("%Y-%m-%d %H:%M:%S")) ;
+    data.ParseFormat(s,"%Y-%m-%d %H:%M:%S", NULL);
 }
 
 template<> void wxStringWriteValue(wxString &s , const wxDateTime &data )
 {
-    s = data.Format(wxT("%Y-%m-%d %H:%M:%S")) ;
+    s = data.Format("%Y-%m-%d %H:%M:%S");
 }
 
 wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter<wxDateTime> , wxFromStringConverter<wxDateTime>)
 
-#endif
+#endif // wxUSE_EXTENDED_RTTI
 
 //
 // ----------------------------------------------------------------------------
@@ -164,12 +163,68 @@ wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter<wxDateTime> , wxFromStringCon
         #define WX_TIMEZONE wxGetTimeZone()
     #elif defined(__DARWIN__)
         #define WX_GMTOFF_IN_TM
+    #elif defined(__WXWINCE__) && defined(__VISUALC8__)
+        // _timezone is not present in dynamic run-time library
+        #if 0
+        // Solution (1): use the function equivalent of _timezone
+        static long wxGetTimeZone()
+        {
+            static long s_Timezone = MAXLONG; // invalid timezone
+            if (s_Timezone == MAXLONG)
+            {
+                int t;
+                _get_timezone(& t);
+                s_Timezone = (long) t;
+            }
+            return s_Timezone;
+        }
+        #define WX_TIMEZONE wxGetTimeZone()
+        #elif 1
+        // Solution (2): using GetTimeZoneInformation
+        static long wxGetTimeZone()
+        {
+            static long timezone = MAXLONG; // invalid timezone
+            if (timezone == MAXLONG)
+            {
+                TIME_ZONE_INFORMATION tzi;
+                ::GetTimeZoneInformation(&tzi);
+                timezone = tzi.Bias;
+            }
+            return timezone;
+        }
+        #define WX_TIMEZONE wxGetTimeZone()
+        #else
+        // Old method using _timezone: this symbol doesn't exist in the dynamic run-time library (i.e. using /MD)
+        #define WX_TIMEZONE _timezone
+        #endif
     #else // unknown platform - try timezone
         #define WX_TIMEZONE timezone
     #endif
 #endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM
 
-#if wxUSE_THREADS
+// everyone has strftime except Win CE unless VC8 is used
+#if !defined(__WXWINCE__) || defined(__VISUALC8__)
+    #define HAVE_STRFTIME
+#endif
+
+// NB: VC8 safe time functions could/should be used for wxMSW as well probably
+#if defined(__WXWINCE__) && defined(__VISUALC8__)
+
+struct tm *wxLocaltime_r(const time_t *t, struct tm* tm)
+{
+    __time64_t t64 = *t;
+    return _localtime64_s(tm, &t64) == 0 ? tm : NULL;
+}
+
+struct tm *wxGmtime_r(const time_t* t, struct tm* tm)
+{
+    __time64_t t64 = *t;
+    return _gmtime64_s(tm, &t64) == 0 ? tm : NULL;
+}
+
+#else // !wxWinCE with VC8
+
+#if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__)
 static wxMutex timeLock;
 #endif
 
@@ -181,10 +236,21 @@ struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp)
   // thread local storage for localtime anyway.
   wxMutexLocker locker(timeLock);
 #endif
-  memcpy(temp, localtime(ticks), sizeof(struct tm));
+
+  // Borland CRT crashes when passed 0 ticks for some reason, see SF bug 1704438
+#ifdef __BORLANDC__
+  if ( !*ticks )
+      return NULL;
+#endif
+
+  const tm * const t = localtime(ticks);
+  if ( !t )
+      return NULL;
+
+  memcpy(temp, t, sizeof(struct tm));
   return temp;
 }
-#endif
+#endif // !HAVE_LOCALTIME_R
 
 #ifndef HAVE_GMTIME_R
 struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp)
@@ -194,23 +260,30 @@ struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp)
   // using thread local storage for gmtime anyway.
   wxMutexLocker locker(timeLock);
 #endif
+
+#ifdef __BORLANDC__
+  if ( !*ticks )
+      return NULL;
+#endif
+
+  const tm * const t = gmtime(ticks);
+  if ( !t )
+      return NULL;
+
   memcpy(temp, gmtime(ticks), sizeof(struct tm));
   return temp;
 }
-#endif
+#endif // !HAVE_GMTIME_R
+
+#endif // wxWinCE with VC8/other platforms
 
 // ----------------------------------------------------------------------------
 // macros
 // ----------------------------------------------------------------------------
 
 // debugging helper: just a convenient replacement of wxCHECK()
-#define wxDATETIME_CHECK(expr, msg)     \
-        if ( !(expr) )                  \
-        {                               \
-            wxFAIL_MSG(msg);            \
-            *this = wxInvalidDateTime;  \
-            return *this;               \
-        }
+#define wxDATETIME_CHECK(expr, msg) \
+    wxCHECK2_MSG(expr, *this = wxInvalidDateTime; return *this, msg)
 
 // ----------------------------------------------------------------------------
 // private classes
@@ -288,8 +361,8 @@ static const wxDateTime::wxDateTime_t gs_cumulatedDays[2][MONTHS_IN_YEAR] =
 // global data
 // ----------------------------------------------------------------------------
 
-const wxChar * wxDefaultDateTimeFormat = wxT("%c");
-const wxChar * wxDefaultTimeSpanFormat = wxT("%H:%M:%S");
+const char *wxDefaultDateTimeFormat = "%c";
+const char *wxDefaultTimeSpanFormat = "%H:%M:%S";
 
 // in the fine tradition of ANSI C we use our equivalent of (time_t)-1 to
 // indicate an invalid wxDateTime object
@@ -303,11 +376,13 @@ wxDateTime::Country wxDateTime::ms_country = wxDateTime::Country_Unknown;
 
 // debugger helper: shows what the date really is
 #ifdef __WXDEBUG__
-extern const wxChar *wxDumpDate(const wxDateTime* dt)
+extern const char *wxDumpDate(const wxDateTime* dt)
 {
-    static wxChar buf[128];
+    static char buf[128];
 
-    wxStrcpy(buf, dt->Format(_T("%Y-%m-%d (%a) %H:%M:%S")));
+    wxString fmt(dt->Format("%Y-%m-%d (%a) %H:%M:%S"));
+    wxStrncpy(buf, fmt + " (" + dt->GetValue().ToString() + " ticks)",
+              WXSIZEOF(buf));
 
     return buf;
 }
@@ -332,7 +407,6 @@ wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month)
 // (in seconds)
 static int GetTimeZone()
 {
-#ifdef WX_GMTOFF_IN_TM
     // set to true when the timezone is set
     static bool s_timezoneSet = false;
     static long gmtoffset = LONG_MAX; // invalid timezone
@@ -343,22 +417,22 @@ static int GetTimeZone()
         // just call wxLocaltime_r() instead of figuring out whether this
         // system supports tzset(), _tzset() or something else
         time_t t = 0;
-        struct tm *tm;
-        struct tm tmstruct;
+        struct tm tm;
 
-        tm = wxLocaltime_r(&t, &tmstruct);
+        wxLocaltime_r(&t, &tm);
         s_timezoneSet = true;
 
+#ifdef WX_GMTOFF_IN_TM
         // note that GMT offset is the opposite of time zone and so to return
         // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM
         // cases we have to negate it
-        gmtoffset = -tm->tm_gmtoff;
+        gmtoffset = -tm.tm_gmtoff;
+#else // !WX_GMTOFF_IN_TM
+        gmtoffset = WX_TIMEZONE;
+#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM
     }
 
     return (int)gmtoffset;
-#else // !WX_GMTOFF_IN_TM
-    return (int)WX_TIMEZONE;
-#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM
 }
 
 // return the integral part of the JDN for the midnight of the given date (to
@@ -401,9 +475,10 @@ static long GetTruncatedJDN(wxDateTime::wxDateTime_t day,
             - JDN_OFFSET;
 }
 
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
+
 // this function is a wrapper around strftime(3) adding error checking
-static wxString CallStrftime(const wxChar *format, const tm* tm)
+static wxString CallStrftime(const wxString& format, const tm* tm)
 {
     wxChar buf[4096];
     // Create temp wxString here to work around mingw/cygwin bug 1046059
@@ -419,7 +494,8 @@ static wxString CallStrftime(const wxChar *format, const tm* tm)
     s = buf;
     return s;
 }
-#endif
+
+#endif // HAVE_STRFTIME
 
 #ifdef HAVE_STRPTIME
 
@@ -430,13 +506,13 @@ static wxString CallStrftime(const wxChar *format, const tm* tm)
 #endif
 
 // Unicode-friendly strptime() wrapper
-static const wxChar *
-CallStrptime(const wxChar *input, const char *fmt, tm *tm)
+static const wxStringCharType *
+CallStrptime(const wxStringCharType *input, const char *fmt, tm *tm)
 {
     // the problem here is that strptime() returns pointer into the string we
     // passed to it while we're really interested in the pointer into the
     // original, Unicode, string so we try to transform the pointer back
-#if wxUSE_UNICODE
+#if wxUSE_UNICODE_WCHAR
     wxCharBuffer inputMB(wxConvertWX2MB(input));
 #else // ASCII
     const char * const inputMB = input;
@@ -446,7 +522,7 @@ CallStrptime(const wxChar *input, const char *fmt, tm *tm)
     if ( !result )
         return NULL;
 
-#if wxUSE_UNICODE
+#if wxUSE_UNICODE_WCHAR
     // FIXME: this is wrong in presence of surrogates &c
     return input + (result - inputMB.data());
 #else // ASCII
@@ -562,7 +638,9 @@ struct tm *wxDateTime::GetTmNow(struct tm *tmstruct)
 }
 
 // scans all digits (but no more than len) and returns the resulting number
-static bool GetNumericToken(size_t len, const wxChar*& p, unsigned long *number)
+static bool GetNumericToken(size_t len,
+                            const wxStringCharType*& p,
+                            unsigned long *number)
 {
     size_t n = 1;
     wxString s;
@@ -578,7 +656,7 @@ static bool GetNumericToken(size_t len, const wxChar*& p, unsigned long *number)
 }
 
 // scans all alphabetic characters and returns the resulting string
-static wxString GetAlphaToken(const wxChar*& p)
+static wxString GetAlphaToken(const wxStringCharType*& p)
 {
     wxString s;
     while ( wxIsalpha(*p) )
@@ -633,7 +711,7 @@ void wxDateTime::Tm::ComputeWeekDay()
     // compute the week day from day/month/year: we use the dumbest algorithm
     // possible: just compute our JDN and then use the (simple to derive)
     // formula: weekday = (JDN + 1.5) % 7
-    wday = (wxDateTime::wxDateTime_t)((wxDateTime::WeekDay)(GetTruncatedJDN(mday, mon, year) + 2) % 7);
+    wday = (wxDateTime::wxDateTime_t)((GetTruncatedJDN(mday, mon, year) + 2) % 7);
 }
 
 void wxDateTime::Tm::AddMonths(int monDiff)
@@ -725,6 +803,7 @@ wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz)
         case wxDateTime::GMT10:
         case wxDateTime::GMT11:
         case wxDateTime::GMT12:
+        case wxDateTime::GMT13:
             m_offset = 3600*(tz - wxDateTime::GMT0);
             break;
 
@@ -875,7 +954,7 @@ wxString wxDateTime::GetMonthName(wxDateTime::Month month,
                                   wxDateTime::NameFlags flags)
 {
     wxCHECK_MSG( month != Inv_Month, wxEmptyString, _T("invalid month") );
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
     // notice that we must set all the fields to avoid confusing libc (GNU one
     // gets confused to a crash if we don't do this)
     tm tm;
@@ -883,7 +962,7 @@ wxString wxDateTime::GetMonthName(wxDateTime::Month month,
     tm.tm_mon = month;
 
     return CallStrftime(flags == Name_Abbr ? _T("%b") : _T("%B"), &tm);
-#else
+#else // !HAVE_STRFTIME
     wxString ret;
     switch(month)
     {
@@ -925,7 +1004,7 @@ wxString wxDateTime::GetMonthName(wxDateTime::Month month,
             break;
     }
     return ret;
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
 }
 
 /* static */
@@ -933,7 +1012,7 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday,
                                     wxDateTime::NameFlags flags)
 {
     wxCHECK_MSG( wday != Inv_WeekDay, wxEmptyString, _T("invalid weekday") );
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
     // take some arbitrary Sunday (but notice that the day should be such that
     // after adding wday to it below we still have a valid date, e.g. don't
     // take 28 here!)
@@ -951,7 +1030,7 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday,
 
     // ... and call strftime()
     return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm);
-#else
+#else // !HAVE_STRFTIME
     wxString ret;
     switch(wday)
     {
@@ -978,8 +1057,7 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday,
             break;
     }
     return ret;
-
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
 }
 
 /* static */
@@ -1057,9 +1135,9 @@ wxDateTime::Country wxDateTime::GetCountry()
             ms_country = USA;
         }
     }
-#else
+#else // __WXWINCE__
      ms_country = USA;
-#endif
+#endif // !__WXWINCE__/__WXWINCE__
 
     return ms_country;
 }
@@ -1150,9 +1228,6 @@ wxDateTime wxDateTime::GetBeginDST(int year, Country country)
         }
 
         dt += wxTimeSpan::Hours(1);
-
-        // disable DST tests because it could result in an infinite recursion!
-        dt.MakeGMT(true);
     }
     else switch ( country )
     {
@@ -1251,9 +1326,6 @@ wxDateTime wxDateTime::GetEndDST(int year, Country country)
         }
 
         dt += wxTimeSpan::Hours(1);
-
-        // disable DST tests because it could result in an infinite recursion!
-        dt.MakeGMT(true);
     }
     else switch ( country )
     {
@@ -1469,6 +1541,16 @@ wxDateTime& wxDateTime::ResetTime()
     return *this;
 }
 
+wxDateTime wxDateTime::GetDateOnly() const
+{
+    Tm tm = GetTm();
+    tm.msec =
+    tm.sec =
+    tm.min =
+    tm.hour = 0;
+    return wxDateTime(tm);
+}
+
 // ----------------------------------------------------------------------------
 // DOS Date and Time Format functions
 // ----------------------------------------------------------------------------
@@ -1522,6 +1604,7 @@ unsigned long wxDateTime::GetAsDOS() const
     time_t ticks = GetTicks();
     struct tm tmstruct;
     struct tm *tm = wxLocaltime_r(&ticks, &tmstruct);
+    wxCHECK_MSG( tm, ULONG_MAX, _T("time can't be represented in DOS format") );
 
     long year = tm->tm_year;
     year -= 80;
@@ -1816,6 +1899,7 @@ wxDateTime::SetToWeekOfYear(int year, wxDateTime_t numWeek, WeekDay wd)
     return dt;
 }
 
+#if WXWIN_COMPATIBILITY_2_6
 // use a separate function to avoid warnings about using deprecated
 // SetToTheWeek in GetWeek below
 static wxDateTime
@@ -1853,6 +1937,7 @@ wxDateTime wxDateTime::GetWeek(wxDateTime_t numWeek,
 {
     return ::SetToTheWeek(GetYear(), numWeek, weekday, flags);
 }
+#endif // WXWIN_COMPATIBILITY_2_6
 
 wxDateTime& wxDateTime::SetToLastMonthDay(Month month,
                                           int year)
@@ -2218,13 +2303,16 @@ wxDateTime& wxDateTime::MakeFromTimezone(const TimeZone& tz, bool noDST)
 // wxDateTime to/from text representations
 // ----------------------------------------------------------------------------
 
-wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
+wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
 {
-    wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxDateTime::Format") );
+    wxCHECK_MSG( !format.empty(), wxEmptyString,
+                 _T("NULL format in wxDateTime::Format") );
 
     // 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
     time_t time = GetTicks();
+
     if ( (time != (time_t)-1) && !wxStrstr(format, _T("%l")) )
     {
         // use strftime()
@@ -2259,15 +2347,14 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                 tm = (struct tm *)NULL;
             }
         }
-#ifndef __WXWINCE__
-    //Windows CE doesn't support strftime or wcsftime, so we use the generic implementation
+
         if ( tm )
         {
             return CallStrftime(format, tm);
         }
-#endif
-        //else: use generic code below
     }
+    //else: use generic code below
+#endif // HAVE_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
@@ -2287,7 +2374,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
     tmTimeOnly.tm_isdst = 0;        // no DST, we adjust for tz ourselves
 
     wxString tmp, res, fmt;
-    for ( const wxChar *p = format; *p; p++ )
+    for ( wxString::const_iterator p = format.begin(); p != format.end(); ++p )
     {
         if ( *p != _T('%') )
         {
@@ -2298,7 +2385,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
         }
 
         // set the default format
-        switch ( *++p )
+        switch ( (*++p).GetValue() )
         {
             case _T('Y'):               // year has 4 digits
                 fmt = _T("%04d");
@@ -2327,7 +2414,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
             restart = false;
 
             // start of the format specification
-            switch ( *p )
+            switch ( (*p).GetValue() )
             {
                 case _T('a'):       // a weekday name
                 case _T('A'):
@@ -2344,7 +2431,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
 
                 case _T('c'):       // locale default date and time  representation
                 case _T('x'):       // locale default date representation
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
                     //
                     // the problem: there is no way to know what do these format
                     // specifications correspond to for the current locale.
@@ -2366,7 +2453,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                     // will change if one of these years is leap and the other one
                     // is not!
                     {
-                        // find the YEAR: normally, for any year X, Jan 1 or the
+                        // find the YEAR: normally, for any year X, Jan 1 of the
                         // year X + 28 is the same weekday as Jan 1 of X (because
                         // the weekday advances by 1 for each normal X and by 2
                         // for each leap X, hence by 5 every 4 years or by 35
@@ -2408,33 +2495,15 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                             nLostWeekDays += year++ % 4 ? 1 : 2;
                         }
 
-                        // at any rate, we couldn't go further than 1988 + 9 + 28!
-                        wxASSERT_MSG( year < 2030,
-                                      _T("logic error in wxDateTime::Format") );
-
-                        wxString strYear, strYear2;
-                        strYear.Printf(_T("%d"), year);
-                        strYear2.Printf(_T("%d"), year % 100);
-
-                        // find two strings not occurring in format (this is surely
-                        // not the optimal way of doing it... improvements welcome!)
-                        wxString fmt2 = format;
-                        wxString replacement = (wxChar)-1;
-                        while ( fmt2.Find(replacement) != wxNOT_FOUND )
-                        {
-                            replacement << (wxChar)-1;
-                        }
+                        // finally move the year below 2000 so that the 2-digit
+                        // year number can never match the month or day of the
+                        // month when we do the replacements below
+                        if ( year >= 2000 )
+                            year -= 28;
 
-                        wxString replacement2 = (wxChar)-2;
-                        while ( fmt2.Find(replacement) != wxNOT_FOUND )
-                        {
-                            replacement << (wxChar)-2;
-                        }
+                        wxASSERT_MSG( year >= 1970 && year < 2000,
+                                      _T("logic error in wxDateTime::Format") );
 
-                        // replace all occurrences of year with it
-                        bool wasReplaced = fmt2.Replace(strYear, replacement) > 0;
-                        if ( !wasReplaced )
-                            wasReplaced = fmt2.Replace(strYear2, replacement2) > 0;
 
                         // use strftime() to format the same date but in supported
                         // year
@@ -2458,27 +2527,31 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                                                                   : _T("%x"),
                                                     &tmAdjusted);
 
-                        // now replace the occurrence of 1999 with the real year
-                        wxString strYearReal, strYearReal2;
-                        strYearReal.Printf(_T("%04d"), yearReal);
-                        strYearReal2.Printf(_T("%02d"), yearReal % 100);
-                        str.Replace(strYear, strYearReal);
-                        str.Replace(strYear2, strYearReal2);
-
-                        // and replace back all occurrences of replacement string
-                        if ( wasReplaced )
-                        {
-                            str.Replace(replacement2, strYear2);
-                            str.Replace(replacement, strYear);
-                        }
+                        // now replace the replacement year with the real year:
+                        // notice that we have to replace the 4 digit year with
+                        // a unique string not appearing in strftime() output
+                        // first to prevent the 2 digit year from matching any
+                        // substring of the 4 digit year (but any day, month,
+                        // hours or minutes components should be safe because
+                        // they are never in 70-99 range)
+                        wxString replacement("|");
+                        while ( str.find(replacement) != wxString::npos )
+                            replacement += '|';
+
+                        str.Replace(wxString::Format("%d", year),
+                                    replacement);
+                        str.Replace(wxString::Format("%d", year % 100),
+                                    wxString::Format("%d", yearReal % 100));
+                        str.Replace(replacement,
+                                    wxString::Format("%d", yearReal));
 
                         res += str;
                     }
-#else
-                    //Use "%m/%d/%y %H:%M:%S" format instead
+#else // !HAVE_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
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
                     break;
 
                 case _T('d'):       // day of a month (01-31)
@@ -2515,11 +2588,11 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                     break;
 
                 case _T('p'):       // AM or PM string
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
                     res += CallStrftime(_T("%p"), &tmTimeOnly);
-#else
+#else // !HAVE_STRFTIME
                     res += (tmTimeOnly.tm_hour > 12) ? wxT("pm") : wxT("am");
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
                     break;
 
                 case _T('S'):       // second as a decimal number (00-61)
@@ -2542,11 +2615,11 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
 
                 case _T('X'):       // locale default time representation
                     // just use strftime() to format the time for us
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
                     res += CallStrftime(_T("%X"), &tmTimeOnly);
-#else
+#else // !HAVE_STRFTIME
                     res += wxString::Format(wxT("%02d:%02d:%02d"),tm.hour, tm.min, tm.sec);
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
                     break;
 
                 case _T('y'):       // year without century (00-99)
@@ -2558,7 +2631,7 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
                     break;
 
                 case _T('Z'):       // timezone name
-#ifndef __WXWINCE__
+#ifdef HAVE_STRFTIME
                     res += CallStrftime(_T("%Z"), &tmTimeOnly);
 #endif
                     break;
@@ -2613,12 +2686,12 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
 // RFC822 time specs.
 //
 // TODO a great candidate for using reg exps
-const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
+const char *
+wxDateTime::ParseRfc822Date(const wxString& date, wxString::const_iterator *end)
 {
-    wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") );
-
-    const wxChar *p = date;
-    const wxChar *comma = wxStrchr(p, _T(','));
+    // 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
@@ -2631,7 +2704,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
         {
             wxLogDebug(_T("no space after weekday in RFC822 time spec"));
 
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         p++; // skip space
@@ -2642,7 +2715,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
     {
         wxLogDebug(_T("day number expected in RFC822 time spec, none found"));
 
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     wxDateTime_t day = (wxDateTime_t)(*p++ - _T('0'));
@@ -2654,7 +2727,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
     if ( *p++ != _T(' ') )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     // the following 3 letters specify the month
@@ -2688,21 +2761,21 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
     {
         wxLogDebug(_T("Invalid RFC 822 month name '%s'"), monName.c_str());
 
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     p += 3;
 
     if ( *p++ != _T(' ') )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     // next is the year
     if ( !wxIsdigit(*p) )
     {
         // no year?
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     int year = *p++ - _T('0');
@@ -2710,7 +2783,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
     if ( !wxIsdigit(*p) )
     {
         // should have at least 2 digits in the year
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     year *= 10;
@@ -2725,7 +2798,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
         if ( !wxIsdigit(*p) )
         {
             // no 3 digit years please
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         year *= 10;
@@ -2734,20 +2807,20 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
     if ( *p++ != _T(' ') )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     // time is in the format hh:mm:ss and seconds are optional
     if ( !wxIsdigit(*p) )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     wxDateTime_t hour = (wxDateTime_t)(*p++ - _T('0'));
 
     if ( !wxIsdigit(*p) )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     hour *= 10;
@@ -2755,37 +2828,38 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
     if ( *p++ != _T(':') )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     if ( !wxIsdigit(*p) )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     wxDateTime_t min = (wxDateTime_t)(*p++ - _T('0'));
 
     if ( !wxIsdigit(*p) )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     min *= 10;
     min = (wxDateTime_t)(min + *p++ - _T('0'));
 
     wxDateTime_t sec = 0;
-    if ( *p++ == _T(':') )
+    if ( *p == _T(':') )
     {
+        p++;
         if ( !wxIsdigit(*p) )
         {
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         sec = (wxDateTime_t)(*p++ - _T('0'));
 
         if ( !wxIsdigit(*p) )
         {
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         sec *= 10;
@@ -2794,7 +2868,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
     if ( *p++ != _T(' ') )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     // and now the interesting part: the timezone
@@ -2806,7 +2880,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
         if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) )
         {
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         // hours
@@ -2816,7 +2890,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
         if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) )
         {
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         // minutes
@@ -2848,7 +2922,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
             {
                 wxLogDebug(_T("Invalid militaty timezone '%c'"), *p);
 
-                return (wxChar *)NULL;
+                return NULL;
             }
 
             offset = offsets[*p++ - _T('A')];
@@ -2883,7 +2957,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
             {
                 wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p);
 
-                return (wxChar *)NULL;
+                return NULL;
             }
 
             p += tz.length();
@@ -2895,9 +2969,13 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
     // the spec was correct, construct the date from the values we found
     Set(day, mon, year, hour, min, sec);
-    MakeFromTimezone(TimeZone((wxDateTime_t)(offset*SEC_PER_MIN)));
+    MakeFromTimezone(TimeZone::Make(offset*SEC_PER_MIN));
 
-    return p;
+    const size_t endpos = p - date.wx_str();
+    if ( end )
+        *end = date.begin() + endpos;
+
+    return date.c_str() + endpos;
 }
 
 #ifdef __WINDOWS__
@@ -3060,12 +3138,13 @@ static wxString GetLocaleDateFormat()
 
 #endif // __WINDOWS__
 
-const wxChar *wxDateTime::ParseFormat(const wxChar *date,
-                                      const wxChar *format,
-                                      const wxDateTime& dateDef)
+const char *
+wxDateTime::ParseFormat(const wxString& date,
+                        const wxString& format,
+                        const wxDateTime& dateDef,
+                        wxString::const_iterator *end)
 {
-    wxCHECK_MSG( date && format, (wxChar *)NULL,
-                 _T("NULL pointer in wxDateTime::ParseFormat()") );
+    wxCHECK_MSG( !format.empty(), NULL, "format can't be empty" );
 
     wxString str;
     unsigned long num;
@@ -3093,8 +3172,8 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
     wxDateTime::Month mon = Inv_Month;
     int year = 0;
 
-    const wxChar *input = date;
-    for ( const wxChar *fmt = format; *fmt; fmt++ )
+    const wxStringCharType *input = date.wx_str();
+    for ( wxString::const_iterator fmt = format.begin(); fmt != format.end(); ++fmt )
     {
         if ( *fmt != _T('%') )
         {
@@ -3114,7 +3193,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( *input++ != *fmt )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
             }
 
@@ -3135,7 +3214,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
         // the default widths for the various fields
         if ( !width )
         {
-            switch ( *fmt )
+            switch ( (*fmt).GetValue() )
             {
                 case _T('Y'):               // year has 4 digits
                     width = 4;
@@ -3157,7 +3236,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
         }
 
         // then the format itself
-        switch ( *fmt )
+        switch ( (*fmt).GetValue() )
         {
             case _T('a'):       // a weekday name
             case _T('A'):
@@ -3167,7 +3246,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     if ( wday == Inv_WeekDay )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
                 }
                 haveWDay = true;
@@ -3181,7 +3260,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     if ( mon == Inv_Month )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
                 }
                 haveMon = true;
@@ -3191,25 +3270,16 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 {
                     wxDateTime dt;
 
-                    // this is the format which corresponds to ctime() output
-                    // and strptime("%c") should parse it, so try it first
-                    static const wxChar *fmtCtime = _T("%a %b %d %H:%M:%S %Y");
-
-                    const wxChar *result = dt.ParseFormat(input, fmtCtime);
-                    if ( !result )
-                    {
-                        result = dt.ParseFormat(input, _T("%x %X"));
-                    }
-
-                    if ( !result )
-                    {
-                        result = dt.ParseFormat(input, _T("%X %x"));
-                    }
+                    const wxString inc(input);
 
-                    if ( !result )
+                    // try the format which corresponds to ctime() output first
+                    wxString::const_iterator endc;
+                    if ( !dt.ParseFormat(inc, wxS("%a %b %d %H:%M:%S %Y"), &endc) &&
+                            !dt.ParseFormat(inc, wxS("%x %X"), &endc) &&
+                                !dt.ParseFormat(inc, wxS("%X %x"), &endc) )
                     {
                         // we've tried everything and still no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
 
                     Tm tm = dt.GetTm();
@@ -3225,7 +3295,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     mon = tm.mon;
                     mday = tm.mday;
 
-                    input = result;
+                    input += endc - inc.begin();
                 }
                 break;
 
@@ -3234,7 +3304,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                         (num > 31) || (num < 1) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 // we can't check whether the day range is correct yet, will
@@ -3247,7 +3317,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 23) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveHour = true;
@@ -3258,7 +3328,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || !num || (num > 12) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveHour = true;
@@ -3270,7 +3340,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || !num || (num > 366) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveYDay = true;
@@ -3281,7 +3351,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || !num || (num > 12) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveMon = true;
@@ -3292,7 +3362,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 59) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveMin = true;
@@ -3305,7 +3375,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
 
                     GetAmPmStrings(&am, &pm);
                     if (am.empty() && pm.empty())
-                        return (wxChar *)NULL;  // no am/pm strings defined
+                        return NULL;  // no am/pm strings defined
                     if ( token.CmpNoCase(pm) == 0 )
                     {
                         isPM = true;
@@ -3313,7 +3383,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     else if ( token.CmpNoCase(am) != 0 )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
                 }
                 break;
@@ -3321,11 +3391,11 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
             case _T('r'):       // time as %I:%M:%S %p
                 {
                     wxDateTime dt;
-                    input = dt.ParseFormat(input, _T("%I:%M:%S %p"));
+                    input = dt.ParseFormat(input, wxS("%I:%M:%S %p"));
                     if ( !input )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
 
                     haveHour = haveMin = haveSec = true;
@@ -3340,11 +3410,11 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
             case _T('R'):       // time as %H:%M
                 {
                     wxDateTime dt;
-                    input = dt.ParseFormat(input, _T("%H:%M"));
+                    input = dt.ParseFormat(input, wxS("%H:%M"));
                     if ( !input )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
 
                     haveHour = haveMin = true;
@@ -3359,7 +3429,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 61) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveSec = true;
@@ -3373,7 +3443,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     if ( !input )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
 
                     haveHour = haveMin = haveSec = true;
@@ -3389,7 +3459,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (wday > 6) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveWDay = true;
@@ -3404,7 +3474,8 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 {
                     struct tm tm;
 
-                    const wxChar *result = CallStrptime(input, "%x", &tm);
+                    const wxStringCharType *
+                        result = CallStrptime(input, "%x", &tm);
                     if ( result )
                     {
                         input = result;
@@ -3430,7 +3501,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     // Windows for the right way of formatting the date:
                     fmtDate = GetLocaleDateFormat();
                     if ( fmtDate.empty() )
-#endif
+#endif // __WINDOWS__
                     {
                         if ( IsWestEuropeanCountry(GetCountry()) ||
                              GetCountry() == Russia )
@@ -3445,29 +3516,29 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                         }
                     }
 
-                    const wxChar *result = dt.ParseFormat(input, fmtDate);
-
-                    if ( !result && !fmtDateAlt.empty() )
-                    {
-                        // ok, be nice and try another one
-                        result = dt.ParseFormat(input, fmtDateAlt);
-                    }
-
-                    if ( !result )
+                    const wxString indate(input);
+                    wxString::const_iterator endDate;
+                    if ( !dt.ParseFormat(indate, fmtDate, &endDate) )
                     {
-                        // bad luck
-                        return (wxChar *)NULL;
+                        // try another one if we have it
+                        if ( fmtDateAlt.empty() ||
+                                !dt.ParseFormat(indate, fmtDateAlt, &endDate) )
+                        {
+                            return NULL;
+                        }
                     }
 
                     Tm tm = dt.GetTm();
 
-                    haveDay = haveMon = haveYear = true;
+                    haveDay =
+                    haveMon =
+                    haveYear = true;
 
                     year = tm.year;
                     mon = tm.mon;
                     mday = tm.mday;
 
-                    input = result;
+                    input += endDate - indate.begin();
                 }
 
                 break;
@@ -3480,7 +3551,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     input = CallStrptime(input, "%X", &tm);
                     if ( !input )
                     {
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
 
                     haveHour = haveMin = haveSec = true;
@@ -3499,19 +3570,22 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     // common cases
                     wxDateTime dt;
 
-                    const wxChar *result = dt.ParseFormat(input, _T("%T"));
+                    const wxStringCharType *
+                        result = dt.ParseFormat(input, wxS("%T"));
                     if ( !result )
                     {
-                        result = dt.ParseFormat(input, _T("%r"));
+                        result = dt.ParseFormat(input, wxS("%r"));
                     }
 
                     if ( !result )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
 
-                    haveHour = haveMin = haveSec = true;
+                    haveHour =
+                    haveMin =
+                    haveSec = true;
 
                     Tm tm = dt.GetTm();
                     hour = tm.hour;
@@ -3527,7 +3601,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 99) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveYear = true;
@@ -3541,7 +3615,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveYear = true;
@@ -3556,7 +3630,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( *input++ != _T('%') )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
                 break;
 
@@ -3566,7 +3640,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 // fall through
 
             default:            // not a known format spec
-                return (wxChar *)NULL;
+                return NULL;
         }
     }
 
@@ -3605,7 +3679,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
         {
             wxLogDebug(_T("bad month day in wxDateTime::ParseFormat"));
 
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         tm.mon = mon;
@@ -3617,7 +3691,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
         {
             wxLogDebug(_T("bad year day in wxDateTime::ParseFormat"));
 
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         Tm tm2 = wxDateTime(1, Jan, tm.year).SetToYearDay(yday).GetTm();
@@ -3660,73 +3734,82 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
         return NULL;
     }
 
-    return input;
+    const size_t endpos = input - date.wx_str();
+    if ( end )
+        *end = date.begin() + endpos;
+
+    return date.c_str() + endpos;
 }
 
-const wxChar *wxDateTime::ParseDateTime(const wxChar *date)
+const char *
+wxDateTime::ParseDateTime(const wxString& date, wxString::const_iterator *end)
 {
-    wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") );
-
     // 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();
 
-    const wxChar* pchTime;
+    wxString::const_iterator
+        endTime,
+        endDate,
+        endBoth;
 
-    // Try to parse the beginning of the string as a date
-    const wxChar* pchDate = dtDate.ParseDate(date);
-
-    // We got a date in the beginning, see if there is a time specified after the date
-    if ( pchDate )
+    // If we got a date in the beginning, see if there is a time specified
+    // after the date
+    if ( dtDate.ParseDate(date, &endDate) )
     {
         // Skip spaces, as the ParseTime() function fails on spaces
-        while ( wxIsspace(*pchDate) )
-            pchDate++;
+        while ( endDate != date.end() && wxIsspace(*endDate) )
+            ++endDate;
+
+        const wxString timestr(endDate, date.end());
+        if ( !dtTime.ParseTime(timestr, &endTime) )
+            return NULL;
 
-        pchTime = dtTime.ParseTime(pchDate);
+        endBoth = endDate + (endTime - timestr.begin());
     }
     else // no date in the beginning
     {
-        // check and see if we have a time followed by a date
-        pchTime = dtTime.ParseTime(date);
-        if ( pchTime )
-        {
-            while ( wxIsspace(*pchTime) )
-                pchTime++;
+        // check if we have a time followed by a date
+        if ( !dtTime.ParseTime(date, &endTime) )
+            return NULL;
 
-            pchDate = dtDate.ParseDate(pchTime);
-        }
-    }
+        while ( endTime != date.end() && wxIsspace(*endTime) )
+            ++endTime;
 
-    // If we have a date specified, set our own data to the same date
-    if ( !pchDate || !pchTime )
-        return NULL;
+        const wxString datestr(endTime, date.end());
+        if ( !dtDate.ParseDate(datestr, &endDate) )
+            return NULL;
+
+        endBoth = endTime + (endDate - datestr.begin());
+    }
 
     Set(dtDate.GetDay(), dtDate.GetMonth(), dtDate.GetYear(),
         dtTime.GetHour(), dtTime.GetMinute(), dtTime.GetSecond(),
         dtTime.GetMillisecond());
 
     // Return endpoint of scan
-    return pchDate > pchTime ? pchDate : pchTime;
+    if ( end )
+        *end = endBoth;
+
+    return date.c_str() + (endBoth - date.begin());
 }
 
-const wxChar *wxDateTime::ParseDate(const wxChar *date)
+const char *
+wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
 {
     // 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)
 
-    wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") );
-
-    const wxChar *p = date;
+    const wxStringCharType *p = date.wx_str();
     while ( wxIsspace(*p) )
         p++;
 
     // some special cases
     static struct
     {
-        const wxChar *str;
+        const char *str;
         int dayDiffFromToday;
     } literalDates[] =
     {
@@ -3754,7 +3837,11 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
                     *this += wxDateSpan::Days(dayDiffFromToday);
                 }
 
-                return p;
+                const size_t endpos = p - date.wx_str();
+
+                if ( end )
+                    *end = date.begin() + endpos;
+                return date.c_str() + endpos;
             }
         }
     }
@@ -3778,7 +3865,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
 
     // tokenize the string
     size_t nPosCur = 0;
-    static const wxChar *dateDelimiters = _T(".,/-\t\r\n ");
+    static const wxStringCharType *dateDelimiters = wxS(".,/-\t\r\n ");
     wxStringTokenizer tok(p, dateDelimiters);
     while ( tok.HasMoreTokens() )
     {
@@ -3810,9 +3897,11 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
                 }
                 else // may be either day or year
                 {
+                    // use a leap year if we don't have the year yet to allow
+                    // dates like 2/29/1976 which would be rejected otherwise
                     wxDateTime_t max_days = (wxDateTime_t)(
                         haveMon
-                        ? GetNumOfDaysInMonth(haveYear ? year : Inv_Year, mon)
+                        ? GetNumOfDaysInMonth(haveYear ? year : 1976, mon)
                         : 31
                     );
 
@@ -3885,8 +3974,8 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
             }
             else // not a valid month name
             {
-                wday = GetWeekDayFromName(token, Name_Full | Name_Abbr);
-                if ( wday != Inv_WeekDay )
+                WeekDay wday2 = GetWeekDayFromName(token, Name_Full | Name_Abbr);
+                if ( wday2 != Inv_WeekDay )
                 {
                     // a week day
                     if ( haveWDay )
@@ -3894,12 +3983,14 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
                         break;
                     }
 
+                    wday = wday2;
+
                     haveWDay = true;
                 }
                 else // not a valid weekday name
                 {
                     // try the ordinals
-                    static const wxChar *ordinals[] =
+                    static const char *ordinals[] =
                     {
                         wxTRANSLATE("first"),
                         wxTRANSLATE("second"),
@@ -3965,7 +4056,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
     {
         wxLogDebug(_T("ParseDate: no day, no weekday hence no date."));
 
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     if ( haveWDay && (haveMon || haveYear || haveDay) &&
@@ -3974,7 +4065,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
         // 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 (wxChar *)NULL;
+        return NULL;
     }
 
     if ( !haveWDay && haveYear && !(haveDay && haveMon) )
@@ -4004,7 +4095,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
             // 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 (wxChar *)NULL;
+            return NULL;
         }
     }
 
@@ -4020,6 +4111,11 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
 
     if ( haveDay )
     {
+        // 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;
+
         Set(day, mon, year);
 
         if ( haveWDay )
@@ -4030,7 +4126,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
                 // inconsistency detected
                 wxLogDebug(_T("ParseDate: inconsistent day/weekday."));
 
-                return (wxChar *)NULL;
+                return NULL;
             }
         }
     }
@@ -4050,17 +4146,20 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
         p--;
     }
 
-    return p;
+    const size_t endpos = p - date.wx_str();
+    if ( end )
+        *end = date.begin() + endpos;
+
+    return date.c_str() + endpos;
 }
 
-const wxChar *wxDateTime::ParseTime(const wxChar *time)
+const char *
+wxDateTime::ParseTime(const wxString& time, wxString::const_iterator *end)
 {
-    wxCHECK_MSG( time, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") );
-
     // first try some extra things
     static const struct
     {
-        const wxChar *name;
+        const char *name;
         wxDateTime_t  hour;
     } stdTimes[] =
     {
@@ -4078,56 +4177,35 @@ const wxChar *wxDateTime::ParseTime(const wxChar *time)
             // casts required by DigitalMars
             Set(stdTimes[n].hour, wxDateTime_t(0), wxDateTime_t(0));
 
-            return time + len;
+            if ( end )
+                *end = time.begin() + len;
+
+            return time.c_str() + len;
         }
     }
 
     // try all time formats we may think about in the order from longest to
     // shortest
-
-    // 12hour with AM/PM?
-    const wxChar *result = ParseFormat(time, _T("%I:%M:%S %p"));
-
-    if ( !result )
+    static const char *timeFormats[] =
     {
-        // normally, it's the same, but why not try it?
-        result = ParseFormat(time, _T("%H:%M:%S"));
-    }
+        "%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
+        "%X",           // possibly something from above or maybe something
+                        // completely different -- try it last
 
-    if ( !result )
-    {
-        // 12hour with AM/PM but without seconds?
-        result = ParseFormat(time, _T("%I:%M %p"));
-    }
-
-    if ( !result )
-    {
-        // without seconds?
-        result = ParseFormat(time, _T("%H:%M"));
-    }
-
-    if ( !result )
-    {
-        // just the hour and AM/PM?
-        result = ParseFormat(time, _T("%I %p"));
-    }
-
-    if ( !result )
-    {
-        // just the hour?
-        result = ParseFormat(time, _T("%H"));
-    }
+        // TODO: parse timezones
+    };
 
-    if ( !result )
+    for ( size_t nFmt = 0; nFmt < WXSIZEOF(timeFormats); nFmt++ )
     {
-        // parse the standard format: normally it is one of the formats above
-        // but it may be set to something completely different by the user
-        result = ParseFormat(time, _T("%X"));
+        const char *result = ParseFormat(time, timeFormats[nFmt], end);
+        if ( result )
+            return result;
     }
 
-    // TODO: parse timezones
-
-    return result;
+    return NULL;
 }
 
 // ----------------------------------------------------------------------------
@@ -4187,12 +4265,13 @@ enum TimeSpanPart
 // And, to be better than MFC :-), we also have
 //  %E          number of wEeks
 //  %l          milliseconds (000 - 999)
-wxString wxTimeSpan::Format(const wxChar *format) const
+wxString wxTimeSpan::Format(const wxString& format) const
 {
-    wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxTimeSpan::Format") );
+    wxCHECK_MSG( !format.empty(), wxEmptyString,
+                 _T("NULL format in wxTimeSpan::Format") );
 
     wxString str;
-    str.Alloc(wxStrlen(format));
+    str.Alloc(format.length());
 
     // Suppose we have wxTimeSpan ts(1 /* hour */, 2 /* min */, 3 /* sec */)
     //
@@ -4210,18 +4289,21 @@ wxString wxTimeSpan::Format(const wxChar *format) const
     // we remember the most important unit found so far
     TimeSpanPart partBiggest = Part_MSec;
 
-    for ( const wxChar *pch = format; *pch; pch++ )
+    for ( wxString::const_iterator pch = format.begin(); pch != format.end(); ++pch )
     {
         wxChar ch = *pch;
 
         if ( ch == _T('%') )
         {
             // the start of the format specification of the printf() below
-            wxString fmtPrefix = _T('%');
+            wxString fmtPrefix(_T('%'));
 
             // the number
             long n;
 
+            // the number of digits for the format string, 0 if unused
+            unsigned digits = 0;
+
             ch = *++pch;    // get the format spec char
             switch ( ch )
             {
@@ -4256,6 +4338,13 @@ wxString wxTimeSpan::Format(const wxChar *format) const
                     n = GetHours();
                     if ( partBiggest < Part_Hour )
                     {
+                        if ( n < 0 )
+                        {
+                            // the sign has already been taken into account
+                            // when outputting the biggest part
+                            n = -n;
+                        }
+
                         n %= HOURS_PER_DAY;
                     }
                     else
@@ -4263,25 +4352,31 @@ wxString wxTimeSpan::Format(const wxChar *format) const
                         partBiggest = Part_Hour;
                     }
 
-                    fmtPrefix += _T("02");
+                    digits = 2;
                     break;
 
                 case _T('l'):
                     n = GetMilliseconds().ToLong();
                     if ( partBiggest < Part_MSec )
                     {
+                        if ( n < 0 )
+                            n = -n;
+
                         n %= 1000;
                     }
                     //else: no need to reset partBiggest to Part_MSec, it is
                     //      the least significant one anyhow
 
-                    fmtPrefix += _T("03");
+                    digits = 3;
                     break;
 
                 case _T('M'):
                     n = GetMinutes();
                     if ( partBiggest < Part_Min )
                     {
+                        if ( n < 0 )
+                            n = -n;
+
                         n %= MIN_PER_HOUR;
                     }
                     else
@@ -4289,13 +4384,16 @@ wxString wxTimeSpan::Format(const wxChar *format) const
                         partBiggest = Part_Min;
                     }
 
-                    fmtPrefix += _T("02");
+                    digits = 2;
                     break;
 
                 case _T('S'):
                     n = GetSeconds().ToLong();
                     if ( partBiggest < Part_Sec )
                     {
+                        if ( n < 0 )
+                            n = -n;
+
                         n %= SEC_PER_MIN;
                     }
                     else
@@ -4303,10 +4401,19 @@ wxString wxTimeSpan::Format(const wxChar *format) const
                         partBiggest = Part_Sec;
                     }
 
-                    fmtPrefix += _T("02");
+                    digits = 2;
                     break;
             }
 
+            if ( digits )
+            {
+                // negative numbers need one extra position for '-' display
+                if ( n < 0 )
+                    digits++;
+
+                fmtPrefix << _T("0") << digits;
+            }
+
             str += wxString::Format(fmtPrefix + _T("ld"), n);
         }
         else
@@ -4484,4 +4591,30 @@ WXDLLIMPEXP_BASE void wxPrevWDay(wxDateTime::WeekDay& wd)
                                : (wxDateTime::WeekDay)(wd - 1);
 }
 
+#ifdef __WXMSW__
+
+wxDateTime& wxDateTime::SetFromMSWSysTime(const SYSTEMTIME& st)
+{
+    return Set(st.wDay,
+            wx_static_cast(wxDateTime::Month, wxDateTime::Jan + st.wMonth - 1),
+            st.wYear,
+            0, 0, 0);
+}
+
+void wxDateTime::GetAsMSWSysTime(SYSTEMTIME* st) const
+{
+    const wxDateTime::Tm tm(GetTm());
+
+    st->wYear = (WXWORD)tm.year;
+    st->wMonth = (WXWORD)(tm.mon - wxDateTime::Jan + 1);
+    st->wDay = tm.mday;
+
+    st->wDayOfWeek =
+    st->wHour =
+    st->wMinute =
+    st->wSecond =
+    st->wMilliseconds = 0;
+}
+#endif // __WXMSW__
+
 #endif // wxUSE_DATETIME