X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1f0299c17dc878540bf190c290392db241b425ad..bf2c43c76e2819be443ab1d830ab68d9569d66b1:/src/common/time.cpp diff --git a/src/common/time.cpp b/src/common/time.cpp index 15936ad323..011b601490 100644 --- a/src/common/time.cpp +++ b/src/common/time.cpp @@ -1,383 +1,361 @@ -///////////////////////////////////////////////////////////////////////////// -// 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 +// 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 USE_TIMEDATE - #include "wx/time.h" -#include "wx/date.h" -#include "wx/utils.h" -#if USE_IOSTREAMH -#include -#else -#include +#ifndef WX_PRECOMP + #ifdef __WINDOWS__ + #include "wx/msw/wrapwin.h" + #endif + #include "wx/intl.h" + #include "wx/log.h" #endif -#include -#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); +#ifndef __WXWINCE__ +#include +#else +#include "wx/msw/private.h" +#include "wx/msw/wince/time.h" +#endif -static long TIME_ZONE; /* seconds west of GMT */ -static int DST_OBSERVED; /* flags U.S. daylight saving time observed */ -static bool wxTimeInitialized = FALSE; +#if !defined(__WXMAC__) && !defined(__WXWINCE__) + #include // for time_t +#endif -wxTime::tFormat wxTime::Format = wxTime::wx12h; -wxTime::tPrecision wxTime::Precision = wxTime::wxStdMinSec; +#if defined(HAVE_GETTIMEOFDAY) + #include + #include +#elif defined(HAVE_FTIME) + #include +#endif -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 */ +#if defined(__DJGPP__) || defined(__WINE__) + #include + #include +#endif -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. -*/ +namespace { - 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(); - sec += 2177452800UL; /* seconds from 1/1/01 to 1/1/70 */ -} +const int MILLISECONDS_PER_SECOND = 1000; +const int MICROSECONDS_PER_MILLISECOND = 1000; +const int MICROSECONDS_PER_SECOND = 1000*1000; -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; -} +} // anonymous namespace +// ============================================================================ +// implementation +// ============================================================================ -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 -} +// NB: VC8 safe time functions could/should be used for wxMSW as well probably +#if defined(__WXWINCE__) && defined(__VISUALC8__) -wxTime::operator wxDate() const -/* - Convert a wxTime to a local wxDate -*/ +struct tm *wxLocaltime_r(const time_t *t, struct tm* tm) { -// return wxDate((int)(GetLocalTime().sec/seconds_in_day)); 4.2 cc bug - long daycount = (long)(GetLocalTime().sec/seconds_in_day); - - wxDate date(1,1,1901); - date += daycount; - return date; + __time64_t t64 = *t; + return _localtime64_s(tm, &t64) == 0 ? tm : NULL; } -bool wxTime::IsBetween(const wxTime& a, const wxTime& b) const +struct tm *wxGmtime_r(const time_t* t, struct tm* tm) { - return *this >= a && *this <= b; + __time64_t t64 = *t; + return _gmtime64_s(tm, &t64) == 0 ? tm : NULL; } -hourTy wxTime::GetHour() const -/* - Return the hour of this wxTime in local time; i.e., adjust for - time zone and Daylight Savings Time. -*/ -{ - return GetLocalTime().GetHourGMT(); -} +#else // !wxWinCE with VC8 -hourTy wxTime::GetHourGMT() const -/* - Return the hour of this Time in GMT. -*/ -{ - return (hourTy)((sec % 86400) / 3600); -} +#if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__) +static wxMutex timeLock; +#endif -wxTime wxTime::GetBeginDST(unsigned year) -/* - Return the local Standard Time at which Daylight Savings Time - begins in the specified year. -*/ +#ifndef HAVE_LOCALTIME_R +struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp) { - // 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; -} +#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 -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; -} + // Borland CRT crashes when passed 0 ticks for some reason, see SF bug 1704438 +#ifdef __BORLANDC__ + if ( !*ticks ) + return NULL; +#endif -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; -} + const tm * const t = localtime(ticks); + if ( !t ) + return NULL; -wxTime wxTime::GetLocalTime() const -/* - Adjusts this GM Time for local time zone and Daylight Savings Time. -*/ -{ - wxTime local_time(sec-TIME_ZONE); - if (local_time.IsDST()) local_time.sec += 3600; - return local_time; + memcpy(temp, t, sizeof(struct tm)); + return temp; } +#endif // !HAVE_LOCALTIME_R -minuteTy wxTime::GetMinute() const -/* - Return the minute of this wxTime in local time; i.e., adjust - for time zone and Daylight Savings Time. -*/ +#ifndef HAVE_GMTIME_R +struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp) { - return GetLocalTime().GetMinuteGMT(); -} +#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 -minuteTy wxTime::GetMinuteGMT() const -/* - Return the minute of this wxTime in GMT. -*/ -{ - return (minuteTy)(((sec % 86400) % 3600) / 60); -} +#ifdef __BORLANDC__ + if ( !*ticks ) + return NULL; +#endif -secondTy wxTime::GetSecond() const -/* - Return the second of this wxTime. -*/ -{ - return (secondTy)(((sec % 86400) % 3600) % 60); -} + const tm * const t = gmtime(ticks); + if ( !t ) + return NULL; -wxTime wxTime::Max(const wxTime& t) const -{ - if (t < *this) return *this; - return t; + memcpy(temp, gmtime(ticks), sizeof(struct tm)); + return temp; } +#endif // !HAVE_GMTIME_R -wxTime wxTime::Min(const wxTime& t) const -{ - if (t > *this) return *this; - return t; -} +#endif // wxWinCE with VC8/other platforms -wxTime::operator char *(void) +// returns the time zone in the C sense, i.e. the difference UTC - local +// (in seconds) +int wxGetTimeZone() { - return FormatTime(); -} - -void wxTime::SetFormat(const wxTime::tFormat lFormat, - const wxTime::tPrecision lPrecision) { - - wxTime::Format = lFormat; - wxTime::Precision = lPrecision; -} - -char *wxTime::FormatTime() const { - static char timeBuf[30]; - unsigned hh(GetHour()); - - switch (Format) { - case wx12h: - hh -= 12; - break; - case wx24h: - break; - } - - switch (Precision) { - case wxStdMinSec: - sprintf(timeBuf,"%2d:%02d:%02d",hh,GetMinute(),GetSecond()); - break; - case wxStdMin: - sprintf(timeBuf,"%2d:%02d",hh,GetMinute()); - break; - } - - if (Format == wx12h) - if (GetHour() <= 12) - strcat(timeBuf,"am"); - else - strcat(timeBuf,"pm"); - - return timeBuf; +#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 } -/* -int wxTime::compare(const Object& ob) const +// Get local time as seconds since 00:00:00, Jan 1st 1970 +long wxGetLocalTime() { - assertArgSpecies(ob,classDesc,"compare"); - register clockTy t = castdown(ob).sec; - if (sec < t) return -1; - if (sec > t) return 1; - return 0; + 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; } -void wxTime::deepenShallowCopy() {} - -unsigned wxTime::hash() const { return sec; } - -bool wxTime::isEqual(const Object& ob) const +// 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"; +#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 } -wxTime::wxTime(OIOin& strm) - : BASE(strm) +// Get local time as milliseconds since 00:00:00, Jan 1st 1970 +wxLongLong wxGetUTCTimeMillis() { - unsigned long usec; - strm >> sec >> usec; + // 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 + // + + #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__ } -void wxTime::storer(OIOout& strm) const +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