Fixed several bugs in wxDateTime timezone handling:
- ToTimezone() and MakeTimezone() now work as expected - added and documented FromTimezone() and MakeFromTimezone() - Set(double jdn) interprets jdn always in UTC - updated ParseRfc822Date() timezone handling - removed workarounds for old bugs from the test git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@35334 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -16,6 +16,7 @@ All:
|
||||
- Fixed compilation with IBM xlC compiler.
|
||||
- wxABI_VERSION, see 'Backward Compatibility' topic overview in the manual.
|
||||
- Added wxLongLong::ToDouble()
|
||||
- Added wxDateTime::[Make]FromTimezone(), fixed several TZ-related bugs
|
||||
|
||||
All (GUI):
|
||||
|
||||
|
@@ -406,10 +406,12 @@ provided. You can construct a wxDateTime object from a
|
||||
Please see the \helpref{time zone overview}{tdatetimezones} for more
|
||||
information about time zones. Normally, these functions should be rarely used.
|
||||
|
||||
\helpref{FromTimezone}{wxdatetimefromtimezone}\\
|
||||
\helpref{ToTimezone}{wxdatetimetotimezone}\\
|
||||
\helpref{MakeTimezone}{wxdatetimemaketimezone}\\
|
||||
\helpref{ToGMT}{wxdatetimetogmt}\\
|
||||
\helpref{MakeGMT}{wxdatetimemakegmt}\\
|
||||
\helpref{MakeFromTimezone}{wxdatetimemakefromtimezone}\\
|
||||
\helpref{ToUTC}{wxdatetimetoutc}\\
|
||||
\helpref{MakeUTC}{wxdatetimemakeutc}\\
|
||||
\helpref{GetBeginDST}{wxdatetimegetbegindst}\\
|
||||
\helpref{GetEndDST}{wxdatetimegetenddst}\\
|
||||
\helpref{IsDST}{wxdatetimeisdst}
|
||||
@@ -1461,6 +1463,16 @@ year 1 is Rata Die day 1.
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%% timezone and DST %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
\membersection{wxDateTime::FromTimezone}\label{wxdatetimefromtimezone}
|
||||
|
||||
\constfunc{wxDateTime}{FromTimezone}{\param{const TimeZone\& }{tz}, \param{bool }{noDST = false}}
|
||||
|
||||
Transform the date from the given time zone to the local one. If {\it noDST} is
|
||||
{\tt true}, no DST adjustments will be made.
|
||||
|
||||
Returns the date in the local time zone.
|
||||
|
||||
|
||||
\membersection{wxDateTime::ToTimezone}\label{wxdatetimetotimezone}
|
||||
|
||||
\constfunc{wxDateTime}{ToTimezone}{\param{const TimeZone\& }{tz}, \param{bool }{noDST = false}}
|
||||
@@ -1479,17 +1491,25 @@ Modifies the object in place to represent the date in another time zone. If
|
||||
{\it noDST} is {\tt true}, no DST adjustments will be made.
|
||||
|
||||
|
||||
\membersection{wxDateTime::ToGMT}\label{wxdatetimetogmt}
|
||||
\membersection{wxDateTime::MakeFromTimezone}\label{wxdatetimemakefromtimezone}
|
||||
|
||||
\constfunc{wxDateTime}{ToGMT}{\param{bool }{noDST = false}}
|
||||
\func{wxDateTime\&}{MakeFromTimezone}{\param{const TimeZone\& }{tz}, \param{bool }{noDST = false}}
|
||||
|
||||
Same as \helpref{FromTimezone}{wxdatetimefromtimezone} but modifies the object
|
||||
in place.
|
||||
|
||||
|
||||
\membersection{wxDateTime::ToUTC}\label{wxdatetimetoutc}
|
||||
|
||||
\constfunc{wxDateTime}{ToUTC}{\param{bool }{noDST = false}}
|
||||
|
||||
This is the same as calling \helpref{ToTimezone}{wxdatetimetotimezone} with
|
||||
the argument {\tt GMT0}.
|
||||
|
||||
|
||||
\membersection{wxDateTime::MakeGMT}\label{wxdatetimemakegmt}
|
||||
\membersection{wxDateTime::MakeUTC}\label{wxdatetimemakeutc}
|
||||
|
||||
\func{wxDateTime\&}{MakeGMT}{\param{bool }{noDST = false}}
|
||||
\func{wxDateTime\&}{MakeUTC}{\param{bool }{noDST = false}}
|
||||
|
||||
This is the same as calling \helpref{MakeTimezone}{wxdatetimemaketimezone} with
|
||||
the argument {\tt GMT0}.
|
||||
|
@@ -757,26 +757,42 @@ public:
|
||||
// religious holidays (Easter...) or moon/solar eclipses? Some
|
||||
// algorithms can be found in the calendar FAQ
|
||||
|
||||
// timezone stuff: a wxDateTime object constructed using given
|
||||
// day/month/year/hour/min/sec values correspond to this moment in local
|
||||
// time. Using the functions below, it may be converted to another time
|
||||
// zone (for example, the Unix epoch is wxDateTime(1, Jan, 1970).ToGMT())
|
||||
|
||||
// Timezone stuff: a wxDateTime object constructed using given
|
||||
// day/month/year/hour/min/sec values is interpreted as this moment in
|
||||
// local time. Using the functions below, it may be converted to another
|
||||
// time zone (e.g., the Unix epoch is wxDateTime(1, Jan, 1970).ToGMT()).
|
||||
//
|
||||
// these functions try to handle DST internally, but there is no magical
|
||||
// These functions try to handle DST internally, but there is no magical
|
||||
// way to know all rules for it in all countries in the world, so if the
|
||||
// program can handle it itself (or doesn't want to handle it at all for
|
||||
// whatever reason), the DST handling can be disabled with noDST.
|
||||
//
|
||||
// Converting to the local time zone doesn't do anything.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// transform to any given timezone
|
||||
inline wxDateTime ToTimezone(const TimeZone& tz, bool noDST = false) const;
|
||||
wxDateTime& MakeTimezone(const TimeZone& tz, bool noDST = false);
|
||||
|
||||
// transform to GMT/UTC
|
||||
wxDateTime ToGMT(bool noDST = false) const { return ToTimezone(GMT0, noDST); }
|
||||
wxDateTime& MakeGMT(bool noDST = false) { return MakeTimezone(GMT0, noDST); }
|
||||
#if wxABI_VERSION >= 20602
|
||||
// interpret current value as being in another timezone and transform
|
||||
// it to local one
|
||||
inline wxDateTime FromTimezone(const TimeZone& tz, bool noDST = false) const;
|
||||
wxDateTime& MakeFromTimezone(const TimeZone& tz, bool noDST = false);
|
||||
#endif // ABI >= 2.6.2
|
||||
|
||||
// transform to/from GMT/UTC
|
||||
wxDateTime ToUTC(bool noDST = false) const { return ToTimezone(UTC, noDST); }
|
||||
wxDateTime& MakeUTC(bool noDST = false) { return MakeTimezone(UTC, noDST); }
|
||||
|
||||
wxDateTime ToGMT(bool noDST = false) const { return ToUTC(noDST); }
|
||||
wxDateTime& MakeGMT(bool noDST = false) { return MakeUTC(noDST); }
|
||||
|
||||
#if wxABI_VERSION >= 20602
|
||||
wxDateTime FromUTC(bool noDST = false) const
|
||||
{ return FromTimezone(UTC, noDST); }
|
||||
wxDateTime& MakeFromUTC(bool noDST = false)
|
||||
{ return MakeFromTimezone(UTC, noDST); }
|
||||
#endif // ABI >= 2.6.2
|
||||
|
||||
// is daylight savings time in effect at this moment according to the
|
||||
// rules of the specified country?
|
||||
@@ -785,6 +801,7 @@ public:
|
||||
// the information is not available (this is compatible with ANSI C)
|
||||
int IsDST(Country country = Country_Default) const;
|
||||
|
||||
|
||||
// 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
|
||||
@@ -1839,12 +1856,22 @@ inline wxDateTime& wxDateTime::operator+=(const wxDateSpan& diff)
|
||||
// wxDateTime and timezones
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
inline wxDateTime wxDateTime::ToTimezone(const wxDateTime::TimeZone& tz,
|
||||
bool noDST) const
|
||||
inline wxDateTime
|
||||
wxDateTime::ToTimezone(const wxDateTime::TimeZone& tz, bool noDST) const
|
||||
{
|
||||
MODIFY_AND_RETURN( MakeTimezone(tz, noDST) );
|
||||
}
|
||||
|
||||
#if wxABI_VERSION >= 20602
|
||||
|
||||
inline wxDateTime
|
||||
wxDateTime::FromTimezone(const wxDateTime::TimeZone& tz, bool noDST) const
|
||||
{
|
||||
MODIFY_AND_RETURN( MakeFromTimezone(tz, noDST) );
|
||||
}
|
||||
|
||||
#endif // ABI >= 2.6.2
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxTimeSpan construction
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@@ -692,7 +692,7 @@ wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz)
|
||||
|
||||
case wxDateTime::A_CST:
|
||||
// Central Standard Time in use in Australia = UTC + 9.5
|
||||
m_offset = 60l*(9*60 + 30);
|
||||
m_offset = 60l*(9*MIN_PER_HOUR + MIN_PER_HOUR/2);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1405,20 +1405,9 @@ wxDateTime& wxDateTime::Set(double jdn)
|
||||
// EPOCH_JDN + 0.5
|
||||
jdn -= EPOCH_JDN + 0.5;
|
||||
|
||||
jdn *= MILLISECONDS_PER_DAY;
|
||||
m_time.Assign(jdn*MILLISECONDS_PER_DAY);
|
||||
|
||||
m_time.Assign(jdn);
|
||||
|
||||
// JDNs always suppose an UTC date, so bring it back to local time zone
|
||||
// (also see GetJulianDayNumber() implementation)
|
||||
long tzDiff = GetTimeZone();
|
||||
if ( IsDST() == 1 )
|
||||
{
|
||||
// FIXME: again, we suppose that DST is always one hour
|
||||
tzDiff -= 3600;
|
||||
}
|
||||
|
||||
m_time += tzDiff*1000; // tzDiff is in seconds
|
||||
// JDNs always are in UTC, so we don't need any adjustments for time zone
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -1637,14 +1626,14 @@ wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const
|
||||
timeOnly -= tm.msec;
|
||||
timeOnly /= 1000; // now we have time in seconds
|
||||
|
||||
tm.sec = (wxDateTime_t)(timeOnly % 60);
|
||||
tm.sec = (wxDateTime_t)(timeOnly % SEC_PER_MIN);
|
||||
timeOnly -= tm.sec;
|
||||
timeOnly /= 60; // now we have time in minutes
|
||||
timeOnly /= SEC_PER_MIN; // now we have time in minutes
|
||||
|
||||
tm.min = (wxDateTime_t)(timeOnly % 60);
|
||||
tm.min = (wxDateTime_t)(timeOnly % MIN_PER_HOUR);
|
||||
timeOnly -= tm.min;
|
||||
|
||||
tm.hour = (wxDateTime_t)(timeOnly / 60);
|
||||
tm.hour = (wxDateTime_t)(timeOnly / MIN_PER_HOUR);
|
||||
|
||||
return tm;
|
||||
}
|
||||
@@ -2110,16 +2099,7 @@ wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday)
|
||||
|
||||
double wxDateTime::GetJulianDayNumber() const
|
||||
{
|
||||
// JDN are always expressed for the UTC dates
|
||||
Tm tm(ToTimezone(UTC).GetTm(UTC));
|
||||
|
||||
double result = GetTruncatedJDN(tm.mday, tm.mon, tm.year);
|
||||
|
||||
// add the part GetTruncatedJDN() neglected
|
||||
result += 0.5;
|
||||
|
||||
// and now add the time: 86400 sec = 1 JDN
|
||||
return result + ((double)(60*(60*tm.hour + tm.min) + tm.sec)) / 86400;
|
||||
return m_time.ToDouble() / MILLISECONDS_PER_DAY + EPOCH_JDN + 0.5;
|
||||
}
|
||||
|
||||
double wxDateTime::GetRataDie() const
|
||||
@@ -2173,6 +2153,21 @@ wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz, bool noDST)
|
||||
secDiff -= 3600;
|
||||
}
|
||||
|
||||
return Add(wxTimeSpan::Seconds(secDiff));
|
||||
}
|
||||
|
||||
wxDateTime& wxDateTime::MakeFromTimezone(const TimeZone& tz, bool noDST)
|
||||
{
|
||||
long secDiff = GetTimeZone() + tz.GetOffset();
|
||||
|
||||
// we need to know whether DST is or not in effect for this date unless
|
||||
// the test disabled by the caller
|
||||
if ( !noDST && (IsDST() == 1) )
|
||||
{
|
||||
// FIXME we assume that the DST is always shifted by 1 hour
|
||||
secDiff -= 3600;
|
||||
}
|
||||
|
||||
return Subtract(wxTimeSpan::Seconds(secDiff));
|
||||
}
|
||||
|
||||
@@ -2771,7 +2766,7 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
|
||||
}
|
||||
|
||||
// hours
|
||||
offset = 60*(10*(*p - _T('0')) + (*(p + 1) - _T('0')));
|
||||
offset = MIN_PER_HOUR*(10*(*p - _T('0')) + (*(p + 1) - _T('0')));
|
||||
|
||||
p += 2;
|
||||
|
||||
@@ -2851,12 +2846,12 @@ const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date)
|
||||
}
|
||||
|
||||
// make it minutes
|
||||
offset *= 60;
|
||||
offset *= MIN_PER_HOUR;
|
||||
}
|
||||
|
||||
// the spec was correct
|
||||
// the spec was correct, construct the date from the values we found
|
||||
Set(day, mon, year, hour, min, sec);
|
||||
MakeTimezone((wxDateTime_t)(60*offset));
|
||||
MakeFromTimezone(offset*SEC_PER_MIN);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
@@ -257,7 +257,9 @@ void DateTimeTestCase::TestTimeJDN()
|
||||
{
|
||||
const Date& d = testDates[n];
|
||||
wxDateTime dt(d.day, d.month, d.year, d.hour, d.min, d.sec);
|
||||
double jdn = dt.GetJulianDayNumber();
|
||||
|
||||
// JDNs must be computed for UTC times
|
||||
double jdn = dt.FromUTC().GetJulianDayNumber();
|
||||
|
||||
CPPUNIT_ASSERT( jdn == d.jdn );
|
||||
|
||||
@@ -662,7 +664,7 @@ void DateTimeTestCase::TestTimeTicks()
|
||||
long ticks = (dt.GetValue() / 1000).ToLong();
|
||||
CPPUNIT_ASSERT( ticks == d.ticks );
|
||||
|
||||
dt = d.DT().ToTimezone(wxDateTime::GMT0);
|
||||
dt = d.DT().FromTimezone(wxDateTime::GMT0);
|
||||
ticks = (dt.GetValue() / 1000).ToLong();
|
||||
CPPUNIT_ASSERT( ticks == d.gmticks );
|
||||
}
|
||||
@@ -674,12 +676,25 @@ void DateTimeTestCase::TestTimeParse()
|
||||
static const struct ParseTestData
|
||||
{
|
||||
const wxChar *format;
|
||||
Date date;
|
||||
Date date; // NB: this should be in UTC
|
||||
bool good;
|
||||
} parseTestDates[] =
|
||||
{
|
||||
{ _T("Sat, 18 Dec 1999 00:46:40 +0100"), { 18, wxDateTime::Dec, 1999, 00, 46, 40, 0.0, wxDateTime::Inv_WeekDay, 0, 0 }, true },
|
||||
{ _T("Wed, 1 Dec 1999 05:17:20 +0300"), { 1, wxDateTime::Dec, 1999, 03, 17, 20, 0.0, wxDateTime::Inv_WeekDay, 0, 0 }, true },
|
||||
{
|
||||
_T("Sat, 18 Dec 1999 00:46:40 +0100"),
|
||||
{ 17, wxDateTime::Dec, 1999, 23, 46, 40, 0.0, wxDateTime::Inv_WeekDay, 0, 0 },
|
||||
true
|
||||
},
|
||||
{
|
||||
_T("Wed, 1 Dec 1999 05:17:20 +0300"),
|
||||
{ 1, wxDateTime::Dec, 1999, 2, 17, 20, 0.0, wxDateTime::Inv_WeekDay, 0, 0 },
|
||||
true
|
||||
},
|
||||
{
|
||||
_T("Sun, 28 Aug 2005 03:31:30 +0200"),
|
||||
{ 28, wxDateTime::Aug, 2005, 1, 31, 30, 0.0, wxDateTime::Inv_WeekDay, 0, 0 },
|
||||
true
|
||||
},
|
||||
};
|
||||
|
||||
for ( size_t n = 0; n < WXSIZEOF(parseTestDates); n++ )
|
||||
@@ -691,10 +706,7 @@ void DateTimeTestCase::TestTimeParse()
|
||||
{
|
||||
CPPUNIT_ASSERT( parseTestDates[n].good );
|
||||
|
||||
wxDateTime dtReal = parseTestDates[n].date.DT();
|
||||
//RN: We need this because the tests are based on
|
||||
//a non-GMT time zone
|
||||
dtReal.MakeTimezone(wxDateTime::WEST, true);
|
||||
wxDateTime dtReal = parseTestDates[n].date.DT().FromUTC();
|
||||
CPPUNIT_ASSERT( dt == dtReal );
|
||||
}
|
||||
else // failed to parse
|
||||
|
Reference in New Issue
Block a user