Add a distant-future local-time-type to tst_QDateTime

It turns out glibc stops varying DST changes past where a 32-bit
signed day-count from 1970 reaches (which, all things considered, can
hardly be called a bug, for all that it's ...), at odds with QTZ's
extrapolations from the current IANA DB rules. As the last date QDT
can represent happens to be in the opposite side of everyone's DST
from the one that leaves zones in, this lead to the 2038
local-time-type not reliably being useful for predicting the max-date
behavior. So add a distant-future time-type that probes beyond glibc's
cut-off, and have relevant tests check that instead of the 2038 one.

Change-Id: If4e244d80fe2447da3bb9d5c406808c6c22c0a73
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2023-05-03 18:02:31 +02:00
parent 89febde32f
commit b1379d34dd

View File

@ -159,7 +159,7 @@ private:
of UTC is it ?" So the various LocalTimeType members may be different.
*/
enum LocalTimeType { LocalTimeIsUtc = 0, LocalTimeAheadOfUtc = 1, LocalTimeBehindUtc = -1};
const LocalTimeType solarMeanType, epochTimeType, futureTimeType;
const LocalTimeType solarMeanType, epochTimeType, futureTimeType, distantTimeType;
static constexpr auto UTC = QTimeZone::UTC;
static constexpr qint64 epochJd = Q_INT64_C(2440588);
int preZoneFix;
@ -211,7 +211,13 @@ tst_QDateTime::tst_QDateTime() :
solarMeanType(timeTypeFor(-62091, -61910)), // 1800
epochTimeType(timeTypeFor(0, 181)), // 1970
// Use stable future, to which current rule is extrapolated, as surrogate for variable current:
futureTimeType(timeTypeFor(24837, 25018)) // 2038
futureTimeType(timeTypeFor(24837, 25018)), // 2038
// The glibc functions only handle DST as far as a 32-bit signed day-count
// from some date in 1970 reaches; the future extreme of that is in the
// second half of 5'881'580 CE. Beyond 5'881'581 CE it treats all zones as
// being in their January state, regardless of time of year. So use data for
// this later year for tests of QDateTime's upper bound.
distantTimeType(timeTypeFor(0x800000adLL, 0x80000162LL))
{
/*
Due to some jurisdictions changing their zones and rules, it's possible
@ -850,7 +856,7 @@ void tst_QDateTime::setMSecsSinceEpoch()
// Check overflow; only robust if local time is the same at epoch as relevant bound.
// See setting of LocalTimeType values for details.
if (epochTimeType == LocalTimeAheadOfUtc
? futureTimeType == LocalTimeAheadOfUtc && msecs == Bound::max()
? distantTimeType == LocalTimeAheadOfUtc && msecs == Bound::max()
: (solarMeanType == LocalTimeBehindUtc && msecs == Bound::min()
&& epochTimeType == LocalTimeBehindUtc)) {
QDateTime curt = QDate(1970, 1, 1).startOfDay(); // initially in short-form
@ -875,7 +881,7 @@ void tst_QDateTime::fromMSecsSinceEpoch()
// actually west of Greenwich but (e.g. Europe/Madrid) our zone claims east,
// "min" can also overflow (case only caught if local time is CET).
const bool localOverflow =
(futureTimeType == LocalTimeAheadOfUtc && (msecs == Bound::max() || preZoneFix < -3600))
(distantTimeType == LocalTimeAheadOfUtc && (msecs == Bound::max() || preZoneFix < -3600))
|| (solarMeanType == LocalTimeBehindUtc && msecs == Bound::min());
if (!localOverflow) // Can fail if offset changes sign, e.g. Alaska, Philippines.
QCOMPARE(dtLocal, utc);