]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/time.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / time.cpp
index 53d034ccf1147ea097baa4dc091a1c0e6fc05b44..5b2460ca6910797294e6b695428b9a80c510e656 100644 (file)
-/////////////////////////////////////////////////////////////////////////////
-// Name:        time.cpp
-// Purpose:     wxTime class, from NIHCL
-// Author:      Julian Smart, after K. E. Gorlen
-// Modified by:
-// Created:     04/01/98
-// RCS-ID:      $Id$
-// Copyright:   (c) Julian Smart and Markus Holzem
-// Licence:     wxWindows license
-/////////////////////////////////////////////////////////////////////////////
-
-#ifdef __GNUG__
-#pragma implementation "time.h"
-#endif
-
-/*
-Provides an object that represents a Time, stored as the number of
-seconds since January 1, 1901, GMT.
-*/
-
-// For compilers that support precompilation, includes "wx.h".
+///////////////////////////////////////////////////////////////////////////////
+// Name:        src/common/time.cpp
+// Purpose:     Implementation of time-related functions.
+// Author:      Vadim Zeitlin
+// Created:     2011-11-26
+// RCS-ID:      $Id: wxhead.cpp,v 1.11 2010-04-22 12:44:51 zeitlin Exp $
+// Copyright:   (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+// for compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-#pragma hdrstop
+    #pragma hdrstop
 #endif
 
-#include "wx/setup.h"
-
-#if wxUSE_TIMEDATE
-
 #include "wx/time.h"
-#include "wx/date.h"
-#include "wx/utils.h"
-#include "wx/intl.h"
-
-#include "wx/ioswrap.h"
 
-#if wxUSE_IOSTREAMH && wxUSE_STD_IOSTREAM
-    #include <iomanip.h>
-#else
-    #include <iomanip>
+#ifndef WX_PRECOMP
+    #ifdef __WINDOWS__
+        #include "wx/msw/wrapwin.h"
+    #endif
+    #include "wx/intl.h"
+    #include "wx/log.h"
 #endif
 
-#include <string.h>
-
-#if !USE_SHARED_LIBRARY
-IMPLEMENT_DYNAMIC_CLASS(wxTime, wxObject)
+#ifndef WX_GMTOFF_IN_TM
+    // Define it for some systems which don't (always) use configure but are
+    // known to have tm_gmtoff field.
+    #if defined(__DARWIN__)
+        #define WX_GMTOFF_IN_TM
+    #endif
 #endif
 
+#if defined(__VISAGECPP__) && !defined(HAVE_FTIME)
+    #define HAVE_FTIME
+#  if __IBMCPP__ >= 400
+    #  define ftime(x) _ftime(x)
+#  endif
+#endif
 
-extern bool wxGetLocalTime(long *timeZone, int *dstObserved);
-extern long wxGetCurrentTime(void);
-
-static long TIME_ZONE;          /* seconds west of GMT */
-static int DST_OBSERVED;        /* flags U.S. daylight saving time observed */
-
-static bool wxTimeInitialized = FALSE;
-
-wxTime::tFormat    wxTime::Format    = wxTime::wx12h;
-wxTime::tPrecision  wxTime::Precision  = wxTime::wxStdMinSec;
-
-static const unsigned long seconds_in_day = 24*60*60L;
-static const wxDate refDate(1,1,1901);
-// static const wxDate maxDate(49709L);      /* ((2**32)-1)/seconds_in_day -1 */
-
-wxTime wxTime::GetLocalTime(const wxDate& date, hourTy h, minuteTy m, secondTy s)
-/*
-      Return a local wxTime for the specified Standard Time date, hour, minute,
-      and second.
-*/
-{
-  if (!wxTimeInitialized)
-  {
-   wxGetLocalTime(&TIME_ZONE, &DST_OBSERVED);
-   wxTimeInitialized = TRUE;
-  }
-/*
-      if (!date.IsBetween(refDate,maxDate))
-           setError(NIHCL_DATERANGE,DEFAULT,
-                date.dayOfMonth(),date.nameOfMonth(),date.year());
-*/
-  // The following line causes an error in GCC 2.1
-//   long daysBetween = date-refDate;
-  // ... but this seems to get round it.
-  wxDate tmp1(date);
-  wxDate tmp2(refDate);
-  long daysBetween = tmp1 - tmp2;
-
-  return wxTime(seconds_in_day*daysBetween + 60*60L*h + 60*m + s);
-}
-
-wxTime::wxTime()
-/*
-      Construct a wxTime for this instant.
-*/
-{
-  if (!wxTimeInitialized)
-  {
-   wxGetLocalTime(&TIME_ZONE, &DST_OBSERVED);
-   wxTimeInitialized = TRUE;
-  }
-  sec = wxGetCurrentTime();
-#ifdef __SALFORDC__
-  sec += (unsigned long) 2177452800;     /* seconds from 1/1/01 to 1/1/70 */
+#ifndef __WXWINCE__
+#include <time.h>
 #else
-  sec += 2177452800UL;     /* seconds from 1/1/01 to 1/1/70 */
+#include "wx/msw/private.h"
+#include "wx/msw/wince/time.h"
 #endif
-}
-
-wxTime::wxTime(hourTy h, minuteTy m, secondTy s, bool dst)
-/*
-      Construct a wxTime for today at the specified (local) hour, minute, and
-      second.
-*/
-{
-  if (!wxTimeInitialized)
-  {
-   wxGetLocalTime(&TIME_ZONE, &DST_OBSERVED);
-   wxTimeInitialized = TRUE;
-  }
-
-  sec = wxTime(wxDate(),h,m,s,dst).sec;
-}
-
 
-wxTime::wxTime(const wxDate& date, hourTy h, minuteTy m, secondTy s, bool dst)
-/*
-        Construct a wxTime for the specified (local) Date, hour, minute, and
-        second.
-*/
-{
-  if (!wxTimeInitialized)
-  {
-    wxGetLocalTime(&TIME_ZONE, &DST_OBSERVED);
-   wxTimeInitialized = TRUE;
-  }
-  sec = GetLocalTime(date,h,m,s).sec-3600;
-  if (IsDST())
-  {
-    sec += 3600;
-    if (IsDST() || dst) sec -= 3600;
-  }
-  else
-  {
-    sec += 3600;
-/*
-                if (IsDST()) setError(NIHCL_BADTIME,DEFAULT,
-                date.dayOfMonth(),date.nameOfMonth(),date.year(),
-                h,m,s,(dst?_("DST("):""));
-*/
-  }
-  sec += TIME_ZONE;                               // adjust to GMT
-}
 
-#ifndef __SALFORDC__
-wxTime::operator wxDate() const
-/*
-      Convert a wxTime to a local wxDate
-*/
-{
-//      return wxDate((int)(GetLocalTime().sec/seconds_in_day));     4.2 cc bug
-      long daycount = (long)(GetLocalTime().sec/seconds_in_day);
+#if !defined(__WXMAC__) && !defined(__WXWINCE__)
+    #include <sys/types.h>      // for time_t
+#endif
 
-        wxDate date(1,1,1901);
-        date += daycount;
-        return date;
-}
+#if defined(HAVE_GETTIMEOFDAY)
+    #include <sys/time.h>
+    #include <unistd.h>
+#elif defined(HAVE_FTIME)
+    #include <sys/timeb.h>
 #endif
 
-bool wxTime::IsBetween(const wxTime& a, const wxTime& b) const
-{
-        return *this >= a && *this <= b;
-}
+#if defined(__DJGPP__) || defined(__WINE__)
+    #include <sys/timeb.h>
+    #include <values.h>
+#endif
 
-hourTy wxTime::GetHour() const
-/*
-      Return the hour of this wxTime in local time; i.e., adjust for
-        time zone and Daylight Savings Time.
-*/
+namespace
 {
-      return GetLocalTime().GetHourGMT();
-}
 
-hourTy wxTime::GetHourGMT() const
-/*
-        Return the hour of this Time in GMT.
-*/
-{
-      return (hourTy)((sec % 86400) / 3600);
-}
+const int MILLISECONDS_PER_SECOND = 1000;
+const int MICROSECONDS_PER_MILLISECOND = 1000;
+const int MICROSECONDS_PER_SECOND = 1000*1000;
 
-wxTime wxTime::GetBeginDST(unsigned year)
-/*
-      Return the local Standard Time at which Daylight Savings Time
-        begins in the specified year.
-*/
-{
-        // Previous Sunday
-        wxTime DSTtime(GetLocalTime(wxDate(3,31,year).Previous(1)+7,2));
-        if (year<=1986) {
-                // Previous Sunday
-           DSTtime = GetLocalTime(wxDate(4,30,year).Previous(1),2);
-           if (year==1974) DSTtime = GetLocalTime(wxDate(1,6,1974),2);
-                if (year==1975) DSTtime = GetLocalTime(wxDate(2,23,1975),2);
-        }
-        return DSTtime;
-}
+} // anonymous namespace
 
-wxTime wxTime::GetEndDST(unsigned year)
-/*
-        Return the local Standard Time at which Daylight Savings Time
-        ends in the specified year.
-*/
-{
-      wxTime STDtime(GetLocalTime(wxDate(10,31,year).Previous(1),2-1));
-      return STDtime;
-}
+// ============================================================================
+// implementation
+// ============================================================================
 
-bool wxTime::IsDST() const
-/*
-        Return TRUE if this local Standard Time should be adjusted
-        for Daylight Savings Time.
-*/
-{
-        long daycount = (long)(sec/seconds_in_day);
-
-        // At this point, daycount is the number of days from 1/1/1901.
-      // Need to convert to julian date (which starts at 1/1/4713 B.C.)
-      wxDate date(1,1,1901);
-        date += daycount;
-
-        unsigned year = date.GetYear();
-      if (DST_OBSERVED)
-        {
-                if (*this >= GetBeginDST(year))
-                        if (*this < GetEndDST(year)) return TRUE;
-        }
-        return FALSE;
-}
+// NB: VC8 safe time functions could/should be used for wxMSW as well probably
+#if defined(__WXWINCE__) && defined(__VISUALC8__)
 
-wxTime wxTime::GetLocalTime() const
-/*
-        Adjusts this GM Time for local time zone and Daylight Savings Time.
-*/
+struct tm *wxLocaltime_r(const time_t *t, struct tm* tm)
 {
-      wxTime local_time(sec-TIME_ZONE);
-        if (local_time.IsDST()) local_time.sec += 3600;
-        return local_time;
+    __time64_t t64 = *t;
+    return _localtime64_s(tm, &t64) == 0 ? tm : NULL;
 }
 
-minuteTy wxTime::GetMinute() const
-/*
-        Return the minute of this wxTime in local time; i.e., adjust
-      for time zone and Daylight Savings Time.
-*/
+struct tm *wxGmtime_r(const time_t* t, struct tm* tm)
 {
-        return GetLocalTime().GetMinuteGMT();
+    __time64_t t64 = *t;
+    return _gmtime64_s(tm, &t64) == 0 ? tm : NULL;
 }
 
-minuteTy wxTime::GetMinuteGMT() const
-/*
-        Return the minute of this wxTime in GMT.
-*/
-{
-      return (minuteTy)(((sec % 86400) % 3600) / 60);
-}
+#else // !wxWinCE with VC8
 
-secondTy wxTime::GetSecond() const
-/*
-        Return the second of this wxTime.
-*/
-{
-      return (secondTy)(((sec % 86400) % 3600) % 60);
-}
-
-secondTy wxTime::GetSecondGMT() const
-/*
-        Return the minute of this wxTime in GMT.
-*/
-{
-        return (secondTy)(((sec % 86400) % 3600) % 60);
-}
-
-int wxTime::GetDay() const
-{
-    wxDate da((wxDate) *this);
-    return da.GetDay();
-}
+#if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__)
+static wxMutex timeLock;
+#endif
 
-int wxTime::GetDayOfWeek() const
+#ifndef HAVE_LOCALTIME_R
+struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp)
 {
-    wxDate da((wxDate) *this);
-    return da.GetDayOfWeek();
-}
+#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
 
-int wxTime::GetMonth() const
-{
-    wxDate da((wxDate) *this);
-    return da.GetMonth();
-}
+  // Borland CRT crashes when passed 0 ticks for some reason, see SF bug 1704438
+#ifdef __BORLANDC__
+  if ( !*ticks )
+      return NULL;
+#endif
 
-int wxTime::GetYear() const
-{
-    wxDate da((wxDate) *this);
-    return da.GetYear();
-}
+  const tm * const t = localtime(ticks);
+  if ( !t )
+      return NULL;
 
-wxTime wxTime::Max(const wxTime& t) const
-{
-        if (t < *this) return *this;
-        return t;
+  memcpy(temp, t, sizeof(struct tm));
+  return temp;
 }
+#endif // !HAVE_LOCALTIME_R
 
-wxTime wxTime::Min(const wxTime& t) const
+#ifndef HAVE_GMTIME_R
+struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp)
 {
-        if (t > *this) return *this;
-      return t;
-}
+#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
 
-#ifndef __SALFORDC__
-wxTime::operator wxChar *(void)
-{
-  return FormatTime();
-}
+#ifdef __BORLANDC__
+  if ( !*ticks )
+      return NULL;
 #endif
 
-void wxTime::SetFormat(const wxTime::tFormat lFormat,
-                const wxTime::tPrecision lPrecision) {
+  const tm * const t = gmtime(ticks);
+  if ( !t )
+      return NULL;
 
-  wxTime::Format    = lFormat;
-  wxTime::Precision  = lPrecision;
+  memcpy(temp, gmtime(ticks), sizeof(struct tm));
+  return temp;
 }
+#endif // !HAVE_GMTIME_R
 
-wxChar *wxTime::FormatTime() const {
-  static wxChar  timeBuf[30];
-  unsigned    hh(GetHour());
-
-  switch (Format) {
-  case wx12h:
-    hh  -= 12;
-    break;
-  case wx24h:
-    break;
-  }
-
-  switch (Precision) {
-  case wxStdMinSec:
-    wxSprintf(timeBuf,T("%2d:%02d:%02d"),hh,GetMinute(),GetSecond());
-    break;
-  case wxStdMin:
-    wxSprintf(timeBuf,T("%2d:%02d"),hh,GetMinute());
-    break;
-  }
-
-  if (Format == wx12h)
-    if (GetHour() <= 12)
-      wxStrcat(timeBuf,_("am"));
-    else
-      wxStrcat(timeBuf,_("pm"));
-
-  return timeBuf;
-}
+#endif // wxWinCE with VC8/other platforms
 
-/*
-int wxTime::compare(const Object& ob) const
+// returns the time zone in the C sense, i.e. the difference UTC - local
+// (in seconds)
+int wxGetTimeZone()
 {
-      assertArgSpecies(ob,classDesc,"compare");
-        register clockTy t = castdown(ob).sec;
-        if (sec < t) return -1;
-        if (sec > t) return 1;
-        return 0;
-}
-
-void wxTime::deepenShallowCopy()  {}
-
-unsigned wxTime::hash() const     { return sec; }
-
-bool wxTime::isEqual(const Object& ob) const
+#ifdef WX_GMTOFF_IN_TM
+    // set to true when the timezone is set
+    static bool s_timezoneSet = false;
+    static long gmtoffset = LONG_MAX; // invalid timezone
+
+    // ensure that the timezone variable is set by calling 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 = time(NULL);
+        struct tm tm;
+
+        wxLocaltime_r(&t, &tm);
+        s_timezoneSet = true;
+
+        // 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;
+
+        // this function is supposed to return the same value whether DST is
+        // enabled or not, so we need to use an additional offset if DST is on
+        // as tm_gmtoff already does include it
+        if ( tm.tm_isdst )
+            gmtoffset += 3600;
+    }
+    return (int)gmtoffset;
+#elif defined(__DJGPP__) || defined(__WINE__)
+    struct timeb tb;
+    ftime(&tb);
+    return tb.timezone*60;
+#elif defined(__VISUALC__)
+    // We must initialize the time zone information before using it (this will
+    // be done only once internally).
+    _tzset();
+
+    // Starting with VC++ 8 timezone variable is deprecated and is not even
+    // available in some standard library version so use the new function for
+    // accessing it instead.
+    #if wxCHECK_VISUALC_VERSION(8)
+        long t;
+        _get_timezone(&t);
+        return t;
+    #else // VC++ < 8
+        return timezone;
+    #endif
+#else // Use some kind of time zone variable.
+    // In any case we must initialize the time zone before using it.
+    tzset();
+
+    #if defined(WX_TIMEZONE) // If WX_TIMEZONE was defined by configure, use it.
+        return WX_TIMEZONE;
+    #elif defined(__BORLANDC__) || defined(__MINGW32__) || defined(__VISAGECPP__)
+        return _timezone;
+    #else // unknown platform -- assume it has timezone
+        return timezone;
+    #endif // different time zone variables
+#endif // different ways to determine time zone
+}
+
+// Get local time as seconds since 00:00:00, Jan 1st 1970
+long wxGetLocalTime()
+{
+    struct tm tm;
+    time_t t0, t1;
+
+    // This cannot be made static because mktime can overwrite it.
+    //
+    memset(&tm, 0, sizeof(tm));
+    tm.tm_year  = 70;
+    tm.tm_mon   = 0;
+    tm.tm_mday  = 5;        // not Jan 1st 1970 due to mktime 'feature'
+    tm.tm_hour  = 0;
+    tm.tm_min   = 0;
+    tm.tm_sec   = 0;
+    tm.tm_isdst = -1;       // let mktime guess
+
+    // Note that mktime assumes that the struct tm contains local time.
+    //
+    t1 = time(&t1);         // now
+    t0 = mktime(&tm);       // origin
+
+    // Return the difference in seconds.
+    //
+    if (( t0 != (time_t)-1 ) && ( t1 != (time_t)-1 ))
+        return (long)difftime(t1, t0) + (60 * 60 * 24 * 4);
+
+    wxLogSysError(_("Failed to get the local system time"));
+    return -1;
+}
+
+// Get UTC time as seconds since 00:00:00, Jan 1st 1970
+long wxGetUTCTime()
 {
-        return ob.isSpecies(classDesc) && *this==castdown(ob);
+    return (long)time(NULL);
 }
 
-const Class* wxTime::species() const { return &classDesc; }
+#if wxUSE_LONGLONG
 
-void wxTime::printOn(ostream& strm) const
+wxLongLong wxGetUTCTimeUSec()
 {
-        register unsigned hh = GetHour();
-        wxDate(*this).printOn(strm);
-        strm << ' ' << ((hh <= 12) ? hh : hh-12) << ':'
-             << setfill('0') << setw(2) << GetMinute() << ':'
-         << setfill('0') << setw(2) << GetSecond() << ' ';
-        if (hh < 12) strm << _("am");
-        else strm << _("pm");
-}
-
-wxTime::wxTime(OIOin& strm)
-      : BASE(strm)
+#if defined(__WINDOWS__)
+    FILETIME ft;
+    ::GetSystemTimeAsFileTime(&ft);
+
+    // FILETIME is in 100ns or 0.1us since 1601-01-01, transform to us since
+    // 1970-01-01.
+    wxLongLong t(ft.dwHighDateTime, ft.dwLowDateTime);
+    t /= 10;
+    t -= wxLL(11644473600000000); // Unix - Windows epochs difference in us.
+    return t;
+#else // non-MSW
+
+#ifdef HAVE_GETTIMEOFDAY
+    timeval tv;
+    if ( wxGetTimeOfDay(&tv) != -1 )
+    {
+        wxLongLong val(tv.tv_sec);
+        val *= MICROSECONDS_PER_SECOND;
+        val += tv.tv_usec;
+        return val;
+    }
+#endif // HAVE_GETTIMEOFDAY
+
+    // Fall back to lesser precision function.
+    return wxGetUTCTimeMillis()*MICROSECONDS_PER_MILLISECOND;
+#endif // MSW/!MSW
+}
+
+// Get local time as milliseconds since 00:00:00, Jan 1st 1970
+wxLongLong wxGetUTCTimeMillis()
 {
-      unsigned long usec;
-      strm >> sec >> usec;
-}
-
-void wxTime::storer(OIOout& strm) const
+    // If possible, use a function which avoids conversions from
+    // broken-up time structures to milliseconds
+#if defined(__WINDOWS__)
+    FILETIME ft;
+    ::GetSystemTimeAsFileTime(&ft);
+
+    // FILETIME is expressed in 100ns (or 0.1us) units since 1601-01-01,
+    // transform them to ms since 1970-01-01.
+    wxLongLong t(ft.dwHighDateTime, ft.dwLowDateTime);
+    t /= 10000;
+    t -= wxLL(11644473600000); // Unix - Windows epochs difference in ms.
+    return t;
+#else // !__WINDOWS__
+    wxLongLong val = MILLISECONDS_PER_SECOND;
+
+#if defined(HAVE_GETTIMEOFDAY)
+    struct timeval tp;
+    if ( wxGetTimeOfDay(&tp) != -1 )
+    {
+        val *= tp.tv_sec;
+        return (val + (tp.tv_usec / MICROSECONDS_PER_MILLISECOND));
+    }
+    else
+    {
+        wxLogError(_("wxGetTimeOfDay failed."));
+        return 0;
+    }
+#elif defined(HAVE_FTIME)
+    struct timeb tp;
+
+    // ftime() is void and not int in some mingw32 headers, so don't
+    // test the return code (well, it shouldn't fail anyhow...)
+    (void)::ftime(&tp);
+    val *= tp.time;
+    return (val + tp.millitm);
+#else // no gettimeofday() nor ftime()
+    // If your platform/compiler does not support ms resolution please
+    // do NOT just shut off these warnings, drop me a line instead at
+    // <guille@iies.es>
+
+    #if defined(__VISUALC__) || defined (__WATCOMC__)
+        #pragma message("wxStopWatch will be up to second resolution!")
+    #elif defined(__BORLANDC__)
+        #pragma message "wxStopWatch will be up to second resolution!"
+    #else
+        #warning "wxStopWatch will be up to second resolution!"
+    #endif // compiler
+
+    val *= wxGetUTCTime();
+    return val;
+#endif // time functions
+
+#endif // __WINDOWS__/!__WINDOWS__
+}
+
+wxLongLong wxGetLocalTimeMillis()
 {
-        BASE::storer(strm);
-        strm << sec << 0l;
+    return wxGetUTCTimeMillis() - wxGetTimeZone()*MILLISECONDS_PER_SECOND;
 }
 
+#else // !wxUSE_LONGLONG
 
-wxTime::wxTime(OIOifd& fd)
-      : BASE(fd)
+double wxGetLocalTimeMillis(void)
 {
-      unsigned long usec;
-      fd >> sec >> usec;
+    return (double(clock()) / double(CLOCKS_PER_SEC)) * 1000.0;
 }
 
-void wxTime::storer(OIOofd& fd) const
-{
-      BASE::storer(fd);
-      fd << sec << 0l;
-}
-*/
-
-#endif
+#endif // wxUSE_LONGLONG/!wxUSE_LONGLONG