+ // ... and call strftime()
+ return CallStrftime(flags == Name_Abbr ? wxT("%a") : wxT("%A"), &tm);
+#else // !wxHAS_STRFTIME
+ return GetEnglishWeekDayName(wday, flags);
+#endif // wxHAS_STRFTIME/!wxHAS_STRFTIME
+}
+
+/* static */
+void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm)
+{
+ tm tm;
+ InitTm(tm);
+ wxChar buffer[64];
+ // @Note: Do not call 'CallStrftime' here! CallStrftime checks the return code
+ // and causes an assertion failed if the buffer is to small (which is good) - OR -
+ // if strftime does not return anything because the format string is invalid - OR -
+ // if there are no 'am' / 'pm' tokens defined for the current locale (which is not good).
+ // wxDateTime::ParseTime will try several different formats to parse the time.
+ // As a result, GetAmPmStrings might get called, even if the current locale
+ // does not define any 'am' / 'pm' tokens. In this case, wxStrftime would
+ // assert, even though it is a perfectly legal use.
+ if ( am )
+ {
+ if (wxStrftime(buffer, WXSIZEOF(buffer), wxT("%p"), &tm) > 0)
+ *am = wxString(buffer);
+ else
+ *am = wxString();
+ }
+ if ( pm )
+ {
+ tm.tm_hour = 13;
+ if (wxStrftime(buffer, WXSIZEOF(buffer), wxT("%p"), &tm) > 0)
+ *pm = wxString(buffer);
+ else
+ *pm = wxString();
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// Country stuff: date calculations depend on the country (DST, work days,
+// ...), so we need to know which rules to follow.
+// ----------------------------------------------------------------------------
+
+/* static */
+wxDateTime::Country wxDateTime::GetCountry()
+{
+ // TODO use LOCALE_ICOUNTRY setting under Win32
+#ifndef __WXWINCE__
+ if ( ms_country == Country_Unknown )
+ {
+ // try to guess from the time zone name
+ time_t t = time(NULL);
+ struct tm tmstruct;
+ struct tm *tm = wxLocaltime_r(&t, &tmstruct);
+
+ wxString tz = CallStrftime(wxT("%Z"), tm);
+ if ( tz == wxT("WET") || tz == wxT("WEST") )
+ {
+ ms_country = UK;
+ }
+ else if ( tz == wxT("CET") || tz == wxT("CEST") )
+ {
+ ms_country = Country_EEC;
+ }
+ else if ( tz == wxT("MSK") || tz == wxT("MSD") )
+ {
+ ms_country = Russia;
+ }
+ else if ( tz == wxT("AST") || tz == wxT("ADT") ||
+ tz == wxT("EST") || tz == wxT("EDT") ||
+ tz == wxT("CST") || tz == wxT("CDT") ||
+ tz == wxT("MST") || tz == wxT("MDT") ||
+ tz == wxT("PST") || tz == wxT("PDT") )
+ {
+ ms_country = USA;
+ }
+ else
+ {
+ // well, choose a default one
+ ms_country = USA;
+ }
+ }
+#else // __WXWINCE__
+ ms_country = USA;
+#endif // !__WXWINCE__/__WXWINCE__
+
+ 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);