]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/datetime.cpp
Always link with expat in monolithic build.
[wxWidgets.git] / src / common / datetime.cpp
index 164cc5b7054f435f08aa5c6e59ef7959fe496502..90038a27c3b601fe16d9e26f5e24370f3d8e1dcc 100644 (file)
@@ -75,6 +75,7 @@
 #endif // WX_PRECOMP
 
 #include "wx/thread.h"
+#include "wx/time.h"
 #include "wx/tokenzr.h"
 
 #include <ctype.h>
@@ -108,149 +109,6 @@ wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter<wxDateTime> , wxFromStringCon
 
 #endif // wxUSE_EXTENDED_RTTI
 
-
-// ----------------------------------------------------------------------------
-// conditional compilation
-// ----------------------------------------------------------------------------
-
-#if defined(__MWERKS__) && wxUSE_UNICODE
-    #include <wtime.h>
-#endif
-
-#if !defined(WX_TIMEZONE) && !defined(WX_GMTOFF_IN_TM)
-    #if defined(__WXPALMOS__)
-        #define WX_GMTOFF_IN_TM
-    #elif defined(__BORLANDC__) || defined(__MINGW32__) || defined(__VISAGECPP__)
-        #define WX_TIMEZONE _timezone
-    #elif defined(__MWERKS__)
-        long wxmw_timezone = 28800;
-        #define WX_TIMEZONE wxmw_timezone
-    #elif defined(__DJGPP__) || defined(__WINE__)
-        #include <sys/timeb.h>
-        #include <values.h>
-        static long wxGetTimeZone()
-        {
-            static long timezone = MAXLONG; // invalid timezone
-            if (timezone == MAXLONG)
-            {
-                struct timeb tb;
-                ftime(&tb);
-                timezone = tb.timezone;
-            }
-            return timezone;
-        }
-        #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
-
-// 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
 // ----------------------------------------------------------------------------
@@ -296,8 +154,6 @@ static const int SEC_PER_MIN = 60;
 
 static const int MIN_PER_HOUR = 60;
 
-static const int HOURS_PER_DAY = 24;
-
 static const long SECONDS_PER_DAY = 86400l;
 
 static const int DAYS_PER_WEEK = 7;
@@ -308,14 +164,15 @@ 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__
+// these values are only used in asserts so don't define them if asserts are
+// disabled to avoid warnings about unused static variables
+#if wxDEBUG_LEVEL
 // 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__
+#endif // wxDEBUG_LEVEL
 
 // the constants used for JDN calculations
 static const long JDN_OFFSET         = 32046l;
@@ -337,8 +194,8 @@ const long wxDateTime::TIME_T_FACTOR = 1000l;
 // global data
 // ----------------------------------------------------------------------------
 
-const char *wxDefaultDateTimeFormat = "%c";
-const char *wxDefaultTimeSpanFormat = "%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
@@ -350,8 +207,8 @@ wxDateTime::Country wxDateTime::ms_country = wxDateTime::Country_Unknown;
 // private functions
 // ----------------------------------------------------------------------------
 
-// debugger helper: shows what the date really is
-#ifdef __WXDEBUG__
+// debugger helper: this function can be called from a debugger to show what
+// the date really is
 extern const char *wxDumpDate(const wxDateTime* dt)
 {
     static char buf[128];
@@ -363,7 +220,6 @@ extern const char *wxDumpDate(const wxDateTime* dt)
 
     return buf;
 }
-#endif // Debug
 
 // get the number of days in the given month of the given year
 static inline
@@ -371,7 +227,7 @@ wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month)
 {
     // the number of days in month in Julian/Gregorian calendar: the first line
     // is for normal years, the second one is for the leap ones
-    static wxDateTime::wxDateTime_t daysInMonth[2][MONTHS_IN_YEAR] =
+    static const wxDateTime::wxDateTime_t daysInMonth[2][MONTHS_IN_YEAR] =
     {
         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
@@ -380,39 +236,6 @@ wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month)
     return daysInMonth[wxDateTime::IsLeapYear(year)][month];
 }
 
-// returns the time zone in the C sense, i.e. the difference UTC - local
-// (in seconds)
-// NOTE: not static because used by datetimefmt.cpp
-int GetTimeZone()
-{
-    // 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 wxLocaltime_r
-    if ( !s_timezoneSet )
-    {
-        // just call wxLocaltime_r() instead of figuring out whether this
-        // system supports tzset(), _tzset() or something else
-        time_t t = 0;
-        struct tm tm;
-
-        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;
-#else // !WX_GMTOFF_IN_TM
-        gmtoffset = WX_TIMEZONE;
-#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM
-    }
-
-    return (int)gmtoffset;
-}
-
 // return the integral part of the JDN for the midnight of the given date (to
 // get the real JDN you need to add 0.5, this is, in fact, JDN of the
 // noon of the previous day)
@@ -427,7 +250,7 @@ static long GetTruncatedJDN(wxDateTime::wxDateTime_t day,
       (year > JDN_0_YEAR) ||
       ((year == JDN_0_YEAR) && (mon > JDN_0_MONTH)) ||
       ((year == JDN_0_YEAR) && (mon == JDN_0_MONTH) && (day >= JDN_0_DAY)),
-      _T("date out of range - can't convert to JDN")
+      wxT("date out of range - can't convert to JDN")
                 );
 
     // make the year positive to avoid problems with negative numbers division
@@ -453,7 +276,7 @@ static long GetTruncatedJDN(wxDateTime::wxDateTime_t day,
             - JDN_OFFSET;
 }
 
-#ifdef HAVE_STRFTIME
+#ifdef wxHAS_STRFTIME
 
 // this function is a wrapper around strftime(3) adding error checking
 // NOTE: not static because used by datetimefmt.cpp
@@ -466,8 +289,15 @@ wxString CallStrftime(const wxString& format, const tm* tm)
 
     if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) )
     {
-        // if the format is valid, buffer must be too small?
-        wxFAIL_MSG(_T("strftime() failed"));
+        // There is one special case in which strftime() can return 0 without
+        // indicating an error: "%p" may give empty string depending on the
+        // locale, so check for it explicitly. Apparently it's really the only
+        // exception.
+        if ( format != wxS("%p") )
+        {
+            // if the format is valid, buffer must be too small?
+            wxFAIL_MSG(wxT("strftime() failed"));
+        }
 
         buf[0] = '\0';
     }
@@ -476,7 +306,7 @@ wxString CallStrftime(const wxString& format, const tm* tm)
     return s;
 }
 
-#endif // HAVE_STRFTIME
+#endif // wxHAS_STRFTIME
 
 // if year and/or month have invalid values, replace them with the current ones
 static void ReplaceDefaultYearMonthWithCurrent(int *year,
@@ -526,8 +356,12 @@ wxDateTime::Tm::Tm()
 {
     year = (wxDateTime_t)wxDateTime::Inv_Year;
     mon = wxDateTime::Inv_Month;
-    mday = 0;
-    hour = min = sec = msec = 0;
+    mday =
+    yday = 0;
+    hour =
+    min =
+    sec =
+    msec = 0;
     wday = wxDateTime::Inv_WeekDay;
 }
 
@@ -547,9 +381,17 @@ wxDateTime::Tm::Tm(const struct tm& tm, const TimeZone& tz)
 
 bool wxDateTime::Tm::IsValid() const
 {
+    if ( mon == wxDateTime::Inv_Month )
+        return false;
+
+    // We need to check this here to avoid crashing in GetNumOfDaysInMonth() if
+    // somebody passed us "(wxDateTime::Month)1000".
+    wxCHECK_MSG( mon >= wxDateTime::Jan && mon < wxDateTime::Inv_Month, false,
+                 wxS("Invalid month value") );
+
     // we allow for the leap seconds, although we don't use them (yet)
     return (year != wxDateTime::Inv_Year) && (mon != wxDateTime::Inv_Month) &&
-           (mday <= GetNumOfDaysInMonth(year, mon)) &&
+           (mday > 0 && mday <= GetNumOfDaysInMonth(year, mon)) &&
            (hour < 24) && (min < 60) && (sec < 62) && (msec < 1000);
 }
 
@@ -580,7 +422,7 @@ void wxDateTime::Tm::AddMonths(int monDiff)
 
     mon = (wxDateTime::Month)(mon + monDiff);
 
-    wxASSERT_MSG( mon >= 0 && mon < MONTHS_IN_YEAR, _T("logic error") );
+    wxASSERT_MSG( mon >= 0 && mon < MONTHS_IN_YEAR, wxT("logic error") );
 
     // NB: we don't check here that the resulting date is valid, this function
     //     is private and the caller must check it if needed
@@ -605,7 +447,7 @@ void wxDateTime::Tm::AddDays(int dayDiff)
     }
 
     wxASSERT_MSG( mday > 0 && mday <= GetNumOfDaysInMonth(year, mon),
-                  _T("logic error") );
+                  wxT("logic error") );
 }
 
 // ----------------------------------------------------------------------------
@@ -619,7 +461,7 @@ wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz)
         case wxDateTime::Local:
             // get the offset from C RTL: it returns the difference GMT-local
             // while we want to have the offset _from_ GMT, hence the '-'
-            m_offset = -GetTimeZone();
+            m_offset = -wxGetTimeZone();
             break;
 
         case wxDateTime::GMT_12:
@@ -660,7 +502,7 @@ wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz)
             break;
 
         default:
-            wxFAIL_MSG( _T("unknown time zone") );
+            wxFAIL_MSG( wxT("unknown time zone") );
     }
 }
 
@@ -696,7 +538,7 @@ bool wxDateTime::IsLeapYear(int year, wxDateTime::Calendar cal)
     }
     else
     {
-        wxFAIL_MSG(_T("unknown calendar"));
+        wxFAIL_MSG(wxT("unknown calendar"));
 
         return false;
     }
@@ -724,11 +566,11 @@ int wxDateTime::GetCurrentYear(wxDateTime::Calendar cal)
             return Now().GetYear();
 
         case Julian:
-            wxFAIL_MSG(_T("TODO"));
+            wxFAIL_MSG(wxT("TODO"));
             break;
 
         default:
-            wxFAIL_MSG(_T("unsupported calendar"));
+            wxFAIL_MSG(wxT("unsupported calendar"));
             break;
     }
 
@@ -744,11 +586,11 @@ wxDateTime::Month wxDateTime::GetCurrentMonth(wxDateTime::Calendar cal)
             return Now().GetMonth();
 
         case Julian:
-            wxFAIL_MSG(_T("TODO"));
+            wxFAIL_MSG(wxT("TODO"));
             break;
 
         default:
-            wxFAIL_MSG(_T("unsupported calendar"));
+            wxFAIL_MSG(wxT("unsupported calendar"));
             break;
     }
 
@@ -771,7 +613,7 @@ wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(int year, Calendar cal)
             return IsLeapYear(year) ? 366 : 365;
 
         default:
-            wxFAIL_MSG(_T("unsupported calendar"));
+            wxFAIL_MSG(wxT("unsupported calendar"));
             break;
     }
 
@@ -783,7 +625,7 @@ wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month,
                                                      int year,
                                                      wxDateTime::Calendar cal)
 {
-    wxCHECK_MSG( month < MONTHS_IN_YEAR, 0, _T("invalid month") );
+    wxCHECK_MSG( month < MONTHS_IN_YEAR, 0, wxT("invalid month") );
 
     if ( cal == Gregorian || cal == Julian )
     {
@@ -797,76 +639,105 @@ wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month,
     }
     else
     {
-        wxFAIL_MSG(_T("unsupported calendar"));
+        wxFAIL_MSG(wxT("unsupported calendar"));
 
         return 0;
     }
 }
 
+namespace
+{
+
+// helper function used by GetEnglish/WeekDayName(): returns 0 if flags is
+// Name_Full and 1 if it is Name_Abbr or -1 if the flags is incorrect (and
+// asserts in this case)
+//
+// the return value of this function is used as an index into 2D array
+// containing full names in its first row and abbreviated ones in the 2nd one
+int NameArrayIndexFromFlag(wxDateTime::NameFlags flags)
+{
+    switch ( flags )
+    {
+        case wxDateTime::Name_Full:
+            return 0;
+
+        case wxDateTime::Name_Abbr:
+            return 1;
+
+        default:
+            wxFAIL_MSG( "unknown wxDateTime::NameFlags value" );
+    }
+
+    return -1;
+}
+
+} // anonymous namespace
+
+/* static */
+wxString wxDateTime::GetEnglishMonthName(Month month, NameFlags flags)
+{
+    wxCHECK_MSG( month != Inv_Month, wxEmptyString, "invalid month" );
+
+    static const char *const monthNames[2][MONTHS_IN_YEAR] =
+    {
+        { "January", "February", "March", "April", "May", "June",
+          "July", "August", "September", "October", "November", "December" },
+        { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }
+    };
+
+    const int idx = NameArrayIndexFromFlag(flags);
+    if ( idx == -1 )
+        return wxString();
+
+    return monthNames[idx][month];
+}
+
 /* static */
 wxString wxDateTime::GetMonthName(wxDateTime::Month month,
                                   wxDateTime::NameFlags flags)
 {
-    wxCHECK_MSG( month != Inv_Month, wxEmptyString, _T("invalid month") );
-#ifdef HAVE_STRFTIME
+#ifdef wxHAS_STRFTIME
+    wxCHECK_MSG( month != Inv_Month, wxEmptyString, wxT("invalid month") );
+
     // 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;
     InitTm(tm);
     tm.tm_mon = month;
 
-    return CallStrftime(flags == Name_Abbr ? _T("%b") : _T("%B"), &tm);
-#else // !HAVE_STRFTIME
-    wxString ret;
-    switch(month)
+    return CallStrftime(flags == Name_Abbr ? wxT("%b") : wxT("%B"), &tm);
+#else // !wxHAS_STRFTIME
+    return GetEnglishMonthName(month, flags);
+#endif // wxHAS_STRFTIME/!wxHAS_STRFTIME
+}
+
+/* static */
+wxString wxDateTime::GetEnglishWeekDayName(WeekDay wday, NameFlags flags)
+{
+    wxCHECK_MSG( wday != Inv_WeekDay, wxEmptyString, wxT("invalid weekday") );
+
+    static const char *const weekdayNames[2][DAYS_PER_WEEK] =
     {
-        case Jan:
-            ret = (flags == Name_Abbr ? wxT("Jan"): wxT("January"));
-            break;
-        case Feb:
-            ret = (flags == Name_Abbr ? wxT("Feb"): wxT("Febuary"));
-            break;
-        case Mar:
-            ret = (flags == Name_Abbr ? wxT("Mar"): wxT("March"));
-            break;
-        case Apr:
-            ret = (flags == Name_Abbr ? wxT("Apr"): wxT("April"));
-            break;
-        case May:
-            ret = (flags == Name_Abbr ? wxT("May"): wxT("May"));
-            break;
-        case Jun:
-            ret = (flags == Name_Abbr ? wxT("Jun"): wxT("June"));
-            break;
-        case Jul:
-            ret = (flags == Name_Abbr ? wxT("Jul"): wxT("July"));
-            break;
-        case Aug:
-            ret = (flags == Name_Abbr ? wxT("Aug"): wxT("August"));
-            break;
-        case Sep:
-            ret = (flags == Name_Abbr ? wxT("Sep"): wxT("September"));
-            break;
-        case Oct:
-            ret = (flags == Name_Abbr ? wxT("Oct"): wxT("October"));
-            break;
-        case Nov:
-            ret = (flags == Name_Abbr ? wxT("Nov"): wxT("November"));
-            break;
-        case Dec:
-            ret = (flags == Name_Abbr ? wxT("Dec"): wxT("December"));
-            break;
-    }
-    return ret;
-#endif // HAVE_STRFTIME/!HAVE_STRFTIME
+        { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
+          "Saturday" },
+        { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
+    };
+
+    const int idx = NameArrayIndexFromFlag(flags);
+    if ( idx == -1 )
+        return wxString();
+
+    return weekdayNames[idx][wday];
 }
 
 /* static */
 wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday,
                                     wxDateTime::NameFlags flags)
 {
-    wxCHECK_MSG( wday != Inv_WeekDay, wxEmptyString, _T("invalid weekday") );
-#ifdef HAVE_STRFTIME
+#ifdef wxHAS_STRFTIME
+    wxCHECK_MSG( wday != Inv_WeekDay, wxEmptyString, wxT("invalid weekday") );
+
     // 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!)
@@ -883,35 +754,10 @@ wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday,
     (void)mktime(&tm);
 
     // ... and call strftime()
-    return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm);
-#else // !HAVE_STRFTIME
-    wxString ret;
-    switch(wday)
-    {
-        case Sun:
-            ret = (flags == Name_Abbr ? wxT("Sun") : wxT("Sunday"));
-            break;
-        case Mon:
-            ret = (flags == Name_Abbr ? wxT("Mon") : wxT("Monday"));
-            break;
-        case Tue:
-            ret = (flags == Name_Abbr ? wxT("Tue") : wxT("Tuesday"));
-            break;
-        case Wed:
-            ret = (flags == Name_Abbr ? wxT("Wed") : wxT("Wednesday"));
-            break;
-        case Thu:
-            ret = (flags == Name_Abbr ? wxT("Thu") : wxT("Thursday"));
-            break;
-        case Fri:
-            ret = (flags == Name_Abbr ? wxT("Fri") : wxT("Friday"));
-            break;
-        case Sat:
-            ret = (flags == Name_Abbr ? wxT("Sat") : wxT("Saturday"));
-            break;
-    }
-    return ret;
-#endif // HAVE_STRFTIME/!HAVE_STRFTIME
+    return CallStrftime(flags == Name_Abbr ? wxT("%a") : wxT("%A"), &tm);
+#else // !wxHAS_STRFTIME
+    return GetEnglishWeekDayName(wday, flags);
+#endif // wxHAS_STRFTIME/!wxHAS_STRFTIME
 }
 
 /* static */
@@ -930,7 +776,7 @@ void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm)
     // assert, even though it is a perfectly legal use.
     if ( am )
     {
-        if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0)
+        if (wxStrftime(buffer, WXSIZEOF(buffer), wxT("%p"), &tm) > 0)
             *am = wxString(buffer);
         else
             *am = wxString();
@@ -938,7 +784,7 @@ void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm)
     if ( pm )
     {
         tm.tm_hour = 13;
-        if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0)
+        if (wxStrftime(buffer, WXSIZEOF(buffer), wxT("%p"), &tm) > 0)
             *pm = wxString(buffer);
         else
             *pm = wxString();
@@ -963,24 +809,24 @@ wxDateTime::Country wxDateTime::GetCountry()
         struct tm tmstruct;
         struct tm *tm = wxLocaltime_r(&t, &tmstruct);
 
-        wxString tz = CallStrftime(_T("%Z"), tm);
-        if ( tz == _T("WET") || tz == _T("WEST") )
+        wxString tz = CallStrftime(wxT("%Z"), tm);
+        if ( tz == wxT("WET") || tz == wxT("WEST") )
         {
             ms_country = UK;
         }
-        else if ( tz == _T("CET") || tz == _T("CEST") )
+        else if ( tz == wxT("CET") || tz == wxT("CEST") )
         {
             ms_country = Country_EEC;
         }
-        else if ( tz == _T("MSK") || tz == _T("MSD") )
+        else if ( tz == wxT("MSK") || tz == wxT("MSD") )
         {
             ms_country = Russia;
         }
-        else if ( tz == _T("AST") || tz == _T("ADT") ||
-                  tz == _T("EST") || tz == _T("EDT") ||
-                  tz == _T("CST") || tz == _T("CDT") ||
-                  tz == _T("MST") || tz == _T("MDT") ||
-                  tz == _T("PST") || tz == _T("PDT") )
+        else if ( tz == wxT("AST") || tz == wxT("ADT") ||
+                  tz == wxT("EST") || tz == wxT("EDT") ||
+                  tz == wxT("CST") || tz == wxT("CDT") ||
+                  tz == wxT("MST") || tz == wxT("MDT") ||
+                  tz == wxT("PST") || tz == wxT("PDT") )
         {
             ms_country = USA;
         }
@@ -1079,7 +925,7 @@ wxDateTime wxDateTime::GetBeginDST(int year, Country country)
         if ( !dt.SetToLastWeekDay(Sun, Mar, year) )
         {
             // weird...
-            wxFAIL_MSG( _T("no last Sunday in March?") );
+            wxFAIL_MSG( wxT("no last Sunday in March?") );
         }
 
         dt += wxTimeSpan::Hours(1);
@@ -1122,7 +968,7 @@ wxDateTime wxDateTime::GetBeginDST(int year, Country country)
                         if ( !dt.SetToLastWeekDay(Sun, Apr, year) )
                         {
                             // weird...
-                            wxFAIL_MSG( _T("no first Sunday in April?") );
+                            wxFAIL_MSG( wxT("no first Sunday in April?") );
                         }
                     }
                     else if ( year > 2006 )
@@ -1133,7 +979,7 @@ wxDateTime wxDateTime::GetBeginDST(int year, Country country)
                         if ( !dt.SetToWeekDay(Sun, 2, Mar, year) )
                         {
                             // weird...
-                            wxFAIL_MSG( _T("no second Sunday in March?") );
+                            wxFAIL_MSG( wxT("no second Sunday in March?") );
                         }
                     }
                     else
@@ -1141,7 +987,7 @@ wxDateTime wxDateTime::GetBeginDST(int year, Country country)
                         if ( !dt.SetToWeekDay(Sun, 1, Apr, year) )
                         {
                             // weird...
-                            wxFAIL_MSG( _T("no first Sunday in April?") );
+                            wxFAIL_MSG( wxT("no first Sunday in April?") );
                         }
                     }
 
@@ -1188,7 +1034,7 @@ wxDateTime wxDateTime::GetEndDST(int year, Country country)
         if ( !dt.SetToLastWeekDay(Sun, Oct, year) )
         {
             // weirder and weirder...
-            wxFAIL_MSG( _T("no last Sunday in October?") );
+            wxFAIL_MSG( wxT("no last Sunday in October?") );
         }
 
         dt += wxTimeSpan::Hours(1);
@@ -1221,7 +1067,7 @@ wxDateTime wxDateTime::GetEndDST(int year, Country country)
                         if ( !dt.SetToWeekDay(Sun, 1, Nov, year) )
                         {
                             // weird...
-                            wxFAIL_MSG( _T("no first Sunday in November?") );
+                            wxFAIL_MSG( wxT("no first Sunday in November?") );
                         }
                     }
                     else
@@ -1231,7 +1077,7 @@ wxDateTime wxDateTime::GetEndDST(int year, Country country)
                         if ( !dt.SetToLastWeekDay(Sun, Oct, year) )
                         {
                             // weirder and weirder...
-                            wxFAIL_MSG( _T("no last Sunday in October?") );
+                            wxFAIL_MSG( wxT("no last Sunday in October?") );
                         }
                     }
 
@@ -1272,13 +1118,13 @@ wxDateTime& wxDateTime::Set(const struct tm& tm)
         if ( tm2.tm_year == 70 && tm2.tm_mon == 0 && tm2.tm_mday == 1 )
         {
             return Set((time_t)(
-                       GetTimeZone() +
+                       wxGetTimeZone() +
                        tm2.tm_hour * MIN_PER_HOUR * SEC_PER_MIN +
                        tm2.tm_min * SEC_PER_MIN +
                        tm2.tm_sec));
         }
 
-        wxFAIL_MSG( _T("mktime() failed") );
+        wxFAIL_MSG( wxT("mktime() failed") );
 
         *this = wxInvalidDateTime;
 
@@ -1301,13 +1147,13 @@ wxDateTime& wxDateTime::Set(wxDateTime_t hour,
                       second < 62 &&
                       minute < 60 &&
                       millisec < 1000,
-                      _T("Invalid time in wxDateTime::Set()") );
+                      wxT("Invalid time in wxDateTime::Set()") );
 
     // get the current date from system
     struct tm tmstruct;
     struct tm *tm = GetTmNow(&tmstruct);
 
-    wxDATETIME_CHECK( tm, _T("wxLocaltime_r() failed") );
+    wxDATETIME_CHECK( tm, wxT("wxLocaltime_r() failed") );
 
     // make a copy so it isn't clobbered by the call to mktime() below
     struct tm tm1(*tm);
@@ -1341,12 +1187,12 @@ wxDateTime& wxDateTime::Set(wxDateTime_t day,
                       second < 62 &&
                       minute < 60 &&
                       millisec < 1000,
-                      _T("Invalid time in wxDateTime::Set()") );
+                      wxT("Invalid time in wxDateTime::Set()") );
 
     ReplaceDefaultYearMonthWithCurrent(&year, &month);
 
     wxDATETIME_CHECK( (0 < day) && (day <= GetNumberOfDays(month, year)),
-                      _T("Invalid date in wxDateTime::Set()") );
+                      wxT("Invalid date in wxDateTime::Set()") );
 
     // the range of time_t type (inclusive)
     static const int yearMinInRange = 1970;
@@ -1386,7 +1232,7 @@ wxDateTime& wxDateTime::Set(wxDateTime_t day,
         m_time *= SECONDS_PER_DAY * TIME_T_FACTOR;
 
         // JDN corresponds to GMT, we take localtime
-        Add(wxTimeSpan(hour, minute, second + GetTimeZone(), millisec));
+        Add(wxTimeSpan(hour, minute, second + wxGetTimeZone(), millisec));
     }
 
     return *this;
@@ -1485,7 +1331,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") );
+    wxCHECK_MSG( tm, ULONG_MAX, wxT("time can't be represented in DOS format") );
 
     long year = tm->tm_year;
     year -= 80;
@@ -1517,7 +1363,7 @@ unsigned long wxDateTime::GetAsDOS() const
 
 wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const
 {
-    wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
+    wxASSERT_MSG( IsValid(), wxT("invalid wxDateTime") );
 
     time_t time = GetTicks();
     if ( time != (time_t)-1 )
@@ -1525,13 +1371,13 @@ wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const
         // use C RTL functions
         struct tm tmstruct;
         tm *tm;
-        if ( tz.GetOffset() == -GetTimeZone() )
+        if ( tz.GetOffset() == -wxGetTimeZone() )
         {
             // we are working with local time
             tm = wxLocaltime_r(&time, &tmstruct);
 
             // should never happen
-            wxCHECK_MSG( tm, Tm(), _T("wxLocaltime_r() failed") );
+            wxCHECK_MSG( tm, Tm(), wxT("wxLocaltime_r() failed") );
         }
         else
         {
@@ -1546,7 +1392,7 @@ wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const
                 tm = wxGmtime_r(&time, &tmstruct);
 
                 // should never happen
-                wxCHECK_MSG( tm, Tm(), _T("wxGmtime_r() failed") );
+                wxCHECK_MSG( tm, Tm(), wxT("wxGmtime_r() failed") );
             }
             else
             {
@@ -1589,7 +1435,7 @@ wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const
 
     // CREDIT: code below is by Scott E. Lee (but bugs are mine)
 
-    wxASSERT_MSG( jdn > -2, _T("JDN out of range") );
+    wxASSERT_MSG( jdn > -2, wxT("JDN out of range") );
 
     // calculate the century
     long temp = (jdn + JDN_OFFSET) * 4 - 1;
@@ -1620,12 +1466,13 @@ wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const
     year -= 4800;
 
     // check that the algorithm gave us something reasonable
-    wxASSERT_MSG( (0 < month) && (month <= 12), _T("invalid month") );
-    wxASSERT_MSG( (1 <= day) && (day < 32), _T("invalid day") );
+    wxASSERT_MSG( (0 < month) && (month <= 12), wxT("invalid month") );
+    wxASSERT_MSG( (1 <= day) && (day < 32), wxT("invalid day") );
 
     // construct Tm from these values
     Tm tm;
     tm.year = (int)year;
+    tm.yday = (wxDateTime_t)(dayOfYear - 1); // use C convention for day number
     tm.mon = (Month)(month - 1); // algorithm yields 1 for January, not 0
     tm.mday = (wxDateTime_t)day;
     tm.msec = (wxDateTime_t)(timeOnly % 1000);
@@ -1646,7 +1493,7 @@ wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const
 
 wxDateTime& wxDateTime::SetYear(int year)
 {
-    wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
+    wxASSERT_MSG( IsValid(), wxT("invalid wxDateTime") );
 
     Tm tm(GetTm());
     tm.year = year;
@@ -1657,7 +1504,7 @@ wxDateTime& wxDateTime::SetYear(int year)
 
 wxDateTime& wxDateTime::SetMonth(Month month)
 {
-    wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
+    wxASSERT_MSG( IsValid(), wxT("invalid wxDateTime") );
 
     Tm tm(GetTm());
     tm.mon = month;
@@ -1668,7 +1515,7 @@ wxDateTime& wxDateTime::SetMonth(Month month)
 
 wxDateTime& wxDateTime::SetDay(wxDateTime_t mday)
 {
-    wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
+    wxASSERT_MSG( IsValid(), wxT("invalid wxDateTime") );
 
     Tm tm(GetTm());
     tm.mday = mday;
@@ -1679,7 +1526,7 @@ wxDateTime& wxDateTime::SetDay(wxDateTime_t mday)
 
 wxDateTime& wxDateTime::SetHour(wxDateTime_t hour)
 {
-    wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
+    wxASSERT_MSG( IsValid(), wxT("invalid wxDateTime") );
 
     Tm tm(GetTm());
     tm.hour = hour;
@@ -1690,7 +1537,7 @@ wxDateTime& wxDateTime::SetHour(wxDateTime_t hour)
 
 wxDateTime& wxDateTime::SetMinute(wxDateTime_t min)
 {
-    wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
+    wxASSERT_MSG( IsValid(), wxT("invalid wxDateTime") );
 
     Tm tm(GetTm());
     tm.min = min;
@@ -1701,7 +1548,7 @@ wxDateTime& wxDateTime::SetMinute(wxDateTime_t min)
 
 wxDateTime& wxDateTime::SetSecond(wxDateTime_t sec)
 {
-    wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
+    wxASSERT_MSG( IsValid(), wxT("invalid wxDateTime") );
 
     Tm tm(GetTm());
     tm.sec = sec;
@@ -1712,7 +1559,7 @@ wxDateTime& wxDateTime::SetSecond(wxDateTime_t sec)
 
 wxDateTime& wxDateTime::SetMillisecond(wxDateTime_t millisecond)
 {
-    wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
+    wxASSERT_MSG( IsValid(), wxT("invalid wxDateTime") );
 
     // we don't need to use GetTm() for this one
     m_time -= m_time % 1000l;
@@ -1750,7 +1597,7 @@ wxDateTime& wxDateTime::Add(const wxDateSpan& diff)
     Set(tm);
 
     wxASSERT_MSG( IsSameTime(tm),
-                  _T("Add(wxDateSpan) shouldn't modify time") );
+                  wxT("Add(wxDateSpan) shouldn't modify time") );
 
     return *this;
 }
@@ -1770,7 +1617,7 @@ wxDateTime
 wxDateTime::SetToWeekOfYear(int year, wxDateTime_t numWeek, WeekDay wd)
 {
     wxASSERT_MSG( numWeek > 0,
-                  _T("invalid week number: weeks are counted from 1") );
+                  wxT("invalid week number: weeks are counted from 1") );
 
     // Jan 4 always lies in the 1st week of the year
     wxDateTime dt(4, Jan, year);
@@ -1834,7 +1681,7 @@ wxDateTime& wxDateTime::SetToLastMonthDay(Month month,
 
 wxDateTime& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday, WeekFlags flags)
 {
-    wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") );
+    wxDATETIME_CHECK( weekday != Inv_WeekDay, wxT("invalid weekday") );
 
     int wdayDst = weekday,
         wdayThis = GetWeekDay();
@@ -1874,7 +1721,7 @@ wxDateTime& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday, WeekFlags flags)
 
 wxDateTime& wxDateTime::SetToNextWeekDay(WeekDay weekday)
 {
-    wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") );
+    wxDATETIME_CHECK( weekday != Inv_WeekDay, wxT("invalid weekday") );
 
     int diff;
     WeekDay wdayThis = GetWeekDay();
@@ -1898,7 +1745,7 @@ wxDateTime& wxDateTime::SetToNextWeekDay(WeekDay weekday)
 
 wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday)
 {
-    wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") );
+    wxDATETIME_CHECK( weekday != Inv_WeekDay, wxT("invalid weekday") );
 
     int diff;
     WeekDay wdayThis = GetWeekDay();
@@ -1925,7 +1772,7 @@ bool wxDateTime::SetToWeekDay(WeekDay weekday,
                               Month month,
                               int year)
 {
-    wxCHECK_MSG( weekday != Inv_WeekDay, false, _T("invalid weekday") );
+    wxCHECK_MSG( weekday != Inv_WeekDay, false, wxT("invalid weekday") );
 
     // we don't check explicitly that -5 <= n <= 5 because we will return false
     // anyhow in such case - but may be should still give an assert for it?
@@ -2066,23 +1913,29 @@ wxDateTime::wxDateTime_t wxDateTime::GetWeekOfMonth(wxDateTime::WeekFlags flags,
                                                     const TimeZone& tz) const
 {
     Tm tm = GetTm(tz);
-    wxDateTime dtMonthStart = wxDateTime(1, tm.mon, tm.year);
-    int nWeek = GetWeekOfYear(flags) - dtMonthStart.GetWeekOfYear(flags) + 1;
-    if ( nWeek < 0 )
+    const wxDateTime dateFirst = wxDateTime(1, tm.mon, tm.year);
+    const wxDateTime::WeekDay wdFirst = dateFirst.GetWeekDay();
+
+    if ( flags == Default_First )
     {
-        // this may happen for January when Jan, 1 is the last week of the
-        // previous year
-        nWeek += IsLeapYear(tm.year - 1) ? 53 : 52;
+        flags = GetCountry() == USA ? Sunday_First : Monday_First;
     }
 
-    return (wxDateTime::wxDateTime_t)nWeek;
+    // compute offset of dateFirst from the beginning of the week
+    int firstOffset;
+    if ( flags == Sunday_First )
+        firstOffset = wdFirst - Sun;
+    else
+        firstOffset = wdFirst == Sun ? DAYS_PER_WEEK - 1 : wdFirst - Mon;
+
+    return (wxDateTime::wxDateTime_t)((tm.mday - 1 + firstOffset)/7 + 1);
 }
 
 wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday)
 {
     int year = GetYear();
     wxDATETIME_CHECK( (0 < yday) && (yday <= GetNumberOfDays(year)),
-                      _T("invalid year day") );
+                      wxT("invalid year day") );
 
     bool isLeap = IsLeapYear(year);
     for ( Month mon = Jan; mon < Inv_Month; wxNextMonth(mon) )
@@ -2123,7 +1976,7 @@ double wxDateTime::GetRataDie() const
 int wxDateTime::IsDST(wxDateTime::Country country) const
 {
     wxCHECK_MSG( country == Country_Default, -1,
-                 _T("country support not implemented") );
+                 wxT("country support not implemented") );
 
     // use the C RTL for the dates in the standard range
     time_t timet = GetTicks();
@@ -2132,7 +1985,7 @@ int wxDateTime::IsDST(wxDateTime::Country country) const
         struct tm tmstruct;
         tm *tm = wxLocaltime_r(&timet, &tmstruct);
 
-        wxCHECK_MSG( tm, -1, _T("wxLocaltime_r() failed") );
+        wxCHECK_MSG( tm, -1, wxT("wxLocaltime_r() failed") );
 
         return tm->tm_isdst;
     }
@@ -2152,7 +2005,7 @@ int wxDateTime::IsDST(wxDateTime::Country country) const
 
 wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz, bool noDST)
 {
-    long secDiff = GetTimeZone() + tz.GetOffset();
+    long secDiff = wxGetTimeZone() + tz.GetOffset();
 
     // we need to know whether DST is or not in effect for this date unless
     // the test disabled by the caller
@@ -2167,7 +2020,7 @@ wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz, bool noDST)
 
 wxDateTime& wxDateTime::MakeFromTimezone(const TimeZone& tz, bool noDST)
 {
-    long secDiff = GetTimeZone() + tz.GetOffset();
+    long secDiff = wxGetTimeZone() + tz.GetOffset();
 
     // we need to know whether DST is or not in effect for this date unless
     // the test disabled by the caller
@@ -2275,7 +2128,7 @@ size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime& dtStart,
 {
     if ( dtStart > dtEnd )
     {
-        wxFAIL_MSG( _T("invalid date range in GetHolidaysInRange") );
+        wxFAIL_MSG( wxT("invalid date range in GetHolidaysInRange") );
 
         return 0u;
     }
@@ -2315,7 +2168,7 @@ size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime& dtStart,
 
 WXDLLIMPEXP_BASE void wxNextMonth(wxDateTime::Month& m)
 {
-    wxASSERT_MSG( m < wxDateTime::Inv_Month, _T("invalid month") );
+    wxASSERT_MSG( m < wxDateTime::Inv_Month, wxT("invalid month") );
 
     // no wrapping or the for loop above would never end!
     m = (wxDateTime::Month)(m + 1);
@@ -2323,7 +2176,7 @@ WXDLLIMPEXP_BASE void wxNextMonth(wxDateTime::Month& m)
 
 WXDLLIMPEXP_BASE void wxPrevMonth(wxDateTime::Month& m)
 {
-    wxASSERT_MSG( m < wxDateTime::Inv_Month, _T("invalid month") );
+    wxASSERT_MSG( m < wxDateTime::Inv_Month, wxT("invalid month") );
 
     m = m == wxDateTime::Jan ? wxDateTime::Inv_Month
                              : (wxDateTime::Month)(m - 1);
@@ -2331,7 +2184,7 @@ WXDLLIMPEXP_BASE void wxPrevMonth(wxDateTime::Month& m)
 
 WXDLLIMPEXP_BASE void wxNextWDay(wxDateTime::WeekDay& wd)
 {
-    wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, _T("invalid week day") );
+    wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, wxT("invalid week day") );
 
     // no wrapping or the for loop above would never end!
     wd = (wxDateTime::WeekDay)(wd + 1);
@@ -2339,7 +2192,7 @@ WXDLLIMPEXP_BASE void wxNextWDay(wxDateTime::WeekDay& wd)
 
 WXDLLIMPEXP_BASE void wxPrevWDay(wxDateTime::WeekDay& wd)
 {
-    wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, _T("invalid week day") );
+    wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, wxT("invalid week day") );
 
     wd = wd == wxDateTime::Sun ? wxDateTime::Inv_WeekDay
                                : (wxDateTime::WeekDay)(wd - 1);
@@ -2352,7 +2205,15 @@ wxDateTime& wxDateTime::SetFromMSWSysTime(const SYSTEMTIME& st)
     return Set(st.wDay,
             static_cast<wxDateTime::Month>(wxDateTime::Jan + st.wMonth - 1),
             st.wYear,
-            0, 0, 0);
+            st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
+}
+
+wxDateTime& wxDateTime::SetFromMSWSysDate(const SYSTEMTIME& st)
+{
+    return Set(st.wDay,
+            static_cast<wxDateTime::Month>(wxDateTime::Jan + st.wMonth - 1),
+            st.wYear,
+            0, 0, 0, 0);
 }
 
 void wxDateTime::GetAsMSWSysTime(SYSTEMTIME* st) const
@@ -2363,12 +2224,28 @@ void wxDateTime::GetAsMSWSysTime(SYSTEMTIME* st) const
     st->wMonth = (WXWORD)(tm.mon - wxDateTime::Jan + 1);
     st->wDay = tm.mday;
 
+    st->wDayOfWeek = 0;
+    st->wHour = tm.hour;
+    st->wMinute = tm.min;
+    st->wSecond = tm.sec;
+    st->wMilliseconds = tm.msec;
+}
+
+void wxDateTime::GetAsMSWSysDate(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