// Note that GMT12 and GMT_12 are not the same: there is a difference
// of exactly one day between them
- // Universal Coordinated Time
+ // some symbolic names for TZ
+
+ // 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
-
- // TODO add symbolic names for TZ (EST, MET, ...)?
};
// the calendar systems we know about: notice that it's valid (for
// 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();
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();
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
// 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
// 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
// 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) { }
// 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
// ------------------------------------------------------------------------
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;
}
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();
return *this;
}
-
// 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;
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
//#define TEST_ARRAYS
//#define TEST_LOG
//#define TEST_STRINGS
-//#define TEST_THREADS
-#define TEST_TIME
+#define TEST_THREADS
+//#define TEST_TIME
//#define TEST_LONGLONG
// ============================================================================
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, },
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
// ----------------------------------------------------------------------------
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();
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()
for ( size_t n = 0; n < m_n; n++ )
{
if ( TestDestroy() )
+ {
+ m_cancelled = TRUE;
+
break;
+ }
putchar(m_ch);
fflush(stdout);
wxLogTrace("thread", "Thread %ld is in OnExit", GetId());
wxCriticalSectionLocker lock(gs_critsect);
- if ( !--gs_counter )
+ if ( !--gs_counter && !m_cancelled )
gs_cond.Signal();
}
#ifdef TEST_TIME
TestTimeStatic();
TestTimeSet();
+ TestTimeZones();
#endif // TEST_TIME
wxUninitialize();
#include "wx/log.h"
#endif // WX_PRECOMP
+#include "wx/thread.h"
+
#define wxDEFINE_TIME_CONSTANTS
#include "wx/datetime.h"
// 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)
{
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;
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);
}
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
// ----------------------------------------------------------------------------
}
}
+/* static */
+int wxDateTime::GetCentury(int year)
+{
+ return year > 0 ? year / 100 : year / 100 - 1;
+}
+
/* static */
void wxDateTime::SetCountry(wxDateTime::Country country)
{
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 )
{
year = GetCurrentYear();
}
- return gs_daysInMonth[IsLeapYear(year)][month];
+ return GetNumOfDaysInMonth(year, month);
}
else
{
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"));
}
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);
// 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,
}
}
+// ----------------------------------------------------------------------------
+// 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
// ----------------------------------------------------------------------------
return _T("");
}
}
+
+// ============================================================================
+// wxTimeSpan
+// ============================================================================
+
+wxString wxTimeSpan::Format(const wxChar *format) const
+{
+ wxFAIL_MSG( _T("TODO") );
+
+ wxString str;
+
+ return str;
+}
return temp;
}
+#if wxUSE_STD_IOSTREAM
+
// input/output
ostream& operator<< (ostream& o, const wxLongLongNative& ll)
{
return o << result;
}
+#endif // wxUSE_STD_IOSTREAM
+
#endif // wxUSE_LONGLONG_NATIVE
#if wxUSE_LONGLONG_WX
return temp;
}
-// input/output
+#if wxUSE_STD_IOSTREAM
+// input/output
ostream& operator<< (ostream& o, const wxLongLongWx& ll)
{
char result[65];
return o << result;
}
-#endif
- // wxUSE_LONGLONG_NATIVE
+#endif // wxUSE_STD_IOSTREAM
+
+#endif // wxUSE_LONGLONG_NATIVE
#endif // wxUSE_LONGLONG
#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
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();
// 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();
}
}
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)