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:
Vadim Zeitlin
2005-08-28 13:06:36 +00:00
parent 5378558e5c
commit d26adb9df7
5 changed files with 114 additions and 59 deletions

View File

@@ -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):

View File

@@ -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}.

View File

@@ -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
// ----------------------------------------------------------------------------

View File

@@ -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;
}

View File

@@ -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