1. more wxDateTime work

2. some thread corrections (not fixing the deadlock with Delete() :-( )


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4791 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 1999-12-01 22:15:53 +00:00
parent fa5f6926ec
commit fcc3d7cbad
7 changed files with 359 additions and 57 deletions

View File

@ -114,10 +114,45 @@ public:
// Note that GMT12 and GMT_12 are not the same: there is a difference
// of exactly one day between them
// Universal Coordinated Time
UTC = GMT0
// some symbolic names for TZ
// TODO add symbolic names for TZ (EST, MET, ...)?
// Europe
WET = GMT0, // Western Europe Time
WEST = GMT1, // Western Europe Summer Time
CET = GMT1, // Central Europe Time
CEST = GMT2, // Central Europe Summer Time
EET = GMT2, // Eastern Europe Time
EEST = GMT3, // Eastern Europe Summer Time
MSK = GMT3, // Moscow Time
MSD = GMT4, // Moscow Summer Time
// US and Canada
AST = GMT_4, // Atlantic Standard Time
ADT = GMT_3, // Atlantic Daylight Time
EST = GMT_5, // Eastern Standard Time
EDT = GMT_4, // Eastern Daylight Saving Time
CST = GMT_6, // Central Standard Time
CDT = GMT_5, // Central Daylight Saving Time
MST = GMT_7, // Mountain Standard Time
MDT = GMT_6, // Mountain Daylight Saving Time
PST = GMT_8, // Pacific Standard Time
PDT = GMT_7, // Pacific Daylight Saving Time
HST = GMT_10, // Hawaiian Standard Time
AKST = GMT_9, // Alaska Standard Time
AKDT = GMT_8, // Alaska Daylight Saving Time
// Australia
A_WST = GMT8, // Western Standard Time
A_CST = GMT12 + 1, // Central Standard Time (+9.5)
A_EST = GMT10, // Eastern Standard Time
A_ESST = GMT11, // Eastern Summer Time
// TODO add more symbolic timezone names here
// Universal Coordinated Time = the new and politically correct name
// for GMT
UTC = GMT0
};
// the calendar systems we know about: notice that it's valid (for
@ -290,10 +325,15 @@ public:
// standard struct tm is limited to the years from 1900 (because
// tm_year field is the offset from 1900), so we use our own struct
// instead to represent broken down time
//
// NB: this struct should always be kept normalized (i.e. mon should
// be < 12, 1 <= day <= 31 &c), so use AddMonths(), AddDays()
// instead of modifying the member fields directly!
struct Tm
{
wxDateTime_t sec, min, hour,
mday, mon, year;
wxDateTime_t sec, min, hour, mday;
Month mon;
int year;
// default ctor inits the object to an invalid value
Tm();
@ -313,6 +353,12 @@ public:
return (WeekDay)wday;
}
// add the given number of months to the date keeping it normalized
void AddMonths(wxDateTime_t monDiff);
// add the given number of months to the date keeping it normalized
void AddDays(wxDateTime_t dayDiff);
private:
// compute the weekday from other fields
void ComputeWeekDay();
@ -330,11 +376,11 @@ public:
TimeZone(TZ tz);
TimeZone(wxDateTime_t offset) { m_offset = offset; }
wxDateTime_t GetOffset() const { return m_offset; }
int GetOffset() const { return m_offset; }
private:
// offset for this timezone from GMT in minutes
wxDateTime_t m_offset;
int m_offset;
};
// static methods
@ -558,18 +604,24 @@ public:
// anything else, it should be requested explicitly
// ------------------------------------------------------------------------
// get the time corresponding to this one in UTC/GMT
wxDateTime ToUTC() const;
wxDateTime ToGMT() const { return ToUTC(); }
// transform this object to UTC/GMT
wxDateTime& MakeUTC();
wxDateTime& MakeGMT() { return MakeUTC(); }
// generic version: transform time to any given timezone
wxDateTime ToTimezone(const TimeZone& tz);
// get the time corresponding to this one in UTC/GMT
inline wxDateTime ToUTC() const;
wxDateTime ToGMT() const { return ToUTC(); }
// generic versions of the above
// transform from local time to any given timezone
inline wxDateTime ToTimezone(const TimeZone& tz) const;
wxDateTime& MakeTimezone(const TimeZone& tz);
// transform time from any timezone to the local time
inline wxDateTime ToLocalTime(const TimeZone& tz) const;
wxDateTime& MakeLocalTime(const TimeZone& tz);
// accessors: many of them take the timezone parameter which indicates the
// timezone for which to make the calculations and the default value means
// to do it for the current timezone of this machine (even if the function
@ -741,7 +793,7 @@ private:
// returns TRUE if we fall in range in which we can use standard ANSI C
// functions
inline IsInStdRange() const;
inline bool IsInStdRange() const;
// the internal representation of the time is the amount of milliseconds
// elapsed since the origin which is set by convention to the UNIX/C epoch
@ -761,25 +813,25 @@ public:
// constructors
// ------------------------------------------------------------------------
// return the timespan for the given number of seconds
static wxTimeSpan Seconds(int sec) { return wxTimeSpan(0, 0, sec); }
// return the timespan for the given number of minutes
static wxTimeSpan Minutes(int min) { return wxTimeSpan(0, min, 0 ); }
// return the timespan for the given number of hours
static wxTimeSpan Hours(int hours) { return wxTimeSpan(hours, 0, 0); }
// default ctor constructs the 0 time span
wxTimeSpan() { }
// from separate values for each component, date set to 0 (hours are
// not restricted to 0..24 range, neither are minutes, seconds or
// milliseconds)
wxTimeSpan(int hours,
int minutes = 0,
int seconds = 0,
int milliseconds = 0);
// from separate values for each component with explicit date (none of
// the parameters isn't restricted to any range)
wxTimeSpan(int years,
int months,
int days,
int hours = 0,
int minutes = 0,
int seconds = 0,
int milliseconds = 0);
inline wxTimeSpan(int hours,
int minutes = 0,
int seconds = 0,
int milliseconds = 0);
// from internal representation
wxTimeSpan(wxLongLong diff) : m_diff(diff) { }
@ -879,11 +931,11 @@ public:
// resulting text representation. Notice that only some of format
// specifiers valid for wxDateTime are valid for wxTimeSpan: hours,
// minutes and seconds make sense, but not "PM/AM" string for example.
wxString Format(const char *format = "%c") const;
wxString Format(const wxChar *format = _T("%c")) const;
// preferred date representation for the current locale
wxString FormatDate() const { return Format("%x"); }
wxString FormatDate() const { return Format(_T("%x")); }
// preferred time representation for the current locale
wxString FormatTime() const { return Format("%X"); }
wxString FormatTime() const { return Format(_T("%X")); }
// implementation
// ------------------------------------------------------------------------

View File

@ -35,7 +35,7 @@ wxDateTime::Country wxDateTime::GetCountry()
const unsigned int wxDateTime::TIME_T_FACTOR = 1000;
#endif // wxDEFINE_TIME_CONSTANTS
wxDateTime::IsInStdRange() const
bool wxDateTime::IsInStdRange() const
{
return m_time >= 0l && (m_time / (long)TIME_T_FACTOR) < LONG_MAX;
}
@ -237,10 +237,41 @@ wxDateTime& wxDateTime::operator+=(const wxDateSpan& diff)
return Add(diff);
}
// ----------------------------------------------------------------------------
// wxDateTime and timezones
// ----------------------------------------------------------------------------
wxDateTime wxDateTime::ToUTC() const
{
return wxDateTime(*this).MakeUTC();
}
wxDateTime wxDateTime::ToTimezone(const wxDateTime::TimeZone& tz) const
{
return wxDateTime(*this).MakeTimezone(tz);
}
wxDateTime wxDateTime::ToLocalTime(const wxDateTime::TimeZone& tz) const
{
return wxDateTime(*this).MakeLocalTime(tz);
}
// ----------------------------------------------------------------------------
// wxTimeSpan
// ----------------------------------------------------------------------------
wxTimeSpan::wxTimeSpan(int hours, int minutes, int seconds, int milliseconds)
{
// assign first to avoid precision loss
m_diff = hours;
m_diff *= 60;
m_diff += minutes;
m_diff *= 60;
m_diff += seconds;
m_diff *= 1000;
m_diff += milliseconds;
}
wxTimeSpan& wxTimeSpan::Add(const wxTimeSpan& diff)
{
m_diff += diff.GetValue();
@ -325,4 +356,3 @@ wxDateSpan& wxDateSpan::Neg()
return *this;
}

View File

@ -254,8 +254,10 @@ public:
// conversion to byte array: returns a pointer to static buffer!
void *asArray() const;
#if wxUSE_STD_IOSTREAM
// input/output
friend ostream& operator<<(ostream&, const wxLongLongNative&);
#endif
private:
wxLongLong_t m_ll;
@ -356,8 +358,10 @@ public:
wxLongLongWx& quotient,
wxLongLongWx& remainder) const;
#if wxUSE_STD_IOSTREAM
// input/output
friend ostream& operator<<(ostream&, const wxLongLongWx&);
#endif // wxUSE_STD_IOSTREAM
private:
// long is at least 32 bits, so represent our 64bit number as 2 longs

View File

@ -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
// ============================================================================
@ -144,8 +144,8 @@ static void TestTimeStatic()
wxDateTime::GetNumberOfDays(month));
// leap year logic
static const nYears = 5;
static const int years[2][nYears] =
static const size_t nYears = 5;
static const size_t years[2][nYears] =
{
// first line: the years to test
{ 1990, 1976, 2000, 2030, 1984, },
@ -179,6 +179,20 @@ static void TestTimeSet()
printf("May 29, 1976:\t%s\n", wxDateTime(29, wxDateTime::May, 1976).Format().c_str());
}
// test time zones stuff
static void TestTimeZones()
{
puts("\n*** wxDateTime timezone test ***");
wxDateTime now = wxDateTime::Now();
printf("Current GMT time:\t%s\n", now.ToGMT().Format().c_str());
//printf("Unix epoch (GMT):\t%s\n", wxDateTime((time_t)0).MakeGMT().Format().c_str());
printf("Current time in Paris:\t%s\n", now.ToTimezone(wxDateTime::CET).Format().c_str());
printf(" Moscow:\t%s\n", now.ToTimezone(wxDateTime::MSK).Format().c_str());
printf(" New York:\t%s\n", now.ToTimezone(wxDateTime::EST).Format().c_str());
}
#endif // TEST_TIME
// ----------------------------------------------------------------------------
@ -223,7 +237,14 @@ wxThread::ExitCode MyJoinableThread::Entry()
class MyDetachedThread : public wxThread
{
public:
MyDetachedThread(size_t n, char ch) { m_n = n; m_ch = ch; Create(); }
MyDetachedThread(size_t n, char ch)
{
m_n = n;
m_ch = ch;
m_cancelled = FALSE;
Create();
}
// thread execution starts here
virtual ExitCode Entry();
@ -234,6 +255,8 @@ public:
private:
size_t m_n; // number of characters to write
char m_ch; // character to write
bool m_cancelled; // FALSE if we exit normally
};
wxThread::ExitCode MyDetachedThread::Entry()
@ -249,7 +272,11 @@ wxThread::ExitCode MyDetachedThread::Entry()
for ( size_t n = 0; n < m_n; n++ )
{
if ( TestDestroy() )
{
m_cancelled = TRUE;
break;
}
putchar(m_ch);
fflush(stdout);
@ -265,7 +292,7 @@ void MyDetachedThread::OnExit()
wxLogTrace("thread", "Thread %ld is in OnExit", GetId());
wxCriticalSectionLocker lock(gs_critsect);
if ( !--gs_counter )
if ( !--gs_counter && !m_cancelled )
gs_cond.Signal();
}
@ -565,6 +592,7 @@ int main(int argc, char **argv)
#ifdef TEST_TIME
TestTimeStatic();
TestTimeSet();
TestTimeZones();
#endif // TEST_TIME
wxUninitialize();

View File

@ -34,6 +34,8 @@
#include "wx/log.h"
#endif // WX_PRECOMP
#include "wx/thread.h"
#define wxDEFINE_TIME_CONSTANTS
#include "wx/datetime.h"
@ -42,18 +44,59 @@
// constants
// ----------------------------------------------------------------------------
// note that all these constants should be signed or we'd get some big
// surprizes with C integer arithmetics
static const int MONTHS_IN_YEAR = 12;
static const int SECONDS_IN_MINUTE = 60;
// the number of days in month in Julian/Gregorian calendar: the first line is
// for normal years, the second one is for the leap ones
static wxDateTime::wxDateTime_t gs_daysInMonth[2][12] =
static wxDateTime::wxDateTime_t gs_daysInMonth[2][MONTHS_IN_YEAR] =
{
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
// ----------------------------------------------------------------------------
// globals
// ----------------------------------------------------------------------------
// a critical section is needed to protect GetTimeZone() static
// variable in MT case
#ifdef wxUSE_THREADS
wxCriticalSection gs_critsectTimezone;
#endif // wxUSE_THREADS
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
// get the number of days in the given month of the given year
static inline
wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month)
{
return gs_daysInMonth[wxDateTime::IsLeapYear(year)][month];
}
// ensure that the timezone variable is set by calling localtime
static int GetTimeZone()
{
// set to TRUE when the timezone is set
static bool s_timezoneSet = FALSE;
wxCRIT_SECT_LOCKER(lock, gs_critsectTimezone);
if ( !s_timezoneSet )
{
(void)localtime(0);
s_timezoneSet = TRUE;
}
return (int)timezone;
}
// this function is a wrapper around strftime(3)
static wxString CallStrftime(const wxChar *format, const tm* tm)
{
@ -119,7 +162,7 @@ wxDateTime::Tm::Tm(const struct tm& tm)
min = tm.tm_min;
hour = tm.tm_hour;
mday = tm.tm_mday;
mon = tm.tm_mon;
mon = (wxDateTime::Month)tm.tm_mon;
year = 1900 + tm.tm_year;
wday = tm.tm_wday;
yday = tm.tm_yday;
@ -128,8 +171,8 @@ wxDateTime::Tm::Tm(const struct tm& tm)
bool wxDateTime::Tm::IsValid() const
{
// we allow for the leap seconds, although we don't use them (yet)
return (year != wxDateTime::Inv_Year) && (mon < 12) &&
(mday < gs_daysInMonth[IsLeapYear(year)][mon]) &&
return (year != wxDateTime::Inv_Year) && (mon != wxDateTime::Inv_Month) &&
(mday < GetNumOfDaysInMonth(year, mon)) &&
(hour < 24) && (min < 60) && (sec < 62);
}
@ -138,6 +181,101 @@ void wxDateTime::Tm::ComputeWeekDay()
wxFAIL_MSG(_T("TODO"));
}
void wxDateTime::Tm::AddMonths(wxDateTime::wxDateTime_t monDiff)
{
// normalize the months field
while ( monDiff < -mon )
{
year--;
monDiff += MONTHS_IN_YEAR;
}
while ( monDiff + mon > MONTHS_IN_YEAR )
{
year++;
}
mon = (wxDateTime::Month)(mon + monDiff);
wxASSERT_MSG( mon >= 0 && mon < 12, _T("logic error") );
}
void wxDateTime::Tm::AddDays(wxDateTime::wxDateTime_t dayDiff)
{
// normalize the days field
mday += dayDiff;
while ( mday < 1 )
{
AddMonths(-1);
mday += GetNumOfDaysInMonth(year, mon);
}
while ( mday > GetNumOfDaysInMonth(year, mon) )
{
mday -= GetNumOfDaysInMonth(year, mon);
AddMonths(1);
}
wxASSERT_MSG( mday > 0 && mday <= GetNumOfDaysInMonth(year, mon),
_T("logic error") );
}
// ----------------------------------------------------------------------------
// class TimeZone
// ----------------------------------------------------------------------------
wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz)
{
switch ( tz )
{
case wxDateTime::Local:
// leave offset to be 0
break;
case wxDateTime::GMT_12:
case wxDateTime::GMT_11:
case wxDateTime::GMT_10:
case wxDateTime::GMT_9:
case wxDateTime::GMT_8:
case wxDateTime::GMT_7:
case wxDateTime::GMT_6:
case wxDateTime::GMT_5:
case wxDateTime::GMT_4:
case wxDateTime::GMT_3:
case wxDateTime::GMT_2:
case wxDateTime::GMT_1:
m_offset = -60*(wxDateTime::GMT0 - tz);
break;
case wxDateTime::GMT0:
case wxDateTime::GMT1:
case wxDateTime::GMT2:
case wxDateTime::GMT3:
case wxDateTime::GMT4:
case wxDateTime::GMT5:
case wxDateTime::GMT6:
case wxDateTime::GMT7:
case wxDateTime::GMT8:
case wxDateTime::GMT9:
case wxDateTime::GMT10:
case wxDateTime::GMT11:
case wxDateTime::GMT12:
m_offset = 60*(tz - wxDateTime::GMT0);
break;
case wxDateTime::A_CST:
// Central Standard Time in use in Australia = UTC + 9.5
m_offset = 9*60 + 30;
break;
default:
wxFAIL_MSG( _T("unknown time zone") );
}
}
// ----------------------------------------------------------------------------
// static functions
// ----------------------------------------------------------------------------
@ -169,6 +307,12 @@ bool wxDateTime::IsLeapYear(int year, wxDateTime::Calendar cal)
}
}
/* static */
int wxDateTime::GetCentury(int year)
{
return year > 0 ? year / 100 : year / 100 - 1;
}
/* static */
void wxDateTime::SetCountry(wxDateTime::Country country)
{
@ -252,7 +396,7 @@ wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month,
int year,
wxDateTime::Calendar cal)
{
wxCHECK_MSG( month < 12, 0, _T("invalid month") );
wxCHECK_MSG( month < MONTHS_IN_YEAR, 0, _T("invalid month") );
if ( cal == Gregorian || cal == Julian )
{
@ -262,7 +406,7 @@ wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month,
year = GetCurrentYear();
}
return gs_daysInMonth[IsLeapYear(year)][month];
return GetNumOfDaysInMonth(year, month);
}
else
{
@ -391,8 +535,7 @@ wxDateTime& wxDateTime::Set(wxDateTime_t day,
else
{
// do time calculations ourselves: we want to calculate the number of
// milliseconds between the given date and the epoch (necessarily
// negative)
// milliseconds between the given date and the epoch
wxFAIL_MSG(_T("TODO"));
}
@ -512,8 +655,8 @@ wxDateTime& wxDateTime::Add(const wxDateSpan& diff)
Tm tm(GetTm());
tm.year += diff.GetYears();
tm.mon += diff.GetMonths();
tm.mday += diff.GetTotalDays();
tm.AddMonths(diff.GetMonths());
tm.AddDays(diff.GetTotalDays());
Set(tm);
@ -530,7 +673,7 @@ wxDateTime& wxDateTime::SetToLastMonthDay(Month month,
// take the current month/year if none specified
ReplaceDefaultYearMonthWithCurrent(&year, &month);
return Set(gs_daysInMonth[IsLeapYear(year)][month], month, year);
return Set(GetNumOfDaysInMonth(year, month), month, year);
}
bool wxDateTime::SetToWeekDay(WeekDay weekday,
@ -601,6 +744,27 @@ bool wxDateTime::SetToWeekDay(WeekDay weekday,
}
}
// ----------------------------------------------------------------------------
// timezone stuff
// ----------------------------------------------------------------------------
wxDateTime& wxDateTime::MakeUTC()
{
return Add(wxTimeSpan::Seconds(GetTimeZone()));
}
wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz)
{
int minDiff = GetTimeZone() / SECONDS_IN_MINUTE + tz.GetOffset();
return Add(wxTimeSpan::Minutes(minDiff));
}
wxDateTime& wxDateTime::MakeLocalTime(const TimeZone& tz)
{
int minDiff = GetTimeZone() / SECONDS_IN_MINUTE + tz.GetOffset();
return Substract(wxTimeSpan::Minutes(minDiff));
}
// ----------------------------------------------------------------------------
// wxDateTime to/from text representations
// ----------------------------------------------------------------------------
@ -625,3 +789,16 @@ wxString wxDateTime::Format(const wxChar *format) const
return _T("");
}
}
// ============================================================================
// wxTimeSpan
// ============================================================================
wxString wxTimeSpan::Format(const wxChar *format) const
{
wxFAIL_MSG( _T("TODO") );
wxString str;
return str;
}

View File

@ -57,6 +57,8 @@ void *wxLongLongNative::asArray(void) const
return temp;
}
#if wxUSE_STD_IOSTREAM
// input/output
ostream& operator<< (ostream& o, const wxLongLongNative& ll)
{
@ -74,6 +76,8 @@ ostream& operator<< (ostream& o, const wxLongLongNative& ll)
return o << result;
}
#endif // wxUSE_STD_IOSTREAM
#endif // wxUSE_LONGLONG_NATIVE
#if wxUSE_LONGLONG_WX
@ -449,8 +453,9 @@ void *wxLongLongWx::asArray(void) const
return temp;
}
// input/output
#if wxUSE_STD_IOSTREAM
// input/output
ostream& operator<< (ostream& o, const wxLongLongWx& ll)
{
char result[65];
@ -467,7 +472,8 @@ ostream& operator<< (ostream& o, const wxLongLongWx& ll)
return o << result;
}
#endif
// wxUSE_LONGLONG_NATIVE
#endif // wxUSE_STD_IOSTREAM
#endif // wxUSE_LONGLONG_NATIVE
#endif // wxUSE_LONGLONG

View File

@ -24,9 +24,7 @@
#pragma implementation "thread.h"
#endif
// With simple makefiles, we must ignore the file body if not using
// threads.
#include "wx/setup.h"
#include "wx/defs.h"
#if wxUSE_THREADS
@ -586,6 +584,9 @@ void wxThreadInternal::Wait()
if ( wxThread::IsMain() )
wxMutexGuiLeave();
wxLogTrace(TRACE_THREADS, _T("Starting to wait for thread %ld to exit."),
GetId());
// wait until the thread terminates (we're blocking in _another_ thread,
// of course)
m_condEnd.Wait();
@ -622,6 +623,9 @@ void wxThreadInternal::SignalExit()
// wake up all the threads waiting for our termination - if there are any
if ( m_shouldBroadcast )
{
wxLogTrace(TRACE_THREADS, _T("Thread %ld signals end condition."),
GetId());
m_condEnd.Broadcast();
}
}
@ -1243,8 +1247,9 @@ static void ScheduleThreadForDeletion()
gs_nThreadsBeingDeleted++;
wxLogTrace(TRACE_THREADS, _T("%u threads waiting to be deleted"),
gs_nThreadsBeingDeleted);
wxLogTrace(TRACE_THREADS, _T("%u thread%s waiting to be deleted"),
gs_nThreadsBeingDeleted,
gs_nThreadsBeingDeleted == 1 ? "" : "s");
}
static void DeleteThread(wxThread *This)