X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/be0872076f185e94b1a76c116ac4874af443c526..41fec01fa9e009d84fe353aa494725328d850af1:/src/common/time.cpp diff --git a/src/common/time.cpp b/src/common/time.cpp index 1e358e4a09..ff163db0cc 100644 --- a/src/common/time.cpp +++ b/src/common/time.cpp @@ -1,426 +1,372 @@ -///////////////////////////////////////////////////////////////////////////// -// 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 +// 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" - -#if wxUSE_STD_IOSTREAM - #include "wx/ioswrap.h" - #if wxUSE_IOSTREAMH - #include - #else - #include + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" #endif + #include "wx/intl.h" + #include "wx/log.h" #endif -#include - -#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); -} +#if defined(__MWERKS__) && defined(__WXMSW__) +# undef HAVE_FTIME +# undef HAVE_GETTIMEOFDAY +#endif -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 #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; -} +#if !defined(__WXMAC__) && !defined(__WXWINCE__) + #include // for time_t +#endif -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(HAVE_GETTIMEOFDAY) + #include + #include +#elif defined(HAVE_FTIME) + #include +#endif - wxDate date(1,1,1901); - date += daycount; - return date; -} +#if defined(__MWERKS__) && wxUSE_UNICODE + #include #endif -bool wxTime::IsBetween(const wxTime& a, const wxTime& b) const -{ - return *this >= a && *this <= b; -} +#if defined(__DJGPP__) || defined(__WINE__) + #include + #include +#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,wxT("%2d:%02d:%02d"),hh,GetMinute(),GetSecond()); - break; - case wxStdMin: - wxSprintf(timeBuf,wxT("%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; + #elif defined(__MWERKS__) + // This is just plain wrong but apparently MetroWerks runtime didn't have + // any way to get the time zone. + return 28800; + #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() { - return ob.isSpecies(classDesc) && *this==castdown(ob); + 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 (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(__WXMSW__) + 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; -} + wxLongLong val = MILLISECONDS_PER_SECOND; + + // If possible, use a function which avoids conversions from + // broken-up time structures to milliseconds +#if defined(__WXMSW__) + 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; +#elif 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 + // + + #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 -void wxTime::storer(OIOout& strm) const -{ - BASE::storer(strm); - strm << sec << 0l; + val *= wxGetUTCTime(); + return val; +#endif // time functions } - -wxTime::wxTime(OIOifd& fd) - : BASE(fd) +wxLongLong wxGetLocalTimeMillis() { - unsigned long usec; - fd >> sec >> usec; + return wxGetUTCTimeMillis() - wxGetTimeZone()*MILLISECONDS_PER_SECOND; } -void wxTime::storer(OIOofd& fd) const +#else // !wxUSE_LONGLONG + +double wxGetLocalTimeMillis(void) { - BASE::storer(fd); - fd << sec << 0l; + return (double(clock()) / double(CLOCKS_PER_SEC)) * 1000.0; } -*/ -#endif +#endif // wxUSE_LONGLONG/!wxUSE_LONGLONG