+ return ms_country;
+}
+
+/* static */
+void wxDateTime::SetCountry(wxDateTime::Country country)
+{
+ ms_country = country;
+}
+
+/* static */
+bool wxDateTime::IsWestEuropeanCountry(Country country)
+{
+ if ( country == Country_Default )
+ {
+ country = GetCountry();
+ }
+
+ return (Country_WesternEurope_Start <= country) &&
+ (country <= Country_WesternEurope_End);
+}
+
+// ----------------------------------------------------------------------------
+// DST calculations: we use 3 different rules for the West European countries,
+// USA and for the rest of the world. This is undoubtedly false for many
+// countries, but I lack the necessary info (and the time to gather it),
+// please add the other rules here!
+// ----------------------------------------------------------------------------
+
+/* static */
+bool wxDateTime::IsDSTApplicable(int year, Country country)
+{
+ if ( year == Inv_Year )
+ {
+ // take the current year if none given
+ year = GetCurrentYear();
+ }
+
+ if ( country == Country_Default )
+ {
+ country = GetCountry();
+ }
+
+ switch ( country )
+ {
+ case USA:
+ case UK:
+ // DST was first observed in the US and UK during WWI, reused
+ // during WWII and used again since 1966
+ return year >= 1966 ||
+ (year >= 1942 && year <= 1945) ||
+ (year == 1918 || year == 1919);
+
+ default:
+ // assume that it started after WWII
+ return year > 1950;
+ }
+}
+
+/* static */
+wxDateTime wxDateTime::GetBeginDST(int year, Country country)
+{
+ if ( year == Inv_Year )
+ {
+ // take the current year if none given
+ year = GetCurrentYear();
+ }
+
+ if ( country == Country_Default )
+ {
+ country = GetCountry();
+ }
+
+ if ( !IsDSTApplicable(year, country) )
+ {
+ return wxInvalidDateTime;
+ }
+
+ wxDateTime dt;
+
+ if ( IsWestEuropeanCountry(country) || (country == Russia) )
+ {
+ // DST begins at 1 a.m. GMT on the last Sunday of March
+ if ( !dt.SetToLastWeekDay(Sun, Mar, year) )
+ {
+ // weird...
+ wxFAIL_MSG( wxT("no last Sunday in March?") );
+ }
+
+ dt += wxTimeSpan::Hours(1);
+ }
+ else switch ( country )
+ {
+ case USA:
+ switch ( year )
+ {
+ case 1918:
+ case 1919:
+ // don't know for sure - assume it was in effect all year
+
+ case 1943:
+ case 1944:
+ case 1945:
+ dt.Set(1, Jan, year);
+ break;
+
+ case 1942:
+ // DST was installed Feb 2, 1942 by the Congress
+ dt.Set(2, Feb, year);
+ break;
+
+ // Oil embargo changed the DST period in the US
+ case 1974:
+ dt.Set(6, Jan, 1974);
+ break;
+
+ case 1975:
+ dt.Set(23, Feb, 1975);
+ break;
+
+ default:
+ // before 1986, DST begun on the last Sunday of April, but
+ // in 1986 Reagan changed it to begin at 2 a.m. of the
+ // first Sunday in April
+ if ( year < 1986 )
+ {
+ if ( !dt.SetToLastWeekDay(Sun, Apr, year) )
+ {
+ // weird...
+ wxFAIL_MSG( wxT("no first Sunday in April?") );
+ }
+ }
+ else if ( year > 2006 )
+ // Energy Policy Act of 2005, Pub. L. no. 109-58, 119 Stat 594 (2005).
+ // Starting in 2007, daylight time begins in the United States on the
+ // second Sunday in March and ends on the first Sunday in November
+ {
+ if ( !dt.SetToWeekDay(Sun, 2, Mar, year) )
+ {
+ // weird...
+ wxFAIL_MSG( wxT("no second Sunday in March?") );
+ }
+ }
+ else
+ {
+ if ( !dt.SetToWeekDay(Sun, 1, Apr, year) )
+ {
+ // weird...
+ wxFAIL_MSG( wxT("no first Sunday in April?") );
+ }
+ }
+
+ dt += wxTimeSpan::Hours(2);
+
+ // TODO what about timezone??
+ }
+
+ break;
+
+ default:
+ // assume Mar 30 as the start of the DST for the rest of the world
+ // - totally bogus, of course
+ dt.Set(30, Mar, year);
+ }
+
+ return dt;
+}
+
+/* static */
+wxDateTime wxDateTime::GetEndDST(int year, Country country)
+{
+ if ( year == Inv_Year )
+ {
+ // take the current year if none given
+ year = GetCurrentYear();
+ }
+
+ if ( country == Country_Default )
+ {
+ country = GetCountry();
+ }
+
+ if ( !IsDSTApplicable(year, country) )
+ {
+ return wxInvalidDateTime;
+ }
+
+ wxDateTime dt;
+
+ if ( IsWestEuropeanCountry(country) || (country == Russia) )
+ {
+ // DST ends at 1 a.m. GMT on the last Sunday of October
+ if ( !dt.SetToLastWeekDay(Sun, Oct, year) )
+ {
+ // weirder and weirder...
+ wxFAIL_MSG( wxT("no last Sunday in October?") );
+ }
+
+ dt += wxTimeSpan::Hours(1);
+ }
+ else switch ( country )
+ {
+ case USA:
+ switch ( year )
+ {
+ case 1918:
+ case 1919:
+ // don't know for sure - assume it was in effect all year
+
+ case 1943:
+ case 1944:
+ dt.Set(31, Dec, year);
+ break;
+
+ case 1945:
+ // the time was reset after the end of the WWII
+ dt.Set(30, Sep, year);
+ break;
+
+ default: // default for switch (year)
+ if ( year > 2006 )
+ // Energy Policy Act of 2005, Pub. L. no. 109-58, 119 Stat 594 (2005).
+ // Starting in 2007, daylight time begins in the United States on the
+ // second Sunday in March and ends on the first Sunday in November
+ {
+ if ( !dt.SetToWeekDay(Sun, 1, Nov, year) )
+ {
+ // weird...
+ wxFAIL_MSG( wxT("no first Sunday in November?") );
+ }
+ }
+ else
+ // pre-2007
+ // DST ends at 2 a.m. on the last Sunday of October
+ {
+ if ( !dt.SetToLastWeekDay(Sun, Oct, year) )
+ {
+ // weirder and weirder...
+ wxFAIL_MSG( wxT("no last Sunday in October?") );
+ }
+ }
+
+ dt += wxTimeSpan::Hours(2);
+
+ // TODO: what about timezone??
+ }
+ break;
+
+ default: // default for switch (country)
+ // assume October 26th as the end of the DST - totally bogus too
+ dt.Set(26, Oct, year);
+ }
+
+ return dt;
+}
+
+// ----------------------------------------------------------------------------
+// constructors and assignment operators
+// ----------------------------------------------------------------------------
+
+// return the current time with ms precision
+/* static */ wxDateTime wxDateTime::UNow()
+{
+ return wxDateTime(wxGetLocalTimeMillis());
+}
+
+// the values in the tm structure contain the local time
+wxDateTime& wxDateTime::Set(const struct tm& tm)
+{
+ struct tm tm2(tm);
+ time_t timet = mktime(&tm2);
+
+ if ( timet == (time_t)-1 )
+ {
+ // mktime() rather unintuitively fails for Jan 1, 1970 if the hour is
+ // less than timezone - try to make it work for this case
+ if ( tm2.tm_year == 70 && tm2.tm_mon == 0 && tm2.tm_mday == 1 )
+ {
+ return Set((time_t)(
+ GetTimeZone() +
+ tm2.tm_hour * MIN_PER_HOUR * SEC_PER_MIN +
+ tm2.tm_min * SEC_PER_MIN +
+ tm2.tm_sec));
+ }
+
+ wxFAIL_MSG( wxT("mktime() failed") );
+
+ *this = wxInvalidDateTime;
+
+ return *this;
+ }
+ else
+ {
+ return Set(timet);
+ }
+}
+
+wxDateTime& wxDateTime::Set(wxDateTime_t hour,
+ wxDateTime_t minute,
+ wxDateTime_t second,
+ wxDateTime_t millisec)
+{
+ // we allow seconds to be 61 to account for the leap seconds, even if we
+ // don't use them really
+ wxDATETIME_CHECK( hour < 24 &&
+ second < 62 &&
+ minute < 60 &&
+ millisec < 1000,
+ wxT("Invalid time in wxDateTime::Set()") );
+
+ // get the current date from system
+ struct tm tmstruct;
+ struct tm *tm = GetTmNow(&tmstruct);
+
+ wxDATETIME_CHECK( tm, wxT("wxLocaltime_r() failed") );
+
+ // make a copy so it isn't clobbered by the call to mktime() below
+ struct tm tm1(*tm);
+
+ // adjust the time
+ tm1.tm_hour = hour;
+ tm1.tm_min = minute;
+ tm1.tm_sec = second;
+
+ // and the DST in case it changes on this date
+ struct tm tm2(tm1);
+ mktime(&tm2);
+ if ( tm2.tm_isdst != tm1.tm_isdst )
+ tm1.tm_isdst = tm2.tm_isdst;
+
+ (void)Set(tm1);
+
+ // and finally adjust milliseconds
+ return SetMillisecond(millisec);
+}
+
+wxDateTime& wxDateTime::Set(wxDateTime_t day,
+ Month month,
+ int year,
+ wxDateTime_t hour,
+ wxDateTime_t minute,
+ wxDateTime_t second,
+ wxDateTime_t millisec)
+{
+ wxDATETIME_CHECK( hour < 24 &&
+ second < 62 &&
+ minute < 60 &&
+ millisec < 1000,
+ wxT("Invalid time in wxDateTime::Set()") );
+
+ ReplaceDefaultYearMonthWithCurrent(&year, &month);
+
+ wxDATETIME_CHECK( (0 < day) && (day <= GetNumberOfDays(month, year)),
+ wxT("Invalid date in wxDateTime::Set()") );