]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/datetime.cpp
Revised #ifndef WX_PRECOMP headers, added missing #include wx/wxcrtvararg.h
[wxWidgets.git] / src / common / datetime.cpp
index f0d29667fff5c0f9c4b2039eb42e0ededdcbe237..8bd4933a187b83f9ecbb48717bdfa58ebd455e54 100644 (file)
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////////
-// Name:        wx/datetime.h
+// Name:        src/common/datetime.cpp
 // Purpose:     implementation of time/date related classes
 // Author:      Vadim Zeitlin
 // Modified by:
 // 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:
  *
 // headers
 // ----------------------------------------------------------------------------
 
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-    #pragma implementation "datetime.h"
-#endif
-
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 #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>
@@ -90,7 +86,6 @@
 #endif
 
 #include "wx/datetime.h"
-#include "wx/stopwatch.h"           // for wxGetLocalTimeMillis()
 
 const long wxDateTime::TIME_T_FACTOR = 1000l;
 
@@ -98,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
 
 //
 // ----------------------------------------------------------------------------
@@ -168,23 +163,127 @@ 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
 
+// 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
+
+#ifndef HAVE_LOCALTIME_R
+struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp)
+{
+#if wxUSE_THREADS && !defined(__WINDOWS__)
+  // No need to waste time with a mutex on windows since it's using
+  // thread local storage for localtime anyway.
+  wxMutexLocker locker(timeLock);
+#endif
+
+  // 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 // !HAVE_LOCALTIME_R
+
+#ifndef HAVE_GMTIME_R
+struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp)
+{
+#if wxUSE_THREADS && !defined(__WINDOWS__)
+  // No need to waste time with a mutex on windows since it's
+  // 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 // !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
@@ -235,11 +334,14 @@ static const long MILLISECONDS_PER_DAY = 86400000l;
 // (i.e. JDN(Jan 1, 1970) = 2440587.5)
 static const long EPOCH_JDN = 2440587l;
 
+// used only in asserts
+#ifdef __WXDEBUG__
 // the date of JDN -0.5 (as we don't work with fractional parts, this is the
 // reference date for us) is Nov 24, 4714BC
 static const int JDN_0_YEAR = -4713;
 static const int JDN_0_MONTH = wxDateTime::Nov;
 static const int JDN_0_DAY = 24;
+#endif // __WXDEBUG__
 
 // the constants used for JDN calculations
 static const long JDN_OFFSET         = 32046l;
@@ -259,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
@@ -274,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;
 }
@@ -303,32 +407,32 @@ 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
 
-    // ensure that the timezone variable is set by calling localtime
+    // ensure that the timezone variable is set by calling wxLocaltime_r
     if ( !s_timezoneSet )
     {
-        // just call localtime() instead of figuring out whether this system
-        // supports tzset(), _tzset() or something else
+        // 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 tm;
 
-        tm = localtime(&t);
+        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
@@ -371,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
@@ -382,31 +487,34 @@ static wxString CallStrftime(const wxChar *format, const tm* tm)
 
     if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) )
     {
-        // buffer is too small?
+        // if the format is valid, buffer must be too small?
         wxFAIL_MSG(_T("strftime() failed"));
+
+        buf[0] = '\0';
     }
 
     s = buf;
     return s;
 }
-#endif
+
+#endif // HAVE_STRFTIME
 
 #ifdef HAVE_STRPTIME
 
-// glibc2 doesn't define this in the headers unless _XOPEN_SOURCE is defined
-// which, unfortunately, wreaks havoc elsewhere
-#if defined(__GLIBC__) && (__GLIBC__ == 2)
+#if wxUSE_UNIX && !defined(HAVE_STRPTIME_DECL)
+    // configure detected that we had strptime() but not its declaration,
+    // provide it ourselves
     extern "C" char *strptime(const char *, const char *, struct tm *);
 #endif
 
 // Unicode-friendly strptime() wrapper
-static const 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;
@@ -416,7 +524,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
@@ -431,10 +539,11 @@ static void ReplaceDefaultYearMonthWithCurrent(int *year,
                                                wxDateTime::Month *month)
 {
     struct tm *tmNow = NULL;
+    struct tm tmstruct;
 
     if ( *year == wxDateTime::Inv_Year )
     {
-        tmNow = wxDateTime::GetTmNow();
+        tmNow = wxDateTime::GetTmNow(&tmstruct);
 
         *year = 1900 + tmNow->tm_year;
     }
@@ -442,7 +551,7 @@ static void ReplaceDefaultYearMonthWithCurrent(int *year,
     if ( *month == wxDateTime::Inv_Month )
     {
         if ( !tmNow )
-            tmNow = wxDateTime::GetTmNow();
+            tmNow = wxDateTime::GetTmNow(&tmstruct);
 
         *month = (wxDateTime::Month)tmNow->tm_mon;
     }
@@ -523,8 +632,17 @@ static wxDateTime::WeekDay GetWeekDayFromName(const wxString& name, int flags)
     return wd;
 }
 
+/* static */
+struct tm *wxDateTime::GetTmNow(struct tm *tmstruct)
+{
+    time_t t = GetTimeNow();
+    return wxLocaltime_r(&t, tmstruct);
+}
+
 // scans all digits (but no more than len) and returns the resulting number
-static bool GetNumericToken(size_t len, const wxChar*& p, unsigned long *number)
+static bool GetNumericToken(size_t len,
+                            const wxStringCharType*& p,
+                            unsigned long *number)
 {
     size_t n = 1;
     wxString s;
@@ -540,7 +658,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) )
@@ -595,7 +713,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)
@@ -687,6 +805,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;
 
@@ -837,7 +956,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;
@@ -845,7 +964,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)
     {
@@ -887,7 +1006,7 @@ wxString wxDateTime::GetMonthName(wxDateTime::Month month,
             break;
     }
     return ret;
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
 }
 
 /* static */
@@ -895,7 +1014,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!)
@@ -913,7 +1032,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)
     {
@@ -940,8 +1059,7 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday,
             break;
     }
     return ret;
-
-#endif
+#endif // HAVE_STRFTIME/!HAVE_STRFTIME
 }
 
 /* static */
@@ -989,7 +1107,8 @@ wxDateTime::Country wxDateTime::GetCountry()
     {
         // try to guess from the time zone name
         time_t t = time(NULL);
-        struct tm *tm = localtime(&t);
+        struct tm tmstruct;
+        struct tm *tm = wxLocaltime_r(&t, &tmstruct);
 
         wxString tz = CallStrftime(_T("%Z"), tm);
         if ( tz == _T("WET") || tz == _T("WEST") )
@@ -1018,9 +1137,9 @@ wxDateTime::Country wxDateTime::GetCountry()
             ms_country = USA;
         }
     }
-#else
+#else // __WXWINCE__
      ms_country = USA;
-#endif
+#endif // !__WXWINCE__/__WXWINCE__
 
     return ms_country;
 }
@@ -1111,9 +1230,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 )
     {
@@ -1212,9 +1328,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 )
     {
@@ -1312,9 +1425,10 @@ wxDateTime& wxDateTime::Set(wxDateTime_t hour,
                       _T("Invalid time in wxDateTime::Set()") );
 
     // get the current date from system
-    struct tm *tm = GetTmNow();
+    struct tm tmstruct;
+    struct tm *tm = GetTmNow(&tmstruct);
 
-    wxDATETIME_CHECK( tm, _T("localtime() failed") );
+    wxDATETIME_CHECK( tm, _T("wxLocaltime_r() failed") );
 
     // make a copy so it isn't clobbered by the call to mktime() below
     struct tm tm1(*tm);
@@ -1429,6 +1543,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
 // ----------------------------------------------------------------------------
@@ -1480,7 +1604,9 @@ unsigned long wxDateTime::GetAsDOS() const
 {
     unsigned long ddt;
     time_t ticks = GetTicks();
-    struct tm *tm = localtime(&ticks);
+    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;
@@ -1518,14 +1644,15 @@ wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const
     if ( time != (time_t)-1 )
     {
         // use C RTL functions
+        struct tm tmstruct;
         tm *tm;
         if ( tz.GetOffset() == -GetTimeZone() )
         {
             // we are working with local time
-            tm = localtime(&time);
+            tm = wxLocaltime_r(&time, &tmstruct);
 
             // should never happen
-            wxCHECK_MSG( tm, Tm(), _T("localtime() failed") );
+            wxCHECK_MSG( tm, Tm(), _T("wxLocaltime_r() failed") );
         }
         else
         {
@@ -1537,10 +1664,10 @@ wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const
             if ( time >= 0 )
 #endif
             {
-                tm = gmtime(&time);
+                tm = wxGmtime_r(&time, &tmstruct);
 
                 // should never happen
-                wxCHECK_MSG( tm, Tm(), _T("gmtime() failed") );
+                wxCHECK_MSG( tm, Tm(), _T("wxGmtime_r() failed") );
             }
             else
             {
@@ -1774,6 +1901,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
@@ -1811,6 +1939,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)
@@ -2121,9 +2250,10 @@ int wxDateTime::IsDST(wxDateTime::Country country) const
     time_t timet = GetTicks();
     if ( timet != (time_t)-1 )
     {
-        tm *tm = localtime(&timet);
+        struct tm tmstruct;
+        tm *tm = wxLocaltime_r(&timet, &tmstruct);
 
-        wxCHECK_MSG( tm, -1, _T("localtime() failed") );
+        wxCHECK_MSG( tm, -1, _T("wxLocaltime_r() failed") );
 
         return tm->tm_isdst;
     }
@@ -2175,24 +2305,28 @@ 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()
-        tm *tm;
+        struct tm tmstruct;
+        struct tm *tm;
         if ( tz.GetOffset() == -GetTimeZone() )
         {
             // we are working with local time
-            tm = localtime(&time);
+            tm = wxLocaltime_r(&time, &tmstruct);
 
             // should never happen
-            wxCHECK_MSG( tm, wxEmptyString, _T("localtime() failed") );
+            wxCHECK_MSG( tm, wxEmptyString, _T("wxLocaltime_r() failed") );
         }
         else
         {
@@ -2205,25 +2339,24 @@ wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const
             if ( time >= 0 )
 #endif
             {
-                tm = gmtime(&time);
+                tm = wxGmtime_r(&time, &tmstruct);
 
                 // should never happen
-                wxCHECK_MSG( tm, wxEmptyString, _T("gmtime() failed") );
+                wxCHECK_MSG( tm, wxEmptyString, _T("wxGmtime_r() failed") );
             }
             else
             {
                 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
@@ -2243,7 +2376,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('%') )
         {
@@ -2254,7 +2387,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");
@@ -2283,7 +2416,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'):
@@ -2300,7 +2433,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.
@@ -2322,7 +2455,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
@@ -2364,33 +2497,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") );
+                        // 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 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 fmt = format;
-                        wxString replacement = (wxChar)-1;
-                        while ( fmt.Find(replacement) != wxNOT_FOUND )
-                        {
-                            replacement << (wxChar)-1;
-                        }
-
-                        wxString replacement2 = (wxChar)-2;
-                        while ( fmt.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 = fmt.Replace(strYear, replacement) > 0;
-                        if ( !wasReplaced )
-                            wasReplaced = fmt.Replace(strYear2, replacement2) > 0;
 
                         // use strftime() to format the same date but in supported
                         // year
@@ -2414,27 +2529,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)
@@ -2471,11 +2590,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)
@@ -2498,11 +2617,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)
@@ -2514,7 +2633,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;
@@ -2569,12 +2688,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
@@ -2587,7 +2706,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
@@ -2598,7 +2717,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'));
@@ -2610,7 +2729,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
     if ( *p++ != _T(' ') )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     // the following 3 letters specify the month
@@ -2644,21 +2763,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');
@@ -2666,7 +2785,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;
@@ -2681,7 +2800,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
         if ( !wxIsdigit(*p) )
         {
             // no 3 digit years please
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         year *= 10;
@@ -2690,20 +2809,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;
@@ -2711,37 +2830,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;
@@ -2750,7 +2870,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
     if ( *p++ != _T(' ') )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     // and now the interesting part: the timezone
@@ -2762,7 +2882,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
         if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) )
         {
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         // hours
@@ -2772,7 +2892,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
         if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) )
         {
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         // minutes
@@ -2804,7 +2924,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')];
@@ -2839,7 +2959,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
             {
                 wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p);
 
-                return (wxChar *)NULL;
+                return NULL;
             }
 
             p += tz.length();
@@ -2851,9 +2971,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__
@@ -3016,12 +3140,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;
@@ -3049,8 +3174,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('%') )
         {
@@ -3070,7 +3195,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( *input++ != *fmt )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
             }
 
@@ -3091,7 +3216,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;
@@ -3113,7 +3238,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'):
@@ -3123,7 +3248,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     if ( wday == Inv_WeekDay )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
                 }
                 haveWDay = true;
@@ -3137,7 +3262,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     if ( mon == Inv_Month )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
                 }
                 haveMon = true;
@@ -3147,25 +3272,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();
@@ -3181,7 +3297,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     mon = tm.mon;
                     mday = tm.mday;
 
-                    input = result;
+                    input += endc - inc.begin();
                 }
                 break;
 
@@ -3190,7 +3306,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
@@ -3203,7 +3319,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 23) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveHour = true;
@@ -3214,7 +3330,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;
@@ -3226,7 +3342,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;
@@ -3237,7 +3353,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;
@@ -3248,7 +3364,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 59) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveMin = true;
@@ -3261,7 +3377,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;
@@ -3269,7 +3385,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     else if ( token.CmpNoCase(am) != 0 )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
                 }
                 break;
@@ -3277,11 +3393,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;
@@ -3296,11 +3412,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;
@@ -3315,7 +3431,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 61) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveSec = true;
@@ -3329,7 +3445,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     if ( !input )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
 
                     haveHour = haveMin = haveSec = true;
@@ -3345,7 +3461,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (wday > 6) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveWDay = true;
@@ -3360,7 +3476,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;
@@ -3386,7 +3503,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 )
@@ -3401,29 +3518,29 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                         }
                     }
 
-                    const wxChar *result = dt.ParseFormat(input, fmtDate);
-
-                    if ( !result && !fmtDateAlt.empty() )
+                    const wxString indate(input);
+                    wxString::const_iterator endDate;
+                    if ( !dt.ParseFormat(indate, fmtDate, &endDate) )
                     {
-                        // ok, be nice and try another one
-                        result = dt.ParseFormat(input, fmtDateAlt);
-                    }
-
-                    if ( !result )
-                    {
-                        // 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;
@@ -3436,7 +3553,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     input = CallStrptime(input, "%X", &tm);
                     if ( !input )
                     {
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
 
                     haveHour = haveMin = haveSec = true;
@@ -3455,19 +3572,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;
@@ -3483,7 +3603,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 99) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveYear = true;
@@ -3497,7 +3617,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveYear = true;
@@ -3512,7 +3632,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( *input++ != _T('%') )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
                 break;
 
@@ -3522,7 +3642,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 // fall through
 
             default:            // not a known format spec
-                return (wxChar *)NULL;
+                return NULL;
         }
     }
 
@@ -3561,7 +3681,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
         {
             wxLogDebug(_T("bad month day in wxDateTime::ParseFormat"));
 
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         tm.mon = mon;
@@ -3573,7 +3693,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();
@@ -3616,73 +3736,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[] =
     {
@@ -3693,12 +3822,12 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
 
     for ( size_t n = 0; n < WXSIZEOF(literalDates); n++ )
     {
-        wxString date = wxGetTranslation(literalDates[n].str);
-        size_t len = date.length();
+        const wxString dateStr = wxGetTranslation(literalDates[n].str);
+        size_t len = dateStr.length();
         if ( wxStrlen(p) >= len )
         {
             wxString str(p, len);
-            if ( str.CmpNoCase(date) == 0 )
+            if ( str.CmpNoCase(dateStr) == 0 )
             {
                 // nothing can follow this, so stop here
                 p += len;
@@ -3710,7 +3839,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;
             }
         }
     }
@@ -3734,7 +3867,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() )
     {
@@ -3766,9 +3899,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
                     );
 
@@ -3841,8 +3976,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 )
@@ -3850,12 +3985,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"),
@@ -3921,7 +4058,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) &&
@@ -3930,7 +4067,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) )
@@ -3960,7 +4097,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;
         }
     }
 
@@ -3976,6 +4113,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 )
@@ -3986,7 +4128,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
                 // inconsistency detected
                 wxLogDebug(_T("ParseDate: inconsistent day/weekday."));
 
-                return (wxChar *)NULL;
+                return NULL;
             }
         }
     }
@@ -4006,17 +4148,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[] =
     {
@@ -4034,56 +4179,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;
 }
 
 // ----------------------------------------------------------------------------
@@ -4143,12 +4267,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 */)
     //
@@ -4166,18 +4291,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 )
             {
@@ -4212,6 +4340,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
@@ -4219,25 +4354,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
@@ -4245,13 +4386,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
@@ -4259,10 +4403,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
@@ -4281,7 +4434,7 @@ wxString wxTimeSpan::Format(const wxChar *format) const
 
 #include "wx/arrimpl.cpp"
 
-WX_DEFINE_OBJARRAY(wxDateTimeArray);
+WX_DEFINE_OBJARRAY(wxDateTimeArray)
 
 static int wxCMPFUNC_CONV
 wxDateTimeCompareFunc(wxDateTime **first, wxDateTime **second)
@@ -4323,8 +4476,8 @@ wxDateTimeHolidayAuthority::GetHolidaysInRange(const wxDateTime& dtStart,
 
     holidays.Clear();
 
-    size_t count = ms_authorities.size();
-    for ( size_t nAuth = 0; nAuth < count; nAuth++ )
+    const size_t countAuth = ms_authorities.size();
+    for ( size_t nAuth = 0; nAuth < countAuth; nAuth++ )
     {
         ms_authorities[nAuth]->DoGetHolidaysInRange(dtStart, dtEnd, hol);
 
@@ -4440,4 +4593,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