]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/datetime.cpp
fix (harmless for now) g++ warning about non-virtual dtor
[wxWidgets.git] / src / common / datetime.cpp
index 906710008547363daaa90a9febf0e6eadb651763..1547b4a14e14bc0c957be8820626b8e0a9f14531 100644 (file)
@@ -93,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
 
 //
 // ----------------------------------------------------------------------------
@@ -138,13 +138,6 @@ wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter<wxDateTime> , wxFromStringCon
     #include <wtime.h>
 #endif
 
-// define a special symbol for VC8 instead of writing tests for 1400 repeatedly
-#ifdef __VISUALC__
-    #if __VISUALC__ >= 1400
-        #define __VISUALC8__
-    #endif
-#endif
-
 #if !defined(WX_TIMEZONE) && !defined(WX_GMTOFF_IN_TM)
     #if defined(__WXPALMOS__)
         #define WX_GMTOFF_IN_TM
@@ -171,7 +164,39 @@ wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter<wxDateTime> , wxFromStringCon
     #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
@@ -336,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
@@ -351,11 +376,14 @@ 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"));
+    wxStrlcpy(buf,
+              (fmt + " (" + dt->GetValue().ToString() + " ticks)").ToAscii(),
+              WXSIZEOF(buf));
 
     return buf;
 }
@@ -460,8 +488,10 @@ static wxString CallStrftime(const wxString& 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;
@@ -479,13 +509,13 @@ static wxString CallStrftime(const wxString& 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;
@@ -495,7 +525,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
@@ -611,7 +641,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;
@@ -627,7 +659,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) )
@@ -1199,9 +1231,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 )
     {
@@ -1244,6 +1273,17 @@ wxDateTime wxDateTime::GetBeginDST(int year, Country country)
                             wxFAIL_MSG( _T("no first Sunday in April?") );
                         }
                     }
+                    else if ( year > 2006 )
+                    // Energy Policy Act of 2005, Pub. L. no. 109-58, 119 Stat 594 (2005).
+                    // Starting in 2007, daylight time begins in the United States on the
+                    // second Sunday in March and ends on the first Sunday in November
+                    {
+                        if ( !dt.SetToWeekDay(Sun, 2, Mar, year) )
+                        {
+                            // weird...
+                            wxFAIL_MSG( _T("no second Sunday in March?") );
+                        }
+                    }
                     else
                     {
                         if ( !dt.SetToWeekDay(Sun, 1, Apr, year) )
@@ -1300,9 +1340,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 )
     {
@@ -1323,21 +1360,36 @@ wxDateTime wxDateTime::GetEndDST(int year, Country country)
                     dt.Set(30, Sep, year);
                     break;
 
-                default:
-                    // DST ends at 2 a.m. on the last Sunday of October
-                    if ( !dt.SetToLastWeekDay(Sun, Oct, year) )
+                default: // default for switch (year)
+                    if ( year > 2006 )
+                      // Energy Policy Act of 2005, Pub. L. no. 109-58, 119 Stat 594 (2005).
+                      // Starting in 2007, daylight time begins in the United States on the
+                      // second Sunday in March and ends on the first Sunday in November
+                    {
+                        if ( !dt.SetToWeekDay(Sun, 1, Nov, year) )
+                        {
+                            // weird...
+                            wxFAIL_MSG( _T("no first Sunday in November?") );
+                        }
+                    }
+                    else
+                     // pre-2007
+                     // DST ends at 2 a.m. on the last Sunday of October
                     {
-                        // weirder and weirder...
-                        wxFAIL_MSG( _T("no last Sunday in October?") );
+                        if ( !dt.SetToLastWeekDay(Sun, Oct, year) )
+                        {
+                            // weirder and weirder...
+                            wxFAIL_MSG( _T("no last Sunday in October?") );
+                        }
                     }
 
                     dt += wxTimeSpan::Hours(2);
 
-                    // TODO what about timezone??
+            // TODO: what about timezone??
             }
             break;
 
-        default:
+        default: // default for switch (country)
             // assume October 26th as the end of the DST - totally bogus too
             dt.Set(26, Oct, year);
     }
@@ -1581,6 +1633,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;
@@ -2429,7 +2482,7 @@ wxString wxDateTime::Format(const wxString& 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
@@ -2471,41 +2524,15 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                             nLostWeekDays += year++ % 4 ? 1 : 2;
                         }
 
-                        // Keep year below 2000 so the 2digit year number
-                        // can never match the month or day of the month
-                        if (year>=2000) year-=28;
-                        // 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 four strings not occurring in format (this is surely
-                        // not the optimal way of doing it... improvements welcome!)
-                        wxString fmt2 = format;
-                        wxString replacement,replacement2,replacement3,replacement4;
-                        for (int rnr=1; rnr<5 ; rnr++)
-                        {
-                            wxString r = (wxChar)-rnr;
-                            while ( fmt2.Find(r) != wxNOT_FOUND )
-                            {
-                                r << (wxChar)-rnr;
-                            }
+                        wxASSERT_MSG( year >= 1970 && year < 2000,
+                                      _T("logic error in wxDateTime::Format") );
 
-                            switch (rnr)
-                            {
-                                case 1: replacement=r; break;
-                                case 2: replacement2=r; break;
-                                case 3: replacement3=r; break;
-                                case 4: replacement4=r; break;
-                            }
-                        }
-                        // replace all occurrences of year with it
-                        bool wasReplaced = fmt2.Replace(strYear, replacement) > 0;
-                        // evaluation order ensures we always attempt the replacement.
-                        wasReplaced = (fmt2.Replace(strYear2, replacement2) > 0) || wasReplaced;
 
                         // use strftime() to format the same date but in supported
                         // year
@@ -2529,25 +2556,23 @@ wxString wxDateTime::Format(const wxString& format, const TimeZone& tz) const
                                                                   : _T("%x"),
                                                     &tmAdjusted);
 
-                        // now replace the occurrence of 1999 with the real year
-                        // we do this in two stages to stop the 2 digit year
-                        // matching any substring of the 4 digit year.
-                        // Any day,month hours and minutes components should be safe due
-                        // to ensuring the range of the years.
-                        wxString strYearReal, strYearReal2;
-                        strYearReal.Printf(_T("%04d"), yearReal);
-                        strYearReal2.Printf(_T("%02d"), yearReal % 100);
-                        str.Replace(strYear, replacement3);
-                        str.Replace(strYear2,replacement4);
-                        str.Replace(replacement3, strYearReal);
-                        str.Replace(replacement4, 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;
                     }
@@ -2690,12 +2715,12 @@ wxString wxDateTime::Format(const wxString& 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
@@ -2708,7 +2733,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
@@ -2719,7 +2744,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'));
@@ -2731,7 +2756,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
     if ( *p++ != _T(' ') )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     // the following 3 letters specify the month
@@ -2765,21 +2790,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');
@@ -2787,7 +2812,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;
@@ -2802,7 +2827,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
         if ( !wxIsdigit(*p) )
         {
             // no 3 digit years please
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         year *= 10;
@@ -2811,20 +2836,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;
@@ -2832,37 +2857,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;
@@ -2871,7 +2897,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
     if ( *p++ != _T(' ') )
     {
-        return (wxChar *)NULL;
+        return NULL;
     }
 
     // and now the interesting part: the timezone
@@ -2883,7 +2909,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
         if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) )
         {
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         // hours
@@ -2893,7 +2919,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
 
         if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) )
         {
-            return (wxChar *)NULL;
+            return NULL;
         }
 
         // minutes
@@ -2925,7 +2951,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')];
@@ -2960,7 +2986,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
             {
                 wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p);
 
-                return (wxChar *)NULL;
+                return NULL;
             }
 
             p += tz.length();
@@ -2972,9 +2998,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));
+
+    const size_t endpos = p - date.wx_str();
+    if ( end )
+        *end = date.begin() + endpos;
 
-    return p;
+    return date.c_str() + endpos;
 }
 
 #ifdef __WINDOWS__
@@ -3137,12 +3167,13 @@ static wxString GetLocaleDateFormat()
 
 #endif // __WINDOWS__
 
-const wxChar *wxDateTime::ParseFormat(const wxChar *date,
-                                      const wxString& 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.empty(), (wxChar *)NULL,
-                 _T("NULL pointer in wxDateTime::ParseFormat()") );
+    wxCHECK_MSG( !format.empty(), NULL, "format can't be empty" );
 
     wxString str;
     unsigned long num;
@@ -3170,7 +3201,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
     wxDateTime::Month mon = Inv_Month;
     int year = 0;
 
-    const wxChar *input = date;
+    const wxStringCharType *input = date.wx_str();
     for ( wxString::const_iterator fmt = format.begin(); fmt != format.end(); ++fmt )
     {
         if ( *fmt != _T('%') )
@@ -3191,7 +3222,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( *input++ != *fmt )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
             }
 
@@ -3244,7 +3275,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     if ( wday == Inv_WeekDay )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
                 }
                 haveWDay = true;
@@ -3258,7 +3289,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     if ( mon == Inv_Month )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
                 }
                 haveMon = true;
@@ -3268,25 +3299,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 wxString inc(input);
 
-                    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"));
-                    }
-
-                    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();
@@ -3302,7 +3324,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     mon = tm.mon;
                     mday = tm.mday;
 
-                    input = result;
+                    input += endc - inc.begin();
                 }
                 break;
 
@@ -3311,7 +3333,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
@@ -3324,7 +3346,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 23) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveHour = true;
@@ -3335,7 +3357,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;
@@ -3347,7 +3369,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;
@@ -3358,7 +3380,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;
@@ -3369,7 +3391,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 59) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveMin = true;
@@ -3382,7 +3404,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;
@@ -3390,7 +3412,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     else if ( token.CmpNoCase(am) != 0 )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
                 }
                 break;
@@ -3398,11 +3420,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;
@@ -3417,11 +3439,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;
@@ -3436,7 +3458,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 61) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveSec = true;
@@ -3450,7 +3472,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     if ( !input )
                     {
                         // no match
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
 
                     haveHour = haveMin = haveSec = true;
@@ -3466,7 +3488,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (wday > 6) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveWDay = true;
@@ -3481,7 +3503,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;
@@ -3507,7 +3530,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 )
@@ -3522,29 +3545,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;
@@ -3557,7 +3580,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                     input = CallStrptime(input, "%X", &tm);
                     if ( !input )
                     {
-                        return (wxChar *)NULL;
+                        return NULL;
                     }
 
                     haveHour = haveMin = haveSec = true;
@@ -3576,19 +3599,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;
@@ -3604,7 +3630,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) || (num > 99) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveYear = true;
@@ -3618,7 +3644,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( !GetNumericToken(width, input, &num) )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
 
                 haveYear = true;
@@ -3633,7 +3659,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 if ( *input++ != _T('%') )
                 {
                     // no match
-                    return (wxChar *)NULL;
+                    return NULL;
                 }
                 break;
 
@@ -3643,7 +3669,7 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
                 // fall through
 
             default:            // not a known format spec
-                return (wxChar *)NULL;
+                return NULL;
         }
     }
 
@@ -3668,6 +3694,11 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
     Tm tm = tmDef;
 
     // set the date
+    if ( haveMon )
+    {
+        tm.mon = mon;
+    }
+
     if ( haveYear )
     {
         tm.year = year;
@@ -3676,16 +3707,15 @@ const wxChar *wxDateTime::ParseFormat(const wxChar *date,
     // TODO we don't check here that the values are consistent, if both year
     //      day and month/day were found, we just ignore the year day and we
     //      also always ignore the week day
-    if ( haveMon && haveDay )
+    if ( haveDay )
     {
-        if ( mday > GetNumOfDaysInMonth(tm.year, mon) )
+        if ( mday > GetNumOfDaysInMonth(tm.year, tm.mon) )
         {
             wxLogDebug(_T("bad month day in wxDateTime::ParseFormat"));
 
-            return (wxChar *)NULL;
+            return NULL;
         }
 
-        tm.mon = mon;
         tm.mday = mday;
     }
     else if ( haveYDay )
@@ -3694,7 +3724,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();
@@ -3737,73 +3767,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[] =
     {
@@ -3831,7 +3870,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;
             }
         }
     }
@@ -3855,7 +3898,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() )
     {
@@ -3964,8 +4007,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 )
@@ -3973,12 +4016,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"),
@@ -4114,7 +4159,7 @@ const wxChar *wxDateTime::ParseDate(const wxChar *date)
                 // inconsistency detected
                 wxLogDebug(_T("ParseDate: inconsistent day/weekday."));
 
-                return (wxChar *)NULL;
+                return NULL;
             }
         }
     }
@@ -4134,17 +4179,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[] =
     {
@@ -4162,56 +4210,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 )
-    {
-        // normally, it's the same, but why not try it?
-        result = ParseFormat(time, _T("%H:%M:%S"));
-    }
-
-    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 )
+    static const char *timeFormats[] =
     {
-        // just the hour and AM/PM?
-        result = ParseFormat(time, _T("%I %p"));
-    }
+        "%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 )
-    {
-        // 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;
 }
 
 // ----------------------------------------------------------------------------
@@ -4273,6 +4300,14 @@ enum TimeSpanPart
 //  %l          milliseconds (000 - 999)
 wxString wxTimeSpan::Format(const wxString& format) const
 {
+    // we deal with only positive time spans here and just add the sign in
+    // front for the negative ones
+    if ( IsNegative() )
+    {
+        wxString str(Negate().Format(format));
+        return "-" + str;
+    }
+
     wxCHECK_MSG( !format.empty(), wxEmptyString,
                  _T("NULL format in wxTimeSpan::Format") );
 
@@ -4344,13 +4379,6 @@ wxString wxTimeSpan::Format(const wxString& 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
@@ -4365,9 +4393,6 @@ wxString wxTimeSpan::Format(const wxString& format) const
                     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
@@ -4380,9 +4405,6 @@ wxString wxTimeSpan::Format(const wxString& format) const
                     n = GetMinutes();
                     if ( partBiggest < Part_Min )
                     {
-                        if ( n < 0 )
-                            n = -n;
-
                         n %= MIN_PER_HOUR;
                     }
                     else
@@ -4397,9 +4419,6 @@ wxString wxTimeSpan::Format(const wxString& format) const
                     n = GetSeconds().ToLong();
                     if ( partBiggest < Part_Sec )
                     {
-                        if ( n < 0 )
-                            n = -n;
-
                         n %= SEC_PER_MIN;
                     }
                     else
@@ -4413,10 +4432,6 @@ wxString wxTimeSpan::Format(const wxString& format) const
 
             if ( digits )
             {
-                // negative numbers need one extra position for '-' display
-                if ( n < 0 )
-                    digits++;
-
                 fmtPrefix << _T("0") << digits;
             }
 
@@ -4597,4 +4612,30 @@ WXDLLIMPEXP_BASE void wxPrevWDay(wxDateTime::WeekDay& wd)
                                : (wxDateTime::WeekDay)(wd - 1);
 }
 
+#ifdef __WXMSW__
+
+wxDateTime& wxDateTime::SetFromMSWSysTime(const SYSTEMTIME& st)
+{
+    return Set(st.wDay,
+            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