From 2f02cb8966964ea7a6f5d875ed9f3434ea05ab59 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Tue, 30 Nov 1999 21:55:00 +0000
Subject: [PATCH] wxDateTime starting to work, more tests for it and for
 threads in console sample

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4779 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/thread.tex    |   4 +-
 include/wx/datetime.h       | 390 +++++++-----------------------------
 include/wx/datetime.inl     | 328 ++++++++++++++++++++++++++++++
 include/wx/longlong.h       |  19 +-
 samples/console/console.cpp | 157 +++++++++++++--
 src/common/datetime.cpp     | 140 ++++++++++++-
 src/common/string.cpp       |   5 +-
 7 files changed, 690 insertions(+), 353 deletions(-)
 create mode 100644 include/wx/datetime.inl

diff --git a/docs/latex/wx/thread.tex b/docs/latex/wx/thread.tex
index 77c2814a59..cfdbc20879 100644
--- a/docs/latex/wx/thread.tex
+++ b/docs/latex/wx/thread.tex
@@ -105,7 +105,9 @@ threads).
 
 Delete() may be called for thread in any state: running, paused or even not yet created. Moreover,
 it must be called if \helpref{Create}{wxthreadcreate} or \helpref{Run}{wxthreadrun} fail to free
-the memory occupied by the thread object.
+the memory occupied by the thread object. However, you should not call Delete()
+on a detached thread which already terminated - doing so will probably result
+in a crash because the thread object doesn't exist any more.
 
 For detached threads Delete() will also delete the C++ thread object, but it
 will not do this for joinable ones.
diff --git a/include/wx/datetime.h b/include/wx/datetime.h
index bf7cab1fcc..ffc3bf6c13 100644
--- a/include/wx/datetime.h
+++ b/include/wx/datetime.h
@@ -10,8 +10,8 @@
 // Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
 
-#ifndef _WX_TIME_H
-#define _WX_TIME_H
+#ifndef _WX_DATETIME_H
+#define _WX_DATETIME_H
 
 #ifdef __GNUG__
     #pragma interface "datetime.h"
@@ -26,6 +26,14 @@ class WXDLLEXPORT wxDateTime;
 class WXDLLEXPORT wxTimeSpan;
 class WXDLLEXPORT wxDateSpan;
 
+// don't use inline functions in debug builds - we don't care about
+// performances and this only leads to increased rebuild time (because every
+// time an inline method is changed, all files including the header must be
+// rebuilt)
+#ifdef __WXDEBUG__
+    #define inline
+#endif // Debug
+
 /*
  * TODO Well, everything :-)
  *
@@ -350,7 +358,10 @@ public:
     static Month GetCurrentMonth(Calendar cal = Gregorian);
 
         // returns TRUE if the given year is a leap year in the given calendar
-    static bool IsLeapYear(int year, Calendar cal = Gregorian);
+    static bool IsLeapYear(int year = Inv_Year, Calendar cal = Gregorian);
+
+        // get the century (19 for 1999, 20 for 2000 and -5 for 492 BC)
+    static int GetCentury(int year = Inv_Year);
 
         // returns the number of days in this year (356 or 355 for Gregorian
         // calendar usually :-)
@@ -493,12 +504,12 @@ public:
         // of the month (see helper function SetToLastWeekDay())
     bool SetToWeekDay(WeekDay weekday,
                       int n = 1,
-                      wxDateTime_t month = Inv_Month,
+                      Month month = Inv_Month,
                       int year = Inv_Year);
 
         // sets to the last weekday in the given month, year
     inline bool SetToLastWeekDay(WeekDay weekday,
-                                 wxDateTime_t month = Inv_Month,
+                                 Month month = Inv_Month,
                                  int year = Inv_Year);
 
         // sets the date to the given day of the given week in the year,
@@ -506,8 +517,10 @@ public:
         // numWeek is > 53)
     bool SetToTheWeek(wxDateTime_t numWeek, WeekDay weekday = Mon);
 
-        // get the century (19 for 1999, 20 for 2000 and -5 for 492 BC)
-    int GetCentury() const;
+        // sets the date to the last day of the given (or current) month or the
+        // given (or current) year
+    wxDateTime& SetToLastMonthDay(Month month = Inv_Month,
+                                  int year = Inv_Year);
 
         // The definitions below were taken verbatim from
         //
@@ -582,7 +595,7 @@ public:
         // get the month day (in 1..31 range, 0 if date is invalid)
     wxDateTime_t GetDay() const { return GetTm().mday; }
         // get the day of the week (Inv_WeekDay if date is invalid)
-    WeekDay GetDayOfWeek() const { return GetTm().GetWeekDay(); }
+    WeekDay GetWeekDay() const { return GetTm().GetWeekDay(); }
         // get the hour of the day
     wxDateTime_t GetHour() const { return GetTm().hour; }
         // get the minute
@@ -701,10 +714,17 @@ public:
         // get the internal representation
     inline wxLongLong GetValue() const;
 
-private:
     // a helper function to get the current time_t
-    static inline time_t GetTimeNow() { return time((time_t *)NULL); }
+    static time_t GetTimeNow() { return time((time_t *)NULL); }
 
+    // another one to get the current time broken down
+    static struct tm *GetTmNow()
+    {
+        time_t t = GetTimeNow();
+        return localtime(&t);
+    }
+
+private:
     // the current country - as it's the same for all program objects (unless
     // it runs on a _really_ big cluster system :-), this is a static member:
     // see SetCountry() and GetCountry()
@@ -907,7 +927,25 @@ public:
     // ------------------------------------------------------------------------
 
         // this many years/months/weeks/days
-    wxDateSpan(int years, int months, int weeks, int days);
+    wxDateSpan(int years = 0, int months = 0, int weeks = 0, int days = 0)
+    {
+        m_years = years;
+        m_months = months;
+        m_weeks = weeks;
+        m_days = days;
+    }
+
+        // get an object for the given number of days
+    static wxDateSpan Days(int days) { return wxDateSpan(0, 0, 0, days); }
+
+        // get an object for the given number of weeks
+    static wxDateSpan Weeks(int weeks) { return wxDateSpan(0, 0, weeks, 0); }
+
+        // get an object for the given number of months
+    static wxDateSpan Months(int mon) { return wxDateSpan(0, mon, 0, 0); }
+
+        // get an object for the given number of years
+    static wxDateSpan Years(int years) { return wxDateSpan(years, 0, 0, 0); }
 
         // default copy ctor is ok
 
@@ -971,6 +1009,23 @@ WXDLLEXPORT_DATA(extern wxDateSpan) wxMonth;
 WXDLLEXPORT_DATA(extern wxDateSpan) wxWeek;
 WXDLLEXPORT_DATA(extern wxDateSpan) wxDay;
 
+// ============================================================================
+// inline functions implementation
+// ============================================================================
+
+// don't include inline functions definitions when we're included from anything
+// else than datetime.cpp in debug builds: this minimizes rebuilds if we change
+// some inline function and the performance doesn't matter in the debug builds.
+
+#if !defined(__WXDEBUG__) || defined(wxDEFINE_TIME_CONSTANTS)
+    #define INCLUDED_FROM_WX_DATETIME_H
+        #include "wx/datetime.inl"
+    #undef INCLUDED_FROM_WX_DATETIME_H
+#endif
+
+// if we defined it to be empty above, restore it now
+#undef inline
+
 // ============================================================================
 // binary operators
 // ============================================================================
@@ -1088,315 +1143,4 @@ inline WXDLLEXPORT wxDateSpan operator+(const wxDateSpan& rt1,
                       rt1.GetDays() + rt2.GetDays());
 }
 
-// ============================================================================
-// inline functions implementation
-// ============================================================================
-
-// ----------------------------------------------------------------------------
-// wxDateTime statics
-// ----------------------------------------------------------------------------
-
-/* static */
-wxDateTime::Country wxDateTime::GetCountry()
-{
-    return ms_country;
-}
-
-// ----------------------------------------------------------------------------
-// wxDateTime construction
-// ----------------------------------------------------------------------------
-
-// only define this once, when included from datetime.cpp
-#ifdef wxDEFINE_TIME_CONSTANTS
-    const unsigned int wxDateTime::TIME_T_FACTOR = 1000;
-#endif // wxDEFINE_TIME_CONSTANTS
-
-wxDateTime::IsInStdRange() const
-{
-    return m_time >= 0l && (m_time / (long)TIME_T_FACTOR) < LONG_MAX;
-}
-
-/* static */
-wxDateTime wxDateTime::Now()
-{
-    return wxDateTime(GetTimeNow());
-}
-
-wxDateTime& wxDateTime::Set(time_t timet)
-{
-    m_time = timet * TIME_T_FACTOR;
-
-    return *this;
-}
-
-wxDateTime& wxDateTime::SetToCurrent()
-{
-    return Set(GetTimeNow());
-}
-
-wxDateTime::wxDateTime(time_t timet)
-{
-    Set(timet);
-}
-
-wxDateTime::wxDateTime(const struct tm& tm)
-{
-    Set(tm);
-}
-
-wxDateTime::wxDateTime(const Tm& tm)
-{
-    Set(tm);
-}
-
-wxDateTime& wxDateTime::Set(const Tm& tm)
-{
-    wxASSERT_MSG( tm.IsValid(), _T("invalid broken down date/time") );
-
-    return Set(tm.mday, (Month)tm.mon, tm.year, tm.hour, tm.min, tm.sec);
-}
-
-wxDateTime::wxDateTime(wxDateTime_t hour,
-                       wxDateTime_t minute,
-                       wxDateTime_t second,
-                       wxDateTime_t millisec)
-{
-    Set(hour, minute, second, millisec);
-}
-
-wxDateTime::wxDateTime(wxDateTime_t day,
-                       Month        month,
-                       int          year,
-                       wxDateTime_t hour,
-                       wxDateTime_t minute,
-                       wxDateTime_t second,
-                       wxDateTime_t millisec)
-{
-    Set(day, month, year, hour, minute, second, millisec);
-}
-
-// ----------------------------------------------------------------------------
-// wxDateTime accessors
-// ----------------------------------------------------------------------------
-
-wxLongLong wxDateTime::GetValue() const
-{
-    wxASSERT_MSG( IsValid(), "invalid wxDateTime");
-
-    return m_time;
-}
-
-time_t wxDateTime::GetTicks() const
-{
-    wxASSERT_MSG( IsValid(), "invalid wxDateTime");
-    if ( !IsInStdRange() )
-    {
-        return (time_t)-1;
-    }
-
-    return (time_t)((m_time / (long)TIME_T_FACTOR).GetLo());
-}
-
-bool wxDateTime::SetToLastWeekDay(WeekDay weekday,
-                                  wxDateTime_t month,
-                                  int year)
-{
-    SetToWeekDay(weekday, -1, month, year);
-}
-
-// ----------------------------------------------------------------------------
-// wxDateTime comparison
-// ----------------------------------------------------------------------------
-
-bool wxDateTime::IsEqualTo(const wxDateTime& datetime) const
-{
-    wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime");
-
-    return m_time == datetime.m_time;
-}
-
-bool wxDateTime::operator==(const wxDateTime& datetime) const
-{
-    return IsEqualTo(datetime);
-}
-
-bool wxDateTime::operator!=(const wxDateTime& datetime) const
-{
-    return !IsEqualTo(datetime);
-}
-
-bool wxDateTime::IsEarlierThan(const wxDateTime& datetime) const
-{
-    wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime");
-
-    return m_time < datetime.m_time;
-}
-
-bool wxDateTime::IsLaterThan(const wxDateTime& datetime) const
-{
-    wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime");
-
-    return m_time > datetime.m_time;
-}
-
-bool wxDateTime::IsStrictlyBetween(const wxDateTime& t1,
-                                   const wxDateTime& t2) const
-{
-    // no need for assert, will be checked by the functions we call
-    return IsLaterThan(t1) && IsEarlierThan(t2);
-}
-
-bool wxDateTime::IsBetween(const wxDateTime& t1, const wxDateTime& t2) const
-{
-    // no need for assert, will be checked by the functions we call
-    return IsEqualTo(t1) || IsEqualTo(t2) || IsStrictlyBetween(t1, t2);
-}
-
-// ----------------------------------------------------------------------------
-// wxDateTime arithmetics
-// ----------------------------------------------------------------------------
-
-wxDateTime& wxDateTime::Add(const wxTimeSpan& diff)
-{
-    wxASSERT_MSG( IsValid(), "invalid wxDateTime");
-
-    m_time += diff.GetValue();
-
-    return *this;
-}
-
-wxDateTime& wxDateTime::operator+=(const wxTimeSpan& diff)
-{
-    return Add(diff);
-}
-
-wxDateTime& wxDateTime::Substract(const wxTimeSpan& diff)
-{
-    wxASSERT_MSG( IsValid(), "invalid wxDateTime");
-
-    m_time -= diff.GetValue();
-
-    return *this;
-}
-
-wxDateTime& wxDateTime::operator-=(const wxTimeSpan& diff)
-{
-    return Substract(diff);
-}
-
-wxTimeSpan wxDateTime::Substract(const wxDateTime& datetime) const
-{
-    wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime");
-
-    return wxTimeSpan(datetime.GetValue() - GetValue());
-}
-
-wxTimeSpan wxDateTime::operator-(const wxDateTime& datetime) const
-{
-    return Substract(datetime);
-}
-
-wxDateTime& wxDateTime::Substract(const wxDateSpan& diff)
-{
-    return Add(diff.Negate());
-}
-
-wxDateTime& wxDateTime::operator-=(const wxDateSpan& diff)
-{
-    return Substract(diff);
-}
-
-wxDateTime& wxDateTime::operator+=(const wxDateSpan& diff)
-{
-    return Add(diff);
-}
-
-// ----------------------------------------------------------------------------
-// wxTimeSpan
-// ----------------------------------------------------------------------------
-
-wxTimeSpan& wxTimeSpan::Add(const wxTimeSpan& diff)
-{
-    m_diff += diff.GetValue();
-
-    return *this;
-}
-
-wxTimeSpan& wxTimeSpan::Substract(const wxTimeSpan& diff)
-{
-    m_diff -= diff.GetValue();
-
-    return *this;
-}
-
-wxTimeSpan& wxTimeSpan::Multiply(int n)
-{
-    m_diff *= n;
-
-    return *this;
-}
-
-wxTimeSpan wxTimeSpan::operator*(int n) const
-{
-    wxTimeSpan result(*this);
-    result.Multiply(n);
-
-    return result;
-}
-
-wxTimeSpan wxTimeSpan::Abs() const
-{
-    return wxTimeSpan(GetValue().Abs());
-}
-
-bool wxTimeSpan::IsEqualTo(const wxTimeSpan& ts) const
-{
-    return GetValue() == ts.GetValue();
-}
-
-bool wxTimeSpan::IsLongerThan(const wxTimeSpan& ts) const
-{
-    return Abs() > ts.Abs();
-}
-
-// ----------------------------------------------------------------------------
-// wxDateSpan
-// ----------------------------------------------------------------------------
-
-wxDateSpan&
-wxDateSpan::operator+=(const wxDateSpan& other)
-{
-    m_years += other.m_years;
-    m_months += other.m_months;
-    m_weeks += other.m_weeks;
-    m_days += other.m_days;
-
-    return *this;
-}
-
-wxDateSpan& wxDateSpan::operator*=(int factor)
-{
-    m_years *= m_years;
-    m_months *= m_months;
-    m_weeks *= m_weeks;
-    m_days *= m_days;
-
-    return *this;
-}
-
-wxDateSpan wxDateSpan::Negate() const
-{
-    return wxDateSpan(-m_years, -m_months, -m_weeks, -m_days);
-}
-
-wxDateSpan& wxDateSpan::Neg()
-{
-    m_years = -m_years;
-    m_months = -m_months;
-    m_weeks = -m_weeks;
-    m_days = -m_days;
-
-    return *this;
-}
-
-#endif // _WX_TIME_H
+#endif // _WX_DATETIME_H
diff --git a/include/wx/datetime.inl b/include/wx/datetime.inl
new file mode 100644
index 0000000000..1ae112d5ad
--- /dev/null
+++ b/include/wx/datetime.inl
@@ -0,0 +1,328 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        wx/datetime.inl
+// Purpose:     definition of inline functions of wxDateTime and related
+//              classes declared in datetime.h
+// Author:      Vadim Zeitlin
+// Remarks:     having the inline functions here allows us to minimize the
+//              dependencies (and hence the rebuild time) in debug builds.
+// Modified by:
+// Created:     30.11.99
+// RCS-ID:      $Id$
+// Copyright:   (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
+// Licence:     wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_FROM_WX_DATETIME_H
+    #error "This file is only included by wx/datetime.h, don't include it manually!"
+#endif
+
+// ----------------------------------------------------------------------------
+// wxDateTime statics
+// ----------------------------------------------------------------------------
+
+/* static */
+wxDateTime::Country wxDateTime::GetCountry()
+{
+    return ms_country;
+}
+
+// ----------------------------------------------------------------------------
+// wxDateTime construction
+// ----------------------------------------------------------------------------
+
+// only define this once, when included from datetime.cpp
+#ifdef wxDEFINE_TIME_CONSTANTS
+    const unsigned int wxDateTime::TIME_T_FACTOR = 1000;
+#endif // wxDEFINE_TIME_CONSTANTS
+
+wxDateTime::IsInStdRange() const
+{
+    return m_time >= 0l && (m_time / (long)TIME_T_FACTOR) < LONG_MAX;
+}
+
+/* static */
+wxDateTime wxDateTime::Now()
+{
+    return wxDateTime(GetTimeNow());
+}
+
+wxDateTime& wxDateTime::Set(time_t timet)
+{
+    // assign first to avoid long multiplication overflow!
+    m_time = timet;
+    m_time *= TIME_T_FACTOR;
+
+    return *this;
+}
+
+wxDateTime& wxDateTime::SetToCurrent()
+{
+    return Set(GetTimeNow());
+}
+
+wxDateTime::wxDateTime(time_t timet)
+{
+    Set(timet);
+}
+
+wxDateTime::wxDateTime(const struct tm& tm)
+{
+    Set(tm);
+}
+
+wxDateTime::wxDateTime(const Tm& tm)
+{
+    Set(tm);
+}
+
+wxDateTime& wxDateTime::Set(const Tm& tm)
+{
+    wxASSERT_MSG( tm.IsValid(), _T("invalid broken down date/time") );
+
+    return Set(tm.mday, (Month)tm.mon, tm.year, tm.hour, tm.min, tm.sec);
+}
+
+wxDateTime::wxDateTime(wxDateTime_t hour,
+                       wxDateTime_t minute,
+                       wxDateTime_t second,
+                       wxDateTime_t millisec)
+{
+    Set(hour, minute, second, millisec);
+}
+
+wxDateTime::wxDateTime(wxDateTime_t day,
+                       Month        month,
+                       int          year,
+                       wxDateTime_t hour,
+                       wxDateTime_t minute,
+                       wxDateTime_t second,
+                       wxDateTime_t millisec)
+{
+    Set(day, month, year, hour, minute, second, millisec);
+}
+
+// ----------------------------------------------------------------------------
+// wxDateTime accessors
+// ----------------------------------------------------------------------------
+
+wxLongLong wxDateTime::GetValue() const
+{
+    wxASSERT_MSG( IsValid(), "invalid wxDateTime");
+
+    return m_time;
+}
+
+time_t wxDateTime::GetTicks() const
+{
+    wxASSERT_MSG( IsValid(), "invalid wxDateTime");
+    if ( !IsInStdRange() )
+    {
+        return (time_t)-1;
+    }
+
+    return (time_t)((m_time / (long)TIME_T_FACTOR).GetLo());
+}
+
+bool wxDateTime::SetToLastWeekDay(WeekDay weekday,
+                                  Month month,
+                                  int year)
+{
+    return SetToWeekDay(weekday, -1, month, year);
+}
+
+// ----------------------------------------------------------------------------
+// wxDateTime comparison
+// ----------------------------------------------------------------------------
+
+bool wxDateTime::IsEqualTo(const wxDateTime& datetime) const
+{
+    wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime");
+
+    return m_time == datetime.m_time;
+}
+
+bool wxDateTime::operator==(const wxDateTime& datetime) const
+{
+    return IsEqualTo(datetime);
+}
+
+bool wxDateTime::operator!=(const wxDateTime& datetime) const
+{
+    return !IsEqualTo(datetime);
+}
+
+bool wxDateTime::IsEarlierThan(const wxDateTime& datetime) const
+{
+    wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime");
+
+    return m_time < datetime.m_time;
+}
+
+bool wxDateTime::IsLaterThan(const wxDateTime& datetime) const
+{
+    wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime");
+
+    return m_time > datetime.m_time;
+}
+
+bool wxDateTime::IsStrictlyBetween(const wxDateTime& t1,
+                                   const wxDateTime& t2) const
+{
+    // no need for assert, will be checked by the functions we call
+    return IsLaterThan(t1) && IsEarlierThan(t2);
+}
+
+bool wxDateTime::IsBetween(const wxDateTime& t1, const wxDateTime& t2) const
+{
+    // no need for assert, will be checked by the functions we call
+    return IsEqualTo(t1) || IsEqualTo(t2) || IsStrictlyBetween(t1, t2);
+}
+
+// ----------------------------------------------------------------------------
+// wxDateTime arithmetics
+// ----------------------------------------------------------------------------
+
+wxDateTime& wxDateTime::Add(const wxTimeSpan& diff)
+{
+    wxASSERT_MSG( IsValid(), "invalid wxDateTime");
+
+    m_time += diff.GetValue();
+
+    return *this;
+}
+
+wxDateTime& wxDateTime::operator+=(const wxTimeSpan& diff)
+{
+    return Add(diff);
+}
+
+wxDateTime& wxDateTime::Substract(const wxTimeSpan& diff)
+{
+    wxASSERT_MSG( IsValid(), "invalid wxDateTime");
+
+    m_time -= diff.GetValue();
+
+    return *this;
+}
+
+wxDateTime& wxDateTime::operator-=(const wxTimeSpan& diff)
+{
+    return Substract(diff);
+}
+
+wxTimeSpan wxDateTime::Substract(const wxDateTime& datetime) const
+{
+    wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime");
+
+    return wxTimeSpan(datetime.GetValue() - GetValue());
+}
+
+wxTimeSpan wxDateTime::operator-(const wxDateTime& datetime) const
+{
+    return Substract(datetime);
+}
+
+wxDateTime& wxDateTime::Substract(const wxDateSpan& diff)
+{
+    return Add(diff.Negate());
+}
+
+wxDateTime& wxDateTime::operator-=(const wxDateSpan& diff)
+{
+    return Substract(diff);
+}
+
+wxDateTime& wxDateTime::operator+=(const wxDateSpan& diff)
+{
+    return Add(diff);
+}
+
+// ----------------------------------------------------------------------------
+// wxTimeSpan
+// ----------------------------------------------------------------------------
+
+wxTimeSpan& wxTimeSpan::Add(const wxTimeSpan& diff)
+{
+    m_diff += diff.GetValue();
+
+    return *this;
+}
+
+wxTimeSpan& wxTimeSpan::Substract(const wxTimeSpan& diff)
+{
+    m_diff -= diff.GetValue();
+
+    return *this;
+}
+
+wxTimeSpan& wxTimeSpan::Multiply(int n)
+{
+    m_diff *= n;
+
+    return *this;
+}
+
+wxTimeSpan wxTimeSpan::operator*(int n) const
+{
+    wxTimeSpan result(*this);
+    result.Multiply(n);
+
+    return result;
+}
+
+wxTimeSpan wxTimeSpan::Abs() const
+{
+    return wxTimeSpan(GetValue().Abs());
+}
+
+bool wxTimeSpan::IsEqualTo(const wxTimeSpan& ts) const
+{
+    return GetValue() == ts.GetValue();
+}
+
+bool wxTimeSpan::IsLongerThan(const wxTimeSpan& ts) const
+{
+    return GetValue().Abs() > ts.GetValue().Abs();
+}
+
+// ----------------------------------------------------------------------------
+// wxDateSpan
+// ----------------------------------------------------------------------------
+
+wxDateSpan&
+wxDateSpan::operator+=(const wxDateSpan& other)
+{
+    m_years += other.m_years;
+    m_months += other.m_months;
+    m_weeks += other.m_weeks;
+    m_days += other.m_days;
+
+    return *this;
+}
+
+wxDateSpan& wxDateSpan::operator*=(int factor)
+{
+    m_years *= m_years;
+    m_months *= m_months;
+    m_weeks *= m_weeks;
+    m_days *= m_days;
+
+    return *this;
+}
+
+wxDateSpan wxDateSpan::Negate() const
+{
+    return wxDateSpan(-m_years, -m_months, -m_weeks, -m_days);
+}
+
+wxDateSpan& wxDateSpan::Neg()
+{
+    m_years = -m_years;
+    m_months = -m_months;
+    m_weeks = -m_weeks;
+    m_days = -m_days;
+
+    return *this;
+}
+
+
diff --git a/include/wx/longlong.h b/include/wx/longlong.h
index cedac4f92b..c9b582b7a3 100644
--- a/include/wx/longlong.h
+++ b/include/wx/longlong.h
@@ -24,11 +24,12 @@
 // ----------------------------------------------------------------------------
 
 // to avoid compilation problems on 64bit machines with ambiguous method calls
-// we will need this
+// we will need to define this
 #undef wxLongLongIsLong
 
 // NB: we #define and not typedef wxLongLong_t because we want to be able to
-//     use 'unsigned wxLongLong_t' as well
+//     use 'unsigned wxLongLong_t' as well and because we use "#ifdef
+//     wxLongLong_t" below
 #if defined(SIZEOF_LONG) && (SIZEOF_LONG == 8)
     #define wxLongLong_t long
     #define wxLongLongIsLong
@@ -98,7 +99,7 @@ public:
         m_ll |= (wxLongLong_t) lo;
     }
 
-    // default copy ctor is ok in both cases
+    // default copy ctor is ok
 
     // no dtor
 
@@ -112,10 +113,10 @@ public:
     // accessors
         // get high part
     long GetHi() const
-        { return (long)((m_ll & 0xFFFFFFFF00000000l) >> 32); }
+        { return (long)(m_ll >> 32); }
         // get low part
     unsigned long GetLo() const
-        { return (unsigned long) (m_ll & 0x00000000FFFFFFFFl); }
+        { return (unsigned long)m_ll; }
 
         // get absolute value
     wxLongLongNative& Abs() { if ( m_ll < 0 ) m_ll = -m_ll; return *this; }
@@ -123,6 +124,8 @@ public:
         // convert to native long long
     wxLongLong_t GetValue() const { return m_ll; }
 
+    // don't provide implicit conversion to wxLongLong_t or we will have an
+    // ambiguity for all arithmetic operations
     //operator wxLongLong_t() const { return m_ll; }
 
     // operations
@@ -200,8 +203,12 @@ public:
     // multiplication/division
     wxLongLongNative operator*(const wxLongLongNative& ll) const
         { return wxLongLongNative(m_ll * ll.m_ll); }
+    wxLongLongNative operator*(long l) const
+        { return wxLongLongNative(m_ll * l); }
     wxLongLongNative& operator*=(const wxLongLongNative& ll)
         { m_ll *= ll.m_ll; return *this; }
+    wxLongLongNative& operator*=(long l)
+        { m_ll *= l; return *this; }
 
     wxLongLongNative operator/(const wxLongLongNative& ll) const
         { return wxLongLongNative(m_ll / ll.m_ll); }
@@ -209,6 +216,8 @@ public:
         { return wxLongLongNative(m_ll / l); }
     wxLongLongNative& operator/=(const wxLongLongNative& ll)
         { m_ll /= ll.m_ll; return *this; }
+    wxLongLongNative& operator/=(long l)
+        { m_ll /= l; return *this; }
 
     wxLongLongNative operator%(const wxLongLongNative& ll) const
         { return wxLongLongNative(m_ll % ll.m_ll); }
diff --git a/samples/console/console.cpp b/samples/console/console.cpp
index f72458ddd5..f83df94ab8 100644
--- a/samples/console/console.cpp
+++ b/samples/console/console.cpp
@@ -32,8 +32,8 @@
 //#define TEST_ARRAYS
 //#define TEST_LOG
 //#define TEST_STRINGS
-#define TEST_THREADS
-//#define TEST_TIME
+//#define TEST_THREADS
+#define TEST_TIME
 //#define TEST_LONGLONG
 
 // ============================================================================
@@ -93,9 +93,26 @@ static void TestSpeed()
 
 static void TestDivision()
 {
-    wxLongLong ll = 0x38417388; // some number < LONG_MAX
+    #define MAKE_LL(x1, x2, x3, x4) wxLongLong((x1 << 16) | x2, (x3 << 16) | x3)
 
-    wxASSERT( (ll / 1000l)*1000l == ll );
+    // seed pseudo random generator
+    //srand((unsigned)time(NULL));
+
+    size_t nTested = 0;
+    for ( size_t n = 0; n < 10000; n++ )
+    {
+        // get a random wxLongLong (shifting by 12 the MSB ensures that the
+        // multiplication will not overflow)
+        wxLongLong ll = MAKE_LL((rand() >> 12), rand(), rand(), rand());
+
+        wxASSERT( (ll * 1000l)/1000l == ll );
+
+        nTested++;
+    }
+
+    printf("\n*** Tested %u divisions/multiplications: ok\n", nTested);
+
+    #undef MAKE_LL
 }
 
 #endif // TEST_LONGLONG
@@ -108,6 +125,60 @@ static void TestDivision()
 
 #include <wx/datetime.h>
 
+// this test miscellaneous static wxDateTime functions
+static void TestTimeStatic()
+{
+    puts("\n*** wxDateTime static methods test ***");
+
+    // some info about the current date
+    int year = wxDateTime::GetCurrentYear();
+    printf("Current year %d is %sa leap one and has %d days.\n",
+           year,
+           wxDateTime::IsLeapYear(year) ? "" : "not ",
+           wxDateTime::GetNumberOfDays(year));
+
+    wxDateTime::Month month = wxDateTime::GetCurrentMonth();
+    printf("Current month is '%s' ('%s') and it has %d days\n",
+           wxDateTime::GetMonthName(month, TRUE).c_str(),
+           wxDateTime::GetMonthName(month).c_str(),
+           wxDateTime::GetNumberOfDays(month));
+
+    // leap year logic
+    static const nYears = 5;
+    static const int years[2][nYears] =
+    {
+        // first line: the years to test
+        { 1990, 1976, 2000, 2030, 1984, },
+
+        // second line: TRUE if leap, FALSE otherwise
+        { FALSE, TRUE, TRUE, FALSE, TRUE }
+    };
+
+    for ( size_t n = 0; n < nYears; n++ )
+    {
+        int year = years[0][n];
+        bool should = years[1][n] != 0;
+
+        printf("Year %d is %sa leap year (should be: %s)\n",
+               year,
+               wxDateTime::IsLeapYear(year) ? "" : "not ",
+               should ? "yes" : "no");
+
+        wxASSERT( should == wxDateTime::IsLeapYear(year) );
+    }
+}
+
+// test constructing wxDateTime objects
+static void TestTimeSet()
+{
+    puts("\n*** wxDateTime construction test ***");
+
+    printf("Current time:\t%s\n", wxDateTime::Now().Format().c_str());
+    printf("Unix epoch:\t%s\n", wxDateTime((time_t)0).Format().c_str());
+    printf("Today noon:\t%s\n", wxDateTime(12, 0).Format().c_str());
+    printf("May 29, 1976:\t%s\n", wxDateTime(29, wxDateTime::May, 1976).Format().c_str());
+}
+
 #endif // TEST_TIME
 
 // ----------------------------------------------------------------------------
@@ -200,7 +271,7 @@ void MyDetachedThread::OnExit()
 
 void TestDetachedThreads()
 {
-    puts("*** Testing detached threads ***");
+    puts("\n*** Testing detached threads ***");
 
     static const size_t nThreads = 3;
     MyDetachedThread *threads[nThreads];
@@ -226,7 +297,7 @@ void TestDetachedThreads()
 
 void TestJoinableThreads()
 {
-    puts("*** Testing a joinable thread (a loooong calculation...) ***");
+    puts("\n*** Testing a joinable thread (a loooong calculation...) ***");
 
     // calc 10! in the background
     MyJoinableThread thread(10);
@@ -238,7 +309,9 @@ void TestJoinableThreads()
 
 void TestThreadSuspend()
 {
-    MyDetachedThread *thread = new MyDetachedThread(30, 'X');
+    puts("\n*** Testing thread suspend/resume functions ***");
+
+    MyDetachedThread *thread = new MyDetachedThread(15, 'X');
 
     thread->Run();
 
@@ -271,6 +344,56 @@ void TestThreadSuspend()
     puts("");
 }
 
+void TestThreadDelete()
+{
+    // As above, using Sleep() is only for testing here - we must use some
+    // synchronisation object instead to ensure that the thread is still
+    // running when we delete it - deleting a detached thread which already
+    // terminated will lead to a crash!
+
+    puts("\n*** Testing thread delete function ***");
+
+    MyDetachedThread *thread1 = new MyDetachedThread(30, 'Y');
+
+    thread1->Run();
+
+    wxThread::Sleep(300);
+
+    thread1->Delete();
+
+    puts("\nDeleted a running thread.");
+
+    MyDetachedThread *thread2 = new MyDetachedThread(30, 'Z');
+
+    thread2->Run();
+
+    wxThread::Sleep(300);
+
+    thread2->Pause();
+
+    thread2->Delete();
+
+    puts("\nDeleted a sleeping thread.");
+
+    MyJoinableThread *thread3 = new MyJoinableThread(20);
+    thread3->Run();
+
+    thread3->Delete();
+
+    puts("\nDeleted a joinable thread.");
+
+    MyJoinableThread *thread4 = new MyJoinableThread(2);
+    thread4->Run();
+
+    wxThread::Sleep(300);
+
+    thread4->Delete();
+
+    puts("\nDeleted a joinable thread which already terminated.");
+
+    puts("");
+}
+
 #endif // TEST_THREADS
 
 // ----------------------------------------------------------------------------
@@ -421,12 +544,15 @@ int main(int argc, char **argv)
     if ( argc > 1 && argv[1][0] == 't' )
         wxLog::AddTraceMask("thread");
 
-    TestThreadSuspend();
     if ( 0 )
-    {
-    TestDetachedThreads();
-    TestJoinableThreads();
-    }
+        TestDetachedThreads();
+    if ( 0 )
+        TestJoinableThreads();
+    if ( 0 )
+        TestThreadSuspend();
+    if ( 1 )
+        TestThreadDelete();
+
 #endif // TEST_THREADS
 
 #ifdef TEST_LONGLONG
@@ -437,11 +563,8 @@ int main(int argc, char **argv)
 #endif // TEST_LONGLONG
 
 #ifdef TEST_TIME
-    wxDateTime time = wxDateTime::Now();
-    printf("Current time: '%s', current year %u is %sa leap one",
-           time.Format().c_str(),
-           time.GetYear(),
-           wxDateTime::IsLeapYear(time.GetYear()) ? "" : "not");
+    TestTimeStatic();
+    TestTimeSet();
 #endif // TEST_TIME
 
     wxUninitialize();
diff --git a/src/common/datetime.cpp b/src/common/datetime.cpp
index f254ddc7e5..46f65d001f 100644
--- a/src/common/datetime.cpp
+++ b/src/common/datetime.cpp
@@ -54,6 +54,7 @@ static wxDateTime::wxDateTime_t gs_daysInMonth[2][12] =
 // private functions
 // ----------------------------------------------------------------------------
 
+// this function is a wrapper around strftime(3)
 static wxString CallStrftime(const wxChar *format, const tm* tm)
 {
     wxChar buf[1024];
@@ -66,6 +67,28 @@ static wxString CallStrftime(const wxChar *format, const tm* tm)
     return wxString(buf);
 }
 
+// if year and/or month have invalid values, replace them with the current ones
+static void ReplaceDefaultYearMonthWithCurrent(int *year,
+                                               wxDateTime::Month *month)
+{
+    struct tm *tmNow = NULL;
+
+    if ( *year == wxDateTime::Inv_Year )
+    {
+        tmNow = wxDateTime::GetTmNow();
+
+        *year = 1900 + tmNow->tm_year;
+    }
+
+    if ( *month == wxDateTime::Inv_Month )
+    {
+        if ( !tmNow )
+            tmNow = wxDateTime::GetTmNow();
+
+        *month = (wxDateTime::Month)tmNow->tm_mon;
+    }
+}
+
 // ============================================================================
 // implementation of wxDateTime
 // ============================================================================
@@ -122,6 +145,9 @@ void wxDateTime::Tm::ComputeWeekDay()
 /* static */
 bool wxDateTime::IsLeapYear(int year, wxDateTime::Calendar cal)
 {
+    if ( year == Inv_Year )
+        year = GetCurrentYear();
+
     if ( cal == Gregorian )
     {
         // in Gregorian calendar leap years are those divisible by 4 except
@@ -197,6 +223,30 @@ wxDateTime::Month wxDateTime::GetCurrentMonth(wxDateTime::Calendar cal)
     return Inv_Month;
 }
 
+/* static */
+wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(int year, Calendar cal)
+{
+    if ( year == Inv_Year )
+    {
+        // take the current year if none given
+        year = GetCurrentYear();
+    }
+
+    switch ( cal )
+    {
+        case Gregorian:
+        case Julian:
+            return IsLeapYear(year) ? 366 : 365;
+            break;
+
+        default:
+            wxFAIL_MSG(_T("unsupported calendar"));
+            break;
+    }
+
+    return 0;
+}
+
 /* static */
 wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month,
                                                      int year,
@@ -310,12 +360,9 @@ wxDateTime& wxDateTime::Set(wxDateTime_t day,
                  ms_InvDateTime,
                  _T("Invalid time in wxDateTime::Set()") );
 
-    if ( year == Inv_Year )
-        year = GetCurrentYear();
-    if ( month == Inv_Month )
-        month = GetCurrentMonth();
+    ReplaceDefaultYearMonthWithCurrent(&year, &month);
 
-    wxCHECK_MSG( day < GetNumberOfDays(month, year), ms_InvDateTime,
+    wxCHECK_MSG( day <= GetNumberOfDays(month, year), ms_InvDateTime,
                  _T("Invalid date in wxDateTime::Set()") );
 
     // the range of time_t type (inclusive)
@@ -324,7 +371,7 @@ wxDateTime& wxDateTime::Set(wxDateTime_t day,
 
     // test only the year instead of testing for the exact end of the Unix
     // time_t range - it doesn't bring anything to do more precise checks
-    if ( year >= yearMaxInRange && year <= yearMaxInRange )
+    if ( year >= yearMinInRange && year <= yearMaxInRange )
     {
         // use the standard library version if the date is in range - this is
         // probably more efficient than our code
@@ -473,6 +520,87 @@ wxDateTime& wxDateTime::Add(const wxDateSpan& diff)
     return *this;
 }
 
+// ----------------------------------------------------------------------------
+// Weekday and monthday stuff
+// ----------------------------------------------------------------------------
+
+wxDateTime& wxDateTime::SetToLastMonthDay(Month month,
+                                          int year)
+{
+    // take the current month/year if none specified
+    ReplaceDefaultYearMonthWithCurrent(&year, &month);
+
+    return Set(gs_daysInMonth[IsLeapYear(year)][month], month, year);
+}
+
+bool wxDateTime::SetToWeekDay(WeekDay weekday,
+                              int n,
+                              Month month,
+                              int year)
+{
+    wxCHECK_MSG( weekday != Inv_WeekDay, FALSE, _T("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?
+
+    // take the current month/year if none specified
+    ReplaceDefaultYearMonthWithCurrent(&year, &month);
+
+    wxDateTime dt;
+
+    // TODO this probably could be optimised somehow...
+
+    if ( n > 0 )
+    {
+        // get the first day of the month
+        dt.Set(1, month, year);
+
+        // get its wday
+        WeekDay wdayFirst = dt.GetWeekDay();
+
+        // go to the first weekday of the month
+        int diff = weekday - wdayFirst;
+        if ( diff < 0 )
+            diff += 7;
+
+        // add advance n-1 weeks more
+        diff += 7*(n - 1);
+
+        dt -= wxDateSpan::Days(diff);
+    }
+    else
+    {
+        // get the last day of the month
+        dt.SetToLastMonthDay(month, year);
+
+        // get its wday
+        WeekDay wdayLast = dt.GetWeekDay();
+
+        // go to the last weekday of the month
+        int diff = wdayLast - weekday;
+        if ( diff < 0 )
+            diff += 7;
+
+        // and rewind n-1 weeks from there
+        diff += 7*(n - 1);
+
+        dt -= wxDateSpan::Days(diff);
+    }
+
+    // check that it is still in the same month
+    if ( dt.GetMonth() == month )
+    {
+        *this = dt;
+
+        return TRUE;
+    }
+    else
+    {
+        // no such day in this month
+        return FALSE;
+    }
+}
+
 // ----------------------------------------------------------------------------
 // wxDateTime to/from text representations
 // ----------------------------------------------------------------------------
diff --git a/src/common/string.cpp b/src/common/string.cpp
index 280e105f25..fe8480cd45 100644
--- a/src/common/string.cpp
+++ b/src/common/string.cpp
@@ -203,7 +203,10 @@ extern int WXDLLEXPORT wxVsnprintf(wxChar *buf, size_t len,
     // vsnprintf() will not terminate the string with '\0' if there is not
     // enough place, but we want the string to always be NUL terminated
     int rc = wxVsnprintfA(buf, len - 1, format, argptr);
-    buf[len] = 0;
+    if ( rc == -1 )
+    {
+        buf[len] = 0;
+    }
 
     return rc;
 #endif // Unicode/ANSI
-- 
2.45.2

