diff --git a/src/corelib/time/qtimezone.cpp b/src/corelib/time/qtimezone.cpp index 8f8d734178..f5e105b831 100644 --- a/src/corelib/time/qtimezone.cpp +++ b/src/corelib/time/qtimezone.cpp @@ -177,7 +177,7 @@ Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz); A default UTC time zone backend is provided which is always available when feature \c timezone is enabled. This provides a set of generic Offset From - UTC time zones in the range UTC-14:00 to UTC+14:00. These time zones can be + UTC time zones in the range UTC-16:00 to UTC+16:00. These time zones can be created using either the standard ISO format names, such as "UTC+00:00", as listed by availableTimeZoneIds(), or using a name of similar form in combination with the number of offset seconds. @@ -258,13 +258,27 @@ Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz); This enumeration provides constants bounding the range of plausible timezone offsets from UTC, measured in seconds. - Sane UTC offsets range from -14 to +14 hours. - No known zone has offset > 12 hrs West of Greenwich (Baker Island, USA). - No known zone has offset > 14 hrs East of Greenwich (Kiritimati, Christmas Island, Kiribati). + + Sane modern zones' UTC offsets range from -14 to +12 hours. + No known modern zone has offset > 12 hrs West of Greenwich (Baker Island, USA). + No known modern zone has offset > 14 hrs East of Greenwich + (Kiritimati, Christmas Island, Kiribati). Note that there are zones whose offsets differ by more than a day. - \value MinUtcOffsetSecs -14 * 3600, - \value MaxUtcOffsetSecs +14 * 3600 + Historically, before 1867, when Russia sold Alaska to America, Alaska used the + same date as Russia, so had offsets over 15 hours East of Greenwich. + Earlier still, until 1844, The Philippines (then controlled by Spain) used the + same date as Spain's American holdings, so had offsets close to 16 hours West + of Greenwich. + Each made its one-day transition to cross the international date line while + using local solar mean time, before adopting a unified time-zone, so the + offsets within their territories were variable. + As a result, The Philippines might have exceeded 16 hours as offset at the + extremities of its territory, but no modern zone's representative location was + at such an extremity. + + \value MinUtcOffsetSecs -16 * 3600, + \value MaxUtcOffsetSecs +16 * 3600 */ #if QT_CONFIG(timezone) @@ -468,7 +482,7 @@ QTimeZone::QTimeZone(const QByteArray &ianaId) /*! Creates a time zone instance with the given offset, \a offsetSeconds, from UTC. - The \a offsetSeconds from UTC must be in the range -14 hours to +14 hours + The \a offsetSeconds from UTC must be in the range -16 hours to +16 hours otherwise an invalid time zone will be returned. This constructor is only available when feature \c timezone is enabled. The @@ -495,7 +509,7 @@ QTimeZone::QTimeZone(int offsetSeconds) The \a ianaId must not be one of the available system IDs returned by availableTimeZoneIds(). The \a offsetSeconds from UTC must be in the range - -14 hours to +14 hours. + -16 hours to +16 hours. If the custom time zone does not have a specific territory then set it to the default value of QLocale::AnyTerritory. @@ -605,10 +619,10 @@ QTimeZone QTimeZone::asBackendZone() const Returns a time representation at a fixed \a offset, in seconds, ahead of UTC. - The \a offset from UTC must be in the range -14 hours to +14 hours otherwise an - invalid time zone will be returned. The returned QTimeZone is a lightweight - time representation, not a time zone (backed by system-supplied or standard - data). + The \a offset from UTC must be in the range -16 hours to +16 hours otherwise + an invalid time zone will be returned. The returned QTimeZone is a + lightweight time representation, not a time zone (backed by system-supplied + or standard data). If the offset is 0, the \l timeSpec() of the returned instance will be Qt::UTC. Otherwise, if \a offset is valid, timeSpec() is diff --git a/src/corelib/time/qtimezone.h b/src/corelib/time/qtimezone.h index 273bcc7b1c..7dd2ba4cf0 100644 --- a/src/corelib/time/qtimezone.h +++ b/src/corelib/time/qtimezone.h @@ -82,12 +82,14 @@ class Q_CORE_EXPORT QTimeZone QTimeZone(ShortData sd) : d(sd) {} public: - // Sane UTC offsets range from -14 to +14 hours: + // Sane UTC offsets range from -16 to +16 hours: enum { - // No known zone > 12 hrs West of Greenwich (Baker Island, USA) - MinUtcOffsetSecs = -14 * 3600, - // No known zone > 14 hrs East of Greenwich (Kiritimati, Christmas Island, Kiribati) - MaxUtcOffsetSecs = +14 * 3600 + // No known modern zone > 12 hrs West of Greenwich. + // Until 1844, Asia/Manila (in The Philippines) was at 15:56 West. + MinUtcOffsetSecs = -16 * 3600, + // No known modern zone > 14 hrs East of Greenwich. + // Until 1867, America/Metlakatla (in Alaska) was at 15:13:42 East. + MaxUtcOffsetSecs = +16 * 3600 }; enum Initialization { LocalTime, UTC }; diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp index 43f1fea935..8871add25d 100644 --- a/src/corelib/time/qtimezoneprivate.cpp +++ b/src/corelib/time/qtimezoneprivate.cpp @@ -182,28 +182,28 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs, /* We need a UTC time at which to ask for the offset, in order to be able to - add that offset to forLocalMSecs, to get the UTC time we - need. Fortunately, no time-zone offset is more than 14 hours; and DST - transitions happen (much) more than thirty-two hours apart. So sampling - offset sixteen hours each side gives us information we can be sure + add that offset to forLocalMSecs, to get the UTC time we need. + Fortunately, all time-zone offsets have been less than 17 hours; and DST + transitions happen (much) more than thirty-four hours apart. So sampling + offset seventeen hours each side gives us information we can be sure brackets the correct time and at most one DST transition. */ - std::integral_constant sixteenHoursInMSecs; - static_assert(-sixteenHoursInMSecs / 1000 < QTimeZone::MinUtcOffsetSecs - && sixteenHoursInMSecs / 1000 > QTimeZone::MaxUtcOffsetSecs); + std::integral_constant seventeenHoursInMSecs; + static_assert(-seventeenHoursInMSecs / 1000 < QTimeZone::MinUtcOffsetSecs + && seventeenHoursInMSecs / 1000 > QTimeZone::MaxUtcOffsetSecs); qint64 millis; // Clip the bracketing times to the bounds of the supported range. Exclude // minMSecs(), because at least one backend (Windows) uses it for a // start-of-time fake transition, that we want previousTransition() to find. const qint64 recent = - sub_overflow(forLocalMSecs, sixteenHoursInMSecs, &millis) || millis <= minMSecs() + sub_overflow(forLocalMSecs, seventeenHoursInMSecs, &millis) || millis <= minMSecs() ? minMSecs() + 1 : millis; // Necessarily <= forLocalMSecs + 2. // (Given that minMSecs() is std::numeric_limits::min() + 1.) const qint64 imminent = - add_overflow(forLocalMSecs, sixteenHoursInMSecs, &millis) + add_overflow(forLocalMSecs, seventeenHoursInMSecs, &millis) ? maxMSecs() : millis; // Necessarily >= forLocalMSecs // At most one of those was clipped to its boundary value: - Q_ASSERT(recent < imminent && sixteenHoursInMSecs < imminent - recent + 2); + Q_ASSERT(recent < imminent && seventeenHoursInMSecs < imminent - recent + 2); /* Offsets are Local - UTC, positive to the east of Greenwich, negative to the west; DST offset always exceeds standard offset, when DST applies. diff --git a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp index b63e506ad2..da1d3b4e76 100644 --- a/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp +++ b/tests/auto/corelib/time/qtimezone/tst_qtimezone.cpp @@ -507,7 +507,7 @@ void tst_QTimeZone::asBackendZone() void tst_QTimeZone::systemZone() { const QTimeZone zone = QTimeZone::systemTimeZone(); - QVERIFY(zone.isValid()); + QVERIFY2(zone.isValid(), "Invalid system zone setting, tests are doomed."); QCOMPARE(zone.id(), QTimeZone::systemTimeZoneId()); QCOMPARE(zone, QTimeZone(QTimeZone::systemTimeZoneId())); // Check it behaves the same as local-time: @@ -1162,9 +1162,9 @@ void tst_QTimeZone::utcTest() QCOMPARE(tz.standardTimeOffset(now), 36000); QCOMPARE(tz.daylightTimeOffset(now), 0); - // Test invalid UTC offset, must be in range -14 to +14 hours - int min = -14*60*60; - int max = 14*60*60; + // Test validity range of UTC offsets: + int min = int(QTimeZone::MinUtcOffsetSecs); + int max = int(QTimeZone::MaxUtcOffsetSecs); QCOMPARE(QTimeZone(min - 1).isValid(), false); QCOMPARE(QTimeZone(min).isValid(), true); QCOMPARE(QTimeZone(min + 1).isValid(), true);