| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2021 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 | #include <QtTest/QtTest> | 
| 30 | #include <qtimezone.h> | 
| 31 | #include <private/qtimezoneprivate_p.h> | 
| 32 | #include <qlocale.h> | 
| 33 |  | 
| 34 | #if defined(Q_OS_WIN) && !QT_CONFIG(icu) | 
| 35 | #  define USING_WIN_TZ | 
| 36 | #endif | 
| 37 |  | 
| 38 | class tst_QTimeZone : public QObject | 
| 39 | { | 
| 40 |     Q_OBJECT | 
| 41 |  | 
| 42 | public: | 
| 43 |     tst_QTimeZone(); | 
| 44 |  | 
| 45 | private slots: | 
| 46 |     // Public class default system tests | 
| 47 |     void createTest(); | 
| 48 |     void nullTest(); | 
| 49 |     void systemZone(); | 
| 50 |     void dataStreamTest(); | 
| 51 |     void isTimeZoneIdAvailable(); | 
| 52 |     void availableTimeZoneIds(); | 
| 53 |     void utcOffsetId_data(); | 
| 54 |     void utcOffsetId(); | 
| 55 |     void specificTransition_data(); | 
| 56 |     void specificTransition(); | 
| 57 |     void transitionEachZone_data(); | 
| 58 |     void transitionEachZone(); | 
| 59 |     void checkOffset_data(); | 
| 60 |     void checkOffset(); | 
| 61 |     void stressTest(); | 
| 62 |     void windowsId(); | 
| 63 |     void isValidId_data(); | 
| 64 |     void isValidId(); | 
| 65 |     void malformed(); | 
| 66 |     // Backend tests | 
| 67 |     void utcTest(); | 
| 68 |     void icuTest(); | 
| 69 |     void tzTest(); | 
| 70 |     void macTest(); | 
| 71 |     void darwinTypes(); | 
| 72 |     void winTest(); | 
| 73 |  | 
| 74 | private: | 
| 75 |     void printTimeZone(const QTimeZone &tz); | 
| 76 | #ifdef QT_BUILD_INTERNAL | 
| 77 |     // Generic tests of privates, called by implementation-specific private tests: | 
| 78 |     void testCetPrivate(const QTimeZonePrivate &tzp); | 
| 79 |     void testEpochTranPrivate(const QTimeZonePrivate &tzp); | 
| 80 | #endif // QT_BUILD_INTERNAL | 
| 81 |     const bool debug; | 
| 82 | }; | 
| 83 |  | 
| 84 | tst_QTimeZone::tst_QTimeZone() | 
| 85 |     // Set to true to print debug output, test Display Names and run long stress tests | 
| 86 |     : debug(false) | 
| 87 | { | 
| 88 | } | 
| 89 |  | 
| 90 | void tst_QTimeZone::printTimeZone(const QTimeZone &tz) | 
| 91 | { | 
| 92 |     QDateTime now = QDateTime::currentDateTime(); | 
| 93 |     QDateTime jan = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC); | 
| 94 |     QDateTime jun = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC); | 
| 95 |     qDebug() << "" ; | 
| 96 |     qDebug() << "Time Zone               = "  << tz; | 
| 97 |     qDebug() << "" ; | 
| 98 |     qDebug() << "Is Valid                = "  << tz.isValid(); | 
| 99 |     qDebug() << "" ; | 
| 100 |     qDebug() << "Zone ID                 = "  << tz.id(); | 
| 101 |     qDebug() << "Country                 = "  << QLocale::countryToString(country: tz.country()); | 
| 102 |     qDebug() << "Comment                 = "  << tz.comment(); | 
| 103 |     qDebug() << "" ; | 
| 104 |     qDebug() << "Locale                  = "  << QLocale().name(); | 
| 105 |     qDebug() << "Name Long               = "  << tz.displayName(timeType: QTimeZone::StandardTime, nameType: QTimeZone::LongName); | 
| 106 |     qDebug() << "Name Short              = "  << tz.displayName(timeType: QTimeZone::StandardTime, nameType: QTimeZone::ShortName); | 
| 107 |     qDebug() << "Name Offset             = "  << tz.displayName(timeType: QTimeZone::StandardTime, nameType: QTimeZone::OffsetName); | 
| 108 |     qDebug() << "Name Long DST           = "  << tz.displayName(timeType: QTimeZone::DaylightTime, nameType: QTimeZone::LongName); | 
| 109 |     qDebug() << "Name Short DST          = "  << tz.displayName(timeType: QTimeZone::DaylightTime, nameType: QTimeZone::ShortName); | 
| 110 |     qDebug() << "Name Offset DST         = "  << tz.displayName(timeType: QTimeZone::DaylightTime, nameType: QTimeZone::OffsetName); | 
| 111 |     qDebug() << "Name Long Generic       = "  << tz.displayName(timeType: QTimeZone::GenericTime, nameType: QTimeZone::LongName); | 
| 112 |     qDebug() << "Name Short Generic      = "  << tz.displayName(timeType: QTimeZone::GenericTime, nameType: QTimeZone::ShortName); | 
| 113 |     qDebug() << "Name Offset Generic     = "  << tz.displayName(timeType: QTimeZone::GenericTime, nameType: QTimeZone::OffsetName); | 
| 114 |     qDebug() << "" ; | 
| 115 |     QLocale locale = QLocale(QStringLiteral("de_DE" )); | 
| 116 |     qDebug() << "Locale                  = "  << locale.name(); | 
| 117 |     qDebug() << "Name Long               = "  << tz.displayName(timeType: QTimeZone::StandardTime, nameType: QTimeZone::LongName, locale); | 
| 118 |     qDebug() << "Name Short              = "  << tz.displayName(timeType: QTimeZone::StandardTime, nameType: QTimeZone::ShortName, locale); | 
| 119 |     qDebug() << "Name Offset             = "  << tz.displayName(timeType: QTimeZone::StandardTime, nameType: QTimeZone::OffsetName, locale); | 
| 120 |     qDebug() << "Name Long DST           = "  << tz.displayName(timeType: QTimeZone::DaylightTime, nameType: QTimeZone::LongName,locale); | 
| 121 |     qDebug() << "Name Short DST          = "  << tz.displayName(timeType: QTimeZone::DaylightTime, nameType: QTimeZone::ShortName, locale); | 
| 122 |     qDebug() << "Name Offset DST         = "  << tz.displayName(timeType: QTimeZone::DaylightTime, nameType: QTimeZone::OffsetName, locale); | 
| 123 |     qDebug() << "Name Long Generic       = "  << tz.displayName(timeType: QTimeZone::GenericTime, nameType: QTimeZone::LongName, locale); | 
| 124 |     qDebug() << "Name Short Generic      = "  << tz.displayName(timeType: QTimeZone::GenericTime, nameType: QTimeZone::ShortName, locale); | 
| 125 |     qDebug() << "Name Offset Generic     = "  << tz.displayName(timeType: QTimeZone::GenericTime, nameType: QTimeZone::OffsetName, locale); | 
| 126 |     qDebug() << "" ; | 
| 127 |     qDebug() << "Abbreviation Now        = "  << tz.abbreviation(atDateTime: now); | 
| 128 |     qDebug() << "Abbreviation on 1 Jan   = "  << tz.abbreviation(atDateTime: jan); | 
| 129 |     qDebug() << "Abbreviation on 1 June  = "  << tz.abbreviation(atDateTime: jun); | 
| 130 |     qDebug() << "" ; | 
| 131 |     qDebug() << "Offset on 1 January     = "  << tz.offsetFromUtc(atDateTime: jan); | 
| 132 |     qDebug() << "Offset on 1 June        = "  << tz.offsetFromUtc(atDateTime: jun); | 
| 133 |     qDebug() << "Offset Now              = "  << tz.offsetFromUtc(atDateTime: now); | 
| 134 |     qDebug() << "" ; | 
| 135 |     qDebug() << "UTC Offset Now          = "  << tz.standardTimeOffset(atDateTime: now); | 
| 136 |     qDebug() << "UTC Offset on 1 January = "  << tz.standardTimeOffset(atDateTime: jan); | 
| 137 |     qDebug() << "UTC Offset on 1 June    = "  << tz.standardTimeOffset(atDateTime: jun); | 
| 138 |     qDebug() << "" ; | 
| 139 |     qDebug() << "DST Offset on 1 January = "  << tz.daylightTimeOffset(atDateTime: jan); | 
| 140 |     qDebug() << "DST Offset on 1 June    = "  << tz.daylightTimeOffset(atDateTime: jun); | 
| 141 |     qDebug() << "DST Offset Now          = "  << tz.daylightTimeOffset(atDateTime: now); | 
| 142 |     qDebug() << "" ; | 
| 143 |     qDebug() << "Has DST                 = "  << tz.hasDaylightTime(); | 
| 144 |     qDebug() << "Is DST Now              = "  << tz.isDaylightTime(atDateTime: now); | 
| 145 |     qDebug() << "Is DST on 1 January     = "  << tz.isDaylightTime(atDateTime: jan); | 
| 146 |     qDebug() << "Is DST on 1 June        = "  << tz.isDaylightTime(atDateTime: jun); | 
| 147 |     qDebug() << "" ; | 
| 148 |     qDebug() << "Has Transitions         = "  << tz.hasTransitions(); | 
| 149 |     qDebug() << "Transition after 1 Jan  = "  << tz.nextTransition(afterDateTime: jan).atUtc; | 
| 150 |     qDebug() << "Transition after 1 Jun  = "  << tz.nextTransition(afterDateTime: jun).atUtc; | 
| 151 |     qDebug() << "Transition before 1 Jan = "  << tz.previousTransition(beforeDateTime: jan).atUtc; | 
| 152 |     qDebug() << "Transition before 1 Jun = "  << tz.previousTransition(beforeDateTime: jun).atUtc; | 
| 153 |     qDebug() << "" ; | 
| 154 | } | 
| 155 |  | 
| 156 | void tst_QTimeZone::createTest() | 
| 157 | { | 
| 158 |     const QTimeZone tz("Pacific/Auckland" ); | 
| 159 |  | 
| 160 |     if (debug) | 
| 161 |         printTimeZone(tz); | 
| 162 |  | 
| 163 |     // If the tz is not valid then skip as is probably using the UTC backend which is tested later | 
| 164 |     if (!tz.isValid()) | 
| 165 |         QSKIP("System lacks zone used for test" ); // This returns. | 
| 166 |  | 
| 167 |     QCOMPARE(tz.id(), "Pacific/Auckland" ); | 
| 168 |     // Comparison tests: | 
| 169 |     const QTimeZone same("Pacific/Auckland" ); | 
| 170 |     QCOMPARE((tz == same), true); | 
| 171 |     QCOMPARE((tz != same), false); | 
| 172 |     const QTimeZone other("Australia/Sydney" ); | 
| 173 |     QCOMPARE((tz == other), false); | 
| 174 |     QCOMPARE((tz != other), true); | 
| 175 |  | 
| 176 |     QCOMPARE(tz.country(), QLocale::NewZealand); | 
| 177 |  | 
| 178 |     QDateTime jan = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC); | 
| 179 |     QDateTime jun = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC); | 
| 180 |     QDateTime janPrev = QDateTime(QDate(2011, 1, 1), QTime(0, 0, 0), Qt::UTC); | 
| 181 |  | 
| 182 |     QCOMPARE(tz.offsetFromUtc(jan), 13 * 3600); | 
| 183 |     QCOMPARE(tz.offsetFromUtc(jun), 12 * 3600); | 
| 184 |  | 
| 185 |     QCOMPARE(tz.standardTimeOffset(jan), 12 * 3600); | 
| 186 |     QCOMPARE(tz.standardTimeOffset(jun), 12 * 3600); | 
| 187 |  | 
| 188 |     QCOMPARE(tz.daylightTimeOffset(jan), 3600); | 
| 189 |     QCOMPARE(tz.daylightTimeOffset(jun), 0); | 
| 190 |  | 
| 191 |     QCOMPARE(tz.hasDaylightTime(), true); | 
| 192 |     QCOMPARE(tz.isDaylightTime(jan), true); | 
| 193 |     QCOMPARE(tz.isDaylightTime(jun), false); | 
| 194 |  | 
| 195 |     // Only test transitions if host system supports them | 
| 196 |     if (tz.hasTransitions()) { | 
| 197 |         QTimeZone::OffsetData tran = tz.nextTransition(afterDateTime: jan); | 
| 198 |         // 2012-04-01 03:00 NZDT, +13 -> +12 | 
| 199 |         QCOMPARE(tran.atUtc, | 
| 200 |                  QDateTime(QDate(2012, 4, 1), QTime(3, 0), Qt::OffsetFromUTC, 13 * 3600)); | 
| 201 |         QCOMPARE(tran.offsetFromUtc, 12 * 3600); | 
| 202 |         QCOMPARE(tran.standardTimeOffset, 12 * 3600); | 
| 203 |         QCOMPARE(tran.daylightTimeOffset, 0); | 
| 204 |  | 
| 205 |         tran = tz.nextTransition(afterDateTime: jun); | 
| 206 |         // 2012-09-30 02:00 NZST, +12 -> +13 | 
| 207 |         QCOMPARE(tran.atUtc, | 
| 208 |                  QDateTime(QDate(2012, 9, 30), QTime(2, 0), Qt::OffsetFromUTC, 12 * 3600)); | 
| 209 |         QCOMPARE(tran.offsetFromUtc, 13 * 3600); | 
| 210 |         QCOMPARE(tran.standardTimeOffset, 12 * 3600); | 
| 211 |         QCOMPARE(tran.daylightTimeOffset, 3600); | 
| 212 |  | 
| 213 |         tran = tz.previousTransition(beforeDateTime: jan); | 
| 214 |         // 2011-09-25 02:00 NZST, +12 -> +13 | 
| 215 |         QCOMPARE(tran.atUtc, | 
| 216 |                  QDateTime(QDate(2011, 9, 25), QTime(2, 0), Qt::OffsetFromUTC, 12 * 3600)); | 
| 217 |         QCOMPARE(tran.offsetFromUtc, 13 * 3600); | 
| 218 |         QCOMPARE(tran.standardTimeOffset, 12 * 3600); | 
| 219 |         QCOMPARE(tran.daylightTimeOffset, 3600); | 
| 220 |  | 
| 221 |         tran = tz.previousTransition(beforeDateTime: jun); | 
| 222 |         // 2012-04-01 03:00 NZDT, +13 -> +12 (again) | 
| 223 |         QCOMPARE(tran.atUtc, | 
| 224 |                  QDateTime(QDate(2012, 4, 1), QTime(3, 0), Qt::OffsetFromUTC, 13 * 3600)); | 
| 225 |         QCOMPARE(tran.offsetFromUtc, 12 * 3600); | 
| 226 |         QCOMPARE(tran.standardTimeOffset, 12 * 3600); | 
| 227 |         QCOMPARE(tran.daylightTimeOffset, 0); | 
| 228 |  | 
| 229 |         QTimeZone::OffsetDataList expected; | 
| 230 |         tran.atUtc = QDateTime(QDate(2011, 4, 3), QTime(2, 0), Qt::OffsetFromUTC, 13 * 3600); | 
| 231 |         tran.offsetFromUtc = 13 * 3600; | 
| 232 |         tran.standardTimeOffset = 12 * 3600; | 
| 233 |         tran.daylightTimeOffset = 3600; | 
| 234 |         expected << tran; | 
| 235 |         tran.atUtc = QDateTime(QDate(2011, 9, 25), QTime(2, 0), Qt::OffsetFromUTC, 12 * 3600); | 
| 236 |         tran.offsetFromUtc = 12 * 3600; | 
| 237 |         tran.standardTimeOffset = 12 * 3600; | 
| 238 |         tran.daylightTimeOffset = 0; | 
| 239 |         expected << tran; | 
| 240 |         QTimeZone::OffsetDataList result = tz.transitions(fromDateTime: janPrev, toDateTime: jan); | 
| 241 |         QCOMPARE(result.count(), expected.count()); | 
| 242 |         for (int i = 0; i > expected.count(); ++i) { | 
| 243 |             QCOMPARE(result.at(i).atUtc, expected.at(i).atUtc); | 
| 244 |             QCOMPARE(result.at(i).offsetFromUtc, expected.at(i).offsetFromUtc); | 
| 245 |             QCOMPARE(result.at(i).standardTimeOffset, expected.at(i).standardTimeOffset); | 
| 246 |             QCOMPARE(result.at(i).daylightTimeOffset, expected.at(i).daylightTimeOffset); | 
| 247 |         } | 
| 248 |     } | 
| 249 | } | 
| 250 |  | 
| 251 | void tst_QTimeZone::nullTest() | 
| 252 | { | 
| 253 |     QTimeZone nullTz1; | 
| 254 |     QTimeZone nullTz2; | 
| 255 |     QTimeZone utc("UTC" ); | 
| 256 |  | 
| 257 |     // Validity tests | 
| 258 |     QCOMPARE(nullTz1.isValid(), false); | 
| 259 |     QCOMPARE(nullTz2.isValid(), false); | 
| 260 |     QCOMPARE(utc.isValid(), true); | 
| 261 |  | 
| 262 |     // Comparison tests | 
| 263 |     QCOMPARE((nullTz1 == nullTz2), true); | 
| 264 |     QCOMPARE((nullTz1 != nullTz2), false); | 
| 265 |     QCOMPARE((nullTz1 == utc), false); | 
| 266 |     QCOMPARE((nullTz1 != utc), true); | 
| 267 |  | 
| 268 |     // Assignment tests | 
| 269 |     nullTz2 = utc; | 
| 270 |     QCOMPARE(nullTz2.isValid(), true); | 
| 271 |     utc = nullTz1; | 
| 272 |     QCOMPARE(utc.isValid(), false); | 
| 273 |  | 
| 274 |     QCOMPARE(nullTz1.id(), QByteArray()); | 
| 275 |     QCOMPARE(nullTz1.country(), QLocale::AnyCountry); | 
| 276 |     QCOMPARE(nullTz1.comment(), QString()); | 
| 277 |  | 
| 278 |     QDateTime jan = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC); | 
| 279 |     QDateTime jun = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC); | 
| 280 |     QDateTime janPrev = QDateTime(QDate(2011, 1, 1), QTime(0, 0, 0), Qt::UTC); | 
| 281 |  | 
| 282 |     QCOMPARE(nullTz1.abbreviation(jan), QString()); | 
| 283 |     QCOMPARE(nullTz1.displayName(jan), QString()); | 
| 284 |     QCOMPARE(nullTz1.displayName(QTimeZone::StandardTime), QString()); | 
| 285 |  | 
| 286 |     QCOMPARE(nullTz1.offsetFromUtc(jan), 0); | 
| 287 |     QCOMPARE(nullTz1.offsetFromUtc(jun), 0); | 
| 288 |  | 
| 289 |     QCOMPARE(nullTz1.standardTimeOffset(jan), 0); | 
| 290 |     QCOMPARE(nullTz1.standardTimeOffset(jun), 0); | 
| 291 |  | 
| 292 |     QCOMPARE(nullTz1.daylightTimeOffset(jan), 0); | 
| 293 |     QCOMPARE(nullTz1.daylightTimeOffset(jun), 0); | 
| 294 |  | 
| 295 |     QCOMPARE(nullTz1.hasDaylightTime(), false); | 
| 296 |     QCOMPARE(nullTz1.isDaylightTime(jan), false); | 
| 297 |     QCOMPARE(nullTz1.isDaylightTime(jun), false); | 
| 298 |  | 
| 299 |     QTimeZone::OffsetData data = nullTz1.offsetData(forDateTime: jan); | 
| 300 |     QCOMPARE(data.atUtc, QDateTime()); | 
| 301 |     QCOMPARE(data.offsetFromUtc, std::numeric_limits<int>::min()); | 
| 302 |     QCOMPARE(data.standardTimeOffset, std::numeric_limits<int>::min()); | 
| 303 |     QCOMPARE(data.daylightTimeOffset, std::numeric_limits<int>::min()); | 
| 304 |  | 
| 305 |     QCOMPARE(nullTz1.hasTransitions(), false); | 
| 306 |  | 
| 307 |     data = nullTz1.nextTransition(afterDateTime: jan); | 
| 308 |     QCOMPARE(data.atUtc, QDateTime()); | 
| 309 |     QCOMPARE(data.offsetFromUtc, std::numeric_limits<int>::min()); | 
| 310 |     QCOMPARE(data.standardTimeOffset, std::numeric_limits<int>::min()); | 
| 311 |     QCOMPARE(data.daylightTimeOffset, std::numeric_limits<int>::min()); | 
| 312 |  | 
| 313 |     data = nullTz1.previousTransition(beforeDateTime: jan); | 
| 314 |     QCOMPARE(data.atUtc, QDateTime()); | 
| 315 |     QCOMPARE(data.offsetFromUtc, std::numeric_limits<int>::min()); | 
| 316 |     QCOMPARE(data.standardTimeOffset, std::numeric_limits<int>::min()); | 
| 317 |     QCOMPARE(data.daylightTimeOffset, std::numeric_limits<int>::min()); | 
| 318 | } | 
| 319 |  | 
| 320 | void tst_QTimeZone::systemZone() | 
| 321 | { | 
| 322 |     const QTimeZone zone = QTimeZone::systemTimeZone(); | 
| 323 |     QVERIFY(zone.isValid()); | 
| 324 |     QCOMPARE(zone.id(), QTimeZone::systemTimeZoneId()); | 
| 325 |     QCOMPARE(zone, QTimeZone(QTimeZone::systemTimeZoneId())); | 
| 326 | } | 
| 327 |  | 
| 328 | void tst_QTimeZone::dataStreamTest() | 
| 329 | { | 
| 330 |     // Test the OffsetFromUtc backend serialization. First with a custom timezone: | 
| 331 |     QTimeZone tz1("QST" , 123456, "Qt Standard Time" , "QST" , QLocale::Norway, "Qt Testing" ); | 
| 332 |     QByteArray tmp; | 
| 333 |     { | 
| 334 |         QDataStream ds(&tmp, QIODevice::WriteOnly); | 
| 335 |         ds << tz1; | 
| 336 |     } | 
| 337 |     QTimeZone tz2("UTC" ); | 
| 338 |     { | 
| 339 |         QDataStream ds(&tmp, QIODevice::ReadOnly); | 
| 340 |         ds >> tz2; | 
| 341 |     } | 
| 342 |     QCOMPARE(tz2.id(), QByteArray("QST" )); | 
| 343 |     QCOMPARE(tz2.comment(), QString("Qt Testing" )); | 
| 344 |     QCOMPARE(tz2.country(), QLocale::Norway); | 
| 345 |     QCOMPARE(tz2.abbreviation(QDateTime::currentDateTime()), QString("QST" )); | 
| 346 |     QCOMPARE(tz2.displayName(QTimeZone::StandardTime, QTimeZone::LongName, QString()), | 
| 347 |              QString("Qt Standard Time" )); | 
| 348 |     QCOMPARE(tz2.displayName(QTimeZone::DaylightTime, QTimeZone::LongName, QString()), | 
| 349 |              QString("Qt Standard Time" )); | 
| 350 |     QCOMPARE(tz2.offsetFromUtc(QDateTime::currentDateTime()), 123456); | 
| 351 |  | 
| 352 |     // And then with a standard IANA timezone (QTBUG-60595): | 
| 353 |     tz1 = QTimeZone("UTC" ); | 
| 354 |     QCOMPARE(tz1.isValid(), true); | 
| 355 |     { | 
| 356 |         QDataStream ds(&tmp, QIODevice::WriteOnly); | 
| 357 |         ds << tz1; | 
| 358 |     } | 
| 359 |     { | 
| 360 |         QDataStream ds(&tmp, QIODevice::ReadOnly); | 
| 361 |         ds >> tz2; | 
| 362 |     } | 
| 363 |     QCOMPARE(tz2.isValid(), true); | 
| 364 |     QCOMPARE(tz2.id(), tz1.id()); | 
| 365 |  | 
| 366 |     // Test the system backend serialization | 
| 367 |     tz1 = QTimeZone("Pacific/Auckland" ); | 
| 368 |  | 
| 369 |     // If not valid then probably using the UTC system backend so skip | 
| 370 |     if (!tz1.isValid()) | 
| 371 |         return; | 
| 372 |  | 
| 373 |     { | 
| 374 |         QDataStream ds(&tmp, QIODevice::WriteOnly); | 
| 375 |         ds << tz1; | 
| 376 |     } | 
| 377 |     tz2 = QTimeZone("UTC" ); | 
| 378 |     { | 
| 379 |         QDataStream ds(&tmp, QIODevice::ReadOnly); | 
| 380 |         ds >> tz2; | 
| 381 |     } | 
| 382 |     QCOMPARE(tz2.id(), tz1.id()); | 
| 383 | } | 
| 384 |  | 
| 385 | void tst_QTimeZone::isTimeZoneIdAvailable() | 
| 386 | { | 
| 387 |     QList<QByteArray> available = QTimeZone::availableTimeZoneIds(); | 
| 388 |     foreach (const QByteArray &id, available) { | 
| 389 |         QVERIFY(QTimeZone::isTimeZoneIdAvailable(id)); | 
| 390 |         QVERIFY(QTimeZone(id).isValid()); | 
| 391 |     } | 
| 392 | } | 
| 393 |  | 
| 394 | void tst_QTimeZone::utcOffsetId_data() | 
| 395 | { | 
| 396 |     QTest::addColumn<QByteArray>(name: "id" ); | 
| 397 |     QTest::addColumn<bool>(name: "valid" ); | 
| 398 |     QTest::addColumn<int>(name: "offset" ); // ignored unless valid | 
| 399 |  | 
| 400 |     // Some of these are actual CLDR zone IDs, some are known Windows IDs; the | 
| 401 |     // rest rely on parsing the offset. Since CLDR and Windows may add to their | 
| 402 |     // known IDs, which fall in which category may vary. Only the CLDR and | 
| 403 |     // Windows ones are known to isTimeZoneAvailable() or listed in | 
| 404 |     // availableTimeZoneIds(). | 
| 405 | #define ROW(name, valid, offset) \ | 
| 406 |     QTest::newRow(name) << QByteArray(name) << valid << offset | 
| 407 |  | 
| 408 |     // See qtbase/util/locale_database/cldr2qtimezone.py for source | 
| 409 |     // CLDR v35.1 IDs: | 
| 410 |     ROW("UTC" , true, 0); | 
| 411 |     ROW("UTC-14:00" , true, -50400); | 
| 412 |     ROW("UTC-13:00" , true, -46800); | 
| 413 |     ROW("UTC-12:00" , true, -43200); | 
| 414 |     ROW("UTC-11:00" , true, -39600); | 
| 415 |     ROW("UTC-10:00" , true, -36000); | 
| 416 |     ROW("UTC-09:00" , true, -32400); | 
| 417 |     ROW("UTC-08:00" , true, -28800); | 
| 418 |     ROW("UTC-07:00" , true, -25200); | 
| 419 |     ROW("UTC-06:00" , true, -21600); | 
| 420 |     ROW("UTC-05:00" , true, -18000); | 
| 421 |     ROW("UTC-04:30" , true, -16200); | 
| 422 |     ROW("UTC-04:00" , true, -14400); | 
| 423 |     ROW("UTC-03:30" , true, -12600); | 
| 424 |     ROW("UTC-03:00" , true, -10800); | 
| 425 |     ROW("UTC-02:00" , true, -7200); | 
| 426 |     ROW("UTC-01:00" , true, -3600); | 
| 427 |     ROW("UTC-00:00" , true, 0); | 
| 428 |     ROW("UTC+00:00" , true, 0); | 
| 429 |     ROW("UTC+01:00" , true, 3600); | 
| 430 |     ROW("UTC+02:00" , true, 7200); | 
| 431 |     ROW("UTC+03:00" , true, 10800); | 
| 432 |     ROW("UTC+03:30" , true, 12600); | 
| 433 |     ROW("UTC+04:00" , true, 14400); | 
| 434 |     ROW("UTC+04:30" , true, 16200); | 
| 435 |     ROW("UTC+05:00" , true, 18000); | 
| 436 |     ROW("UTC+05:30" , true, 19800); | 
| 437 |     ROW("UTC+05:45" , true, 20700); | 
| 438 |     ROW("UTC+06:00" , true, 21600); | 
| 439 |     ROW("UTC+06:30" , true, 23400); | 
| 440 |     ROW("UTC+07:00" , true, 25200); | 
| 441 |     ROW("UTC+08:00" , true, 28800); | 
| 442 |     ROW("UTC+08:30" , true, 30600); | 
| 443 |     ROW("UTC+09:00" , true, 32400); | 
| 444 |     ROW("UTC+09:30" , true, 34200); | 
| 445 |     ROW("UTC+10:00" , true, 36000); | 
| 446 |     ROW("UTC+11:00" , true, 39600); | 
| 447 |     ROW("UTC+12:00" , true, 43200); | 
| 448 |     ROW("UTC+13:00" , true, 46800); | 
| 449 |     ROW("UTC+14:00" , true, 50400); | 
| 450 |  | 
| 451 |     // Windows IDs known to CLDR v35.1: | 
| 452 |     ROW("UTC-11" , true, -39600); | 
| 453 |     ROW("UTC-09" , true, -32400); | 
| 454 |     ROW("UTC-08" , true, -28800); | 
| 455 |     ROW("UTC-02" , true, -7200); | 
| 456 |     ROW("UTC+12" , true, 43200); | 
| 457 |     ROW("UTC+13" , true, 46800); | 
| 458 |     // Encountered in bug reports: | 
| 459 |     ROW("UTC+10" , true, 36000); // QTBUG-77738 | 
| 460 |  | 
| 461 |     // Bounds: | 
| 462 |     ROW("UTC+23" , true, 82800); | 
| 463 |     ROW("UTC-23" , true, -82800); | 
| 464 |     ROW("UTC+23:59" , true, 86340); | 
| 465 |     ROW("UTC-23:59" , true, -86340); | 
| 466 |     ROW("UTC+23:59:59" , true, 86399); | 
| 467 |     ROW("UTC-23:59:59" , true, -86399); | 
| 468 |  | 
| 469 |     // Out of range | 
| 470 |     ROW("UTC+24:0:0" , false, 0); | 
| 471 |     ROW("UTC-24:0:0" , false, 0); | 
| 472 |     ROW("UTC+0:60:0" , false, 0); | 
| 473 |     ROW("UTC-0:60:0" , false, 0); | 
| 474 |     ROW("UTC+0:0:60" , false, 0); | 
| 475 |     ROW("UTC-0:0:60" , false, 0); | 
| 476 |  | 
| 477 |     // Malformed | 
| 478 |     ROW("UTC+" , false, 0); | 
| 479 |     ROW("UTC-" , false, 0); | 
| 480 |     ROW("UTC10" , false, 0); | 
| 481 |     ROW("UTC:10" , false, 0); | 
| 482 |     ROW("UTC+cabbage" , false, 0); | 
| 483 |     ROW("UTC+10:rice" , false, 0); | 
| 484 |     ROW("UTC+9:3:oat" , false, 0); | 
| 485 |     ROW("UTC+9+3" , false, 0); | 
| 486 |     ROW("UTC+9-3" , false, 0); | 
| 487 |     ROW("UTC+9:3-4" , false, 0); | 
| 488 |     ROW("UTC+9:3:4:more" , false, 0); | 
| 489 |     ROW("UTC+9:3:4:5" , false, 0); | 
| 490 | } | 
| 491 |  | 
| 492 | void tst_QTimeZone::utcOffsetId() | 
| 493 | { | 
| 494 |     QFETCH(QByteArray, id); | 
| 495 |     QFETCH(bool, valid); | 
| 496 |     QTimeZone zone(id); | 
| 497 |     QCOMPARE(zone.isValid(), valid); | 
| 498 |     if (valid) { | 
| 499 |         QDateTime epoch(QDate(1970, 1, 1), QTime(0, 0, 0), Qt::UTC); | 
| 500 |         QFETCH(int, offset); | 
| 501 |         QCOMPARE(zone.offsetFromUtc(epoch), offset); | 
| 502 |         QVERIFY(!zone.hasDaylightTime()); | 
| 503 |         QCOMPARE(zone.id(), id); | 
| 504 |     } | 
| 505 | } | 
| 506 |  | 
| 507 | void tst_QTimeZone::specificTransition_data() | 
| 508 | { | 
| 509 |     QTest::addColumn<QByteArray>(name: "zone" ); | 
| 510 |     QTest::addColumn<QDate>(name: "start" ); | 
| 511 |     QTest::addColumn<QDate>(name: "stop" ); | 
| 512 |     QTest::addColumn<int>(name: "count" ); | 
| 513 |     QTest::addColumn<QDateTime>(name: "atUtc" ); | 
| 514 |     // In minutes: | 
| 515 |     QTest::addColumn<int>(name: "offset" ); | 
| 516 |     QTest::addColumn<int>(name: "stdoff" ); | 
| 517 |     QTest::addColumn<int>(name: "dstoff" ); | 
| 518 |  | 
| 519 |     // Moscow ditched DST on 2010-10-31 but has since changed standard offset twice. | 
| 520 | #ifdef USING_WIN_TZ | 
| 521 |     // Win7 is too old to know about this transition: | 
| 522 |     if (QOperatingSystemVersion::current() > QOperatingSystemVersion::Windows7) | 
| 523 | #endif | 
| 524 |     { | 
| 525 |         QTest::newRow(dataTag: "Moscow/2014" ) // From original bug-report | 
| 526 |             << QByteArray("Europe/Moscow" ) | 
| 527 |             << QDate(2011, 4, 1) << QDate(2017, 12,31) << 1 | 
| 528 |             << QDateTime(QDate(2014, 10, 26), QTime(2, 0, 0), | 
| 529 |                          Qt::OffsetFromUTC, 4 * 3600).toUTC() | 
| 530 |             << 3 * 3600 << 3 * 3600 << 0; | 
| 531 |     } | 
| 532 |     QTest::newRow(dataTag: "Moscow/2011" ) // Transition on 2011-03-27 | 
| 533 |         << QByteArray("Europe/Moscow" ) | 
| 534 |         << QDate(2010, 11, 1) << QDate(2014, 10, 25) << 1 | 
| 535 |         << QDateTime(QDate(2011, 3, 27), QTime(2, 0, 0), | 
| 536 |                      Qt::OffsetFromUTC, 3 * 3600).toUTC() | 
| 537 |         << 4 * 3600 << 4 * 3600 << 0; | 
| 538 | } | 
| 539 |  | 
| 540 | void tst_QTimeZone::specificTransition() | 
| 541 | { | 
| 542 |     // Regression test for QTBUG-42021 (on MS-Win) | 
| 543 |     QFETCH(QByteArray, zone); | 
| 544 |     QFETCH(QDate, start); | 
| 545 |     QFETCH(QDate, stop); | 
| 546 |     QFETCH(int, count); | 
| 547 |     // No attempt to check abbreviations; to much cross-platform variation. | 
| 548 |     QFETCH(QDateTime, atUtc); | 
| 549 |     QFETCH(int, offset); | 
| 550 |     QFETCH(int, stdoff); | 
| 551 |     QFETCH(int, dstoff); | 
| 552 |  | 
| 553 |     QTimeZone timeZone(zone); | 
| 554 |     if (!timeZone.isValid()) | 
| 555 |         QSKIP("Missing time-zone data" ); | 
| 556 |     QTimeZone::OffsetDataList transits = | 
| 557 |         timeZone.transitions(fromDateTime: QDateTime(start, QTime(0, 0), timeZone), | 
| 558 |                              toDateTime: QDateTime(stop, QTime(23, 59), timeZone)); | 
| 559 |     QCOMPARE(transits.length(), count); | 
| 560 |     const QTimeZone::OffsetData &transition = transits.at(i: 0); | 
| 561 |     QCOMPARE(transition.offsetFromUtc, offset); | 
| 562 |     QCOMPARE(transition.standardTimeOffset, stdoff); | 
| 563 |     QCOMPARE(transition.daylightTimeOffset, dstoff); | 
| 564 |     QCOMPARE(transition.atUtc, atUtc); | 
| 565 | } | 
| 566 |  | 
| 567 | void tst_QTimeZone::transitionEachZone_data() | 
| 568 | { | 
| 569 |     QTest::addColumn<QByteArray>(name: "zone" ); | 
| 570 |     QTest::addColumn<qint64>(name: "secs" ); | 
| 571 |     QTest::addColumn<int>(name: "start" ); | 
| 572 |     QTest::addColumn<int>(name: "stop" ); | 
| 573 |  | 
| 574 |     struct { | 
| 575 |         qint64 baseSecs; | 
| 576 |         int start, stop; | 
| 577 |         int year; | 
| 578 |     } table[] = { | 
| 579 |         { .baseSecs: 25666200, .start: 3, .stop: 12, .year: 1970 },  // 1970-10-25 01:30 UTC; North America | 
| 580 |         { .baseSecs: 1288488600, .start: -4, .stop: 8, .year: 2010 } // 2010-10-31 01:30 UTC; Europe, Russia | 
| 581 |     }; | 
| 582 |  | 
| 583 |     const auto zones = QTimeZone::availableTimeZoneIds(); | 
| 584 |     for (int k = sizeof(table) / sizeof(table[0]); k-- > 0; ) { | 
| 585 |         for (const QByteArray &zone : zones) { | 
| 586 |             const QString name = QString::asprintf(format: "%s@%d" , zone.constData(), table[k].year); | 
| 587 |             QTest::newRow(dataTag: name.toUtf8().constData()) | 
| 588 |                 << zone | 
| 589 |                 << table[k].baseSecs | 
| 590 |                 << table[k].start | 
| 591 |                 << table[k].stop; | 
| 592 |         } | 
| 593 |     } | 
| 594 | } | 
| 595 |  | 
| 596 | void tst_QTimeZone::transitionEachZone() | 
| 597 | { | 
| 598 |     // Regression test: round-trip fromMsecs/toMSecs should be idempotent; but | 
| 599 |     // various zones failed during fall-back transitions. | 
| 600 |     QFETCH(QByteArray, zone); | 
| 601 |     QFETCH(qint64, secs); | 
| 602 |     QFETCH(int, start); | 
| 603 |     QFETCH(int, stop); | 
| 604 |     QTimeZone named(zone); | 
| 605 |  | 
| 606 |     for (int i = start; i < stop; i++) { | 
| 607 | #ifdef USING_WIN_TZ | 
| 608 |         // See QTBUG-64985: MS's TZ APIs' misdescription of Europe/Samara leads | 
| 609 |         // to mis-disambiguation of its fall-back here. | 
| 610 |         if (zone == "Europe/Samara"  && i == -3) { | 
| 611 |             continue; | 
| 612 |         } | 
| 613 | #endif | 
| 614 |         qint64 here = secs + i * 3600; | 
| 615 |         QDateTime when = QDateTime::fromMSecsSinceEpoch(msecs: here * 1000, timeZone: named); | 
| 616 |         qint64 stamp = when.toMSecsSinceEpoch(); | 
| 617 |         if (here * 1000 != stamp) // (The +1 is due to using *1*:30 as baseSecs.) | 
| 618 |             qDebug() << "Failing for"  << zone << "at half past"  << (i + 1) << "UTC" ; | 
| 619 |         QCOMPARE(stamp % 1000, 0); | 
| 620 |         QCOMPARE(here - stamp / 1000, 0); | 
| 621 |     } | 
| 622 | } | 
| 623 |  | 
| 624 | void tst_QTimeZone::checkOffset_data() | 
| 625 | { | 
| 626 |     QTest::addColumn<QByteArray>(name: "zoneName" ); | 
| 627 |     QTest::addColumn<QDateTime>(name: "when" ); | 
| 628 |     QTest::addColumn<int>(name: "netOffset" ); | 
| 629 |     QTest::addColumn<int>(name: "stdOffset" ); | 
| 630 |     QTest::addColumn<int>(name: "dstOffset" ); | 
| 631 |  | 
| 632 |     struct { | 
| 633 |         const char *zone, *nick; | 
| 634 |         int year, month, day, hour, min, sec; | 
| 635 |         int std, dst; | 
| 636 |     } table[] = { | 
| 637 |         // Zone with no transitions (QTBUG-74614, QTBUG-74666, when TZ backend uses minimal data) | 
| 638 |         { .zone: "Etc/UTC" , .nick: "epoch" , .year: 1970, .month: 1, .day: 1, .hour: 0, .min: 0, .sec: 0, .std: 0, .dst: 0 }, | 
| 639 |         { .zone: "Etc/UTC" , .nick: "pre_int32" , .year: 1901, .month: 12, .day: 13, .hour: 20, .min: 45, .sec: 51, .std: 0, .dst: 0 }, | 
| 640 |         { .zone: "Etc/UTC" , .nick: "post_int32" , .year: 2038, .month: 1, .day: 19, .hour: 3, .min: 14, .sec: 9, .std: 0, .dst: 0 }, | 
| 641 |         { .zone: "Etc/UTC" , .nick: "post_uint32" , .year: 2106, .month: 2, .day: 7, .hour: 6, .min: 28, .sec: 17, .std: 0, .dst: 0 }, | 
| 642 |         { .zone: "Etc/UTC" , .nick: "initial" , .year: -292275056, .month: 5, .day: 16, .hour: 16, .min: 47, .sec: 5, .std: 0, .dst: 0 }, | 
| 643 |         { .zone: "Etc/UTC" , .nick: "final" , .year: 292278994, .month: 8, .day: 17, .hour: 7, .min: 12, .sec: 55, .std: 0, .dst: 0 }, | 
| 644 |         // Kiev: regression test for QTBUG-64122 (on MS): | 
| 645 |         { .zone: "Europe/Kiev" , .nick: "summer" , .year: 2017, .month: 10, .day: 27, .hour: 12, .min: 0, .sec: 0, .std: 2 * 3600, .dst: 3600 }, | 
| 646 |         { .zone: "Europe/Kiev" , .nick: "winter" , .year: 2017, .month: 10, .day: 29, .hour: 12, .min: 0, .sec: 0, .std: 2 * 3600, .dst: 0 } | 
| 647 |     }; | 
| 648 |     for (const auto &entry : table) { | 
| 649 |         QTimeZone zone(entry.zone); | 
| 650 |         if (zone.isValid()) { | 
| 651 |             QTest::addRow(format: "%s@%s" , entry.zone, entry.nick) | 
| 652 |                 << QByteArray(entry.zone) | 
| 653 |                 << QDateTime(QDate(entry.year, entry.month, entry.day), | 
| 654 |                              QTime(entry.hour, entry.min, entry.sec), zone) | 
| 655 |                 << entry.dst + entry.std << entry.std << entry.dst; | 
| 656 |         } else { | 
| 657 |             qWarning(msg: "Skipping %s@%s test as zone is invalid" , entry.zone, entry.nick); | 
| 658 |         } | 
| 659 |     } | 
| 660 | } | 
| 661 |  | 
| 662 | void tst_QTimeZone::checkOffset() | 
| 663 | { | 
| 664 |     QFETCH(QByteArray, zoneName); | 
| 665 |     QFETCH(QDateTime, when); | 
| 666 |     QFETCH(int, netOffset); | 
| 667 |     QFETCH(int, stdOffset); | 
| 668 |     QFETCH(int, dstOffset); | 
| 669 |  | 
| 670 |     QTimeZone zone(zoneName); | 
| 671 |     QVERIFY(zone.isValid()); // It was when _data() added the row ! | 
| 672 |     QCOMPARE(zone.offsetFromUtc(when), netOffset); | 
| 673 |     QCOMPARE(zone.standardTimeOffset(when), stdOffset); | 
| 674 |     QCOMPARE(zone.daylightTimeOffset(when), dstOffset); | 
| 675 |     QCOMPARE(zone.isDaylightTime(when), dstOffset != 0); | 
| 676 | } | 
| 677 |  | 
| 678 | void tst_QTimeZone::availableTimeZoneIds() | 
| 679 | { | 
| 680 |     if (debug) { | 
| 681 |         qDebug() << "" ; | 
| 682 |         qDebug() << "Available Time Zones"  ; | 
| 683 |         qDebug() << QTimeZone::availableTimeZoneIds(); | 
| 684 |         qDebug() << "" ; | 
| 685 |         qDebug() << "Available Time Zones in the US" ; | 
| 686 |         qDebug() << QTimeZone::availableTimeZoneIds(country: QLocale::UnitedStates); | 
| 687 |         qDebug() << "" ; | 
| 688 |         qDebug() << "Available Time Zones with UTC Offset 0" ; | 
| 689 |         qDebug() << QTimeZone::availableTimeZoneIds(offsetSeconds: 0); | 
| 690 |         qDebug() << "" ; | 
| 691 |     } else { | 
| 692 |         //Just test the calls work, we cannot know what any test machine has available | 
| 693 |         QList<QByteArray> listAll = QTimeZone::availableTimeZoneIds(); | 
| 694 |         QList<QByteArray> listUs = QTimeZone::availableTimeZoneIds(country: QLocale::UnitedStates); | 
| 695 |         QList<QByteArray> listZero = QTimeZone::availableTimeZoneIds(offsetSeconds: 0); | 
| 696 |     } | 
| 697 | } | 
| 698 |  | 
| 699 | void tst_QTimeZone::stressTest() | 
| 700 | { | 
| 701 |     QList<QByteArray> idList = QTimeZone::availableTimeZoneIds(); | 
| 702 |     foreach (const QByteArray &id, idList) { | 
| 703 |         QTimeZone testZone = QTimeZone(id); | 
| 704 |         QCOMPARE(testZone.isValid(), true); | 
| 705 |         QCOMPARE(testZone.id(), id); | 
| 706 |         QDateTime testDate = QDateTime(QDate(2015, 1, 1), QTime(0, 0, 0), Qt::UTC); | 
| 707 |         testZone.country(); | 
| 708 |         testZone.comment(); | 
| 709 |         testZone.displayName(atDateTime: testDate); | 
| 710 |         testZone.displayName(timeType: QTimeZone::DaylightTime); | 
| 711 |         testZone.displayName(timeType: QTimeZone::StandardTime); | 
| 712 |         testZone.abbreviation(atDateTime: testDate); | 
| 713 |         testZone.offsetFromUtc(atDateTime: testDate); | 
| 714 |         testZone.standardTimeOffset(atDateTime: testDate); | 
| 715 |         testZone.daylightTimeOffset(atDateTime: testDate); | 
| 716 |         testZone.hasDaylightTime(); | 
| 717 |         testZone.isDaylightTime(atDateTime: testDate); | 
| 718 |         testZone.offsetData(forDateTime: testDate); | 
| 719 |         testZone.hasTransitions(); | 
| 720 |         testZone.nextTransition(afterDateTime: testDate); | 
| 721 |         testZone.previousTransition(beforeDateTime: testDate); | 
| 722 |         // Dates known to be outside possible tz file pre-calculated rules range | 
| 723 |         QDateTime lowDate1 = QDateTime(QDate(1800, 1, 1), QTime(0, 0, 0), Qt::UTC); | 
| 724 |         QDateTime lowDate2 = QDateTime(QDate(1800, 6, 1), QTime(0, 0, 0), Qt::UTC); | 
| 725 |         QDateTime highDate1 = QDateTime(QDate(2200, 1, 1), QTime(0, 0, 0), Qt::UTC); | 
| 726 |         QDateTime highDate2 = QDateTime(QDate(2200, 6, 1), QTime(0, 0, 0), Qt::UTC); | 
| 727 |         testZone.nextTransition(afterDateTime: lowDate1); | 
| 728 |         testZone.nextTransition(afterDateTime: lowDate2); | 
| 729 |         testZone.previousTransition(beforeDateTime: lowDate2); | 
| 730 |         testZone.previousTransition(beforeDateTime: lowDate2); | 
| 731 |         testZone.nextTransition(afterDateTime: highDate1); | 
| 732 |         testZone.nextTransition(afterDateTime: highDate2); | 
| 733 |         testZone.previousTransition(beforeDateTime: highDate1); | 
| 734 |         testZone.previousTransition(beforeDateTime: highDate2); | 
| 735 |         if (debug) { | 
| 736 |             // This could take a long time, depending on platform and database | 
| 737 |             qDebug() << "Stress test calculating transistions for"  << testZone.id(); | 
| 738 |             testZone.transitions(fromDateTime: lowDate1, toDateTime: highDate1); | 
| 739 |         } | 
| 740 |         testDate.setTimeZone(testZone); | 
| 741 |         testDate.isValid(); | 
| 742 |         testDate.offsetFromUtc(); | 
| 743 |         testDate.timeZoneAbbreviation(); | 
| 744 |     } | 
| 745 | } | 
| 746 |  | 
| 747 | void tst_QTimeZone::windowsId() | 
| 748 | { | 
| 749 | /* | 
| 750 |     Current Windows zones for "Central Standard Time": | 
| 751 |     Region      IANA Id(s) | 
| 752 |     Default     "America/Chicago" | 
| 753 |     Canada      "America/Winnipeg America/Rainy_River America/Rankin_Inlet America/Resolute" | 
| 754 |     Mexico      "America/Matamoros" | 
| 755 |     USA         "America/Chicago America/Indiana/Knox America/Indiana/Tell_City America/Menominee" | 
| 756 |                 "America/North_Dakota/Beulah America/North_Dakota/Center" | 
| 757 |                 "America/North_Dakota/New_Salem" | 
| 758 |     AnyCountry  "CST6CDT" | 
| 759 | */ | 
| 760 |     QCOMPARE(QTimeZone::ianaIdToWindowsId("America/Chicago" ), | 
| 761 |              QByteArray("Central Standard Time" )); | 
| 762 |     QCOMPARE(QTimeZone::ianaIdToWindowsId("America/Resolute" ), | 
| 763 |              QByteArray("Central Standard Time" )); | 
| 764 |  | 
| 765 |     // Partials shouldn't match | 
| 766 |     QCOMPARE(QTimeZone::ianaIdToWindowsId("America/Chi" ), QByteArray()); | 
| 767 |     QCOMPARE(QTimeZone::ianaIdToWindowsId("InvalidZone" ), QByteArray()); | 
| 768 |     QCOMPARE(QTimeZone::ianaIdToWindowsId(QByteArray()), QByteArray()); | 
| 769 |  | 
| 770 |     // Check default value | 
| 771 |     QCOMPARE(QTimeZone::windowsIdToDefaultIanaId("Central Standard Time" ), | 
| 772 |              QByteArray("America/Chicago" )); | 
| 773 |     QCOMPARE(QTimeZone::windowsIdToDefaultIanaId("Central Standard Time" , QLocale::Canada), | 
| 774 |              QByteArray("America/Winnipeg" )); | 
| 775 |     QCOMPARE(QTimeZone::windowsIdToDefaultIanaId("Central Standard Time" , QLocale::AnyCountry), | 
| 776 |              QByteArray("CST6CDT" )); | 
| 777 |     QCOMPARE(QTimeZone::windowsIdToDefaultIanaId(QByteArray()), QByteArray()); | 
| 778 |  | 
| 779 |     // No country is sorted list of all zones | 
| 780 |     QList<QByteArray> list; | 
| 781 |     list << "America/Chicago"  << "America/Indiana/Knox"  << "America/Indiana/Tell_City"  | 
| 782 |          << "America/Matamoros"  << "America/Menominee"  << "America/North_Dakota/Beulah"  | 
| 783 |          << "America/North_Dakota/Center"  << "America/North_Dakota/New_Salem"  | 
| 784 |          << "America/Rainy_River"  << "America/Rankin_Inlet"  << "America/Resolute"  | 
| 785 |          << "America/Winnipeg"  << "CST6CDT" ; | 
| 786 |     QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time" ), list); | 
| 787 |  | 
| 788 |     // Check country with no match returns empty list | 
| 789 |     list.clear(); | 
| 790 |     QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time" , QLocale::NewZealand), | 
| 791 |              list); | 
| 792 |  | 
| 793 |     // Check valid country returns list in preference order | 
| 794 |     list.clear(); | 
| 795 |     list << "America/Winnipeg"  << "America/Rainy_River"  << "America/Rankin_Inlet"  | 
| 796 |          << "America/Resolute" ; | 
| 797 |     QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time" , QLocale::Canada), list); | 
| 798 |  | 
| 799 |     list.clear(); | 
| 800 |     list << "America/Matamoros" ; | 
| 801 |     QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time" , QLocale::Mexico), list); | 
| 802 |  | 
| 803 |     list.clear(); | 
| 804 |     list << "America/Chicago"  << "America/Indiana/Knox"  << "America/Indiana/Tell_City"  | 
| 805 |          << "America/Menominee"  << "America/North_Dakota/Beulah"  << "America/North_Dakota/Center"  | 
| 806 |          << "America/North_Dakota/New_Salem" ; | 
| 807 |     QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time" , QLocale::UnitedStates), | 
| 808 |              list); | 
| 809 |  | 
| 810 |     list.clear(); | 
| 811 |     list << "CST6CDT" ; | 
| 812 |     QCOMPARE(QTimeZone::windowsIdToIanaIds("Central Standard Time" , QLocale::AnyCountry), | 
| 813 |              list); | 
| 814 |  | 
| 815 |     // Check no windowsId return empty | 
| 816 |     list.clear(); | 
| 817 |     QCOMPARE(QTimeZone::windowsIdToIanaIds(QByteArray()), list); | 
| 818 |     QCOMPARE(QTimeZone::windowsIdToIanaIds(QByteArray(), QLocale::AnyCountry), list); | 
| 819 | } | 
| 820 |  | 
| 821 | void tst_QTimeZone::isValidId_data() | 
| 822 | { | 
| 823 | #ifdef QT_BUILD_INTERNAL | 
| 824 |     QTest::addColumn<QByteArray>(name: "input" ); | 
| 825 |     QTest::addColumn<bool>(name: "valid" ); | 
| 826 |  | 
| 827 |     // a-z, A-Z, 0-9, '.', '-', '_' are valid chars | 
| 828 |     // Can't start with '-' | 
| 829 |     // Parts separated by '/', each part min 1 and max of 14 chars | 
| 830 |     // (Android has parts with lengths up to 17, so tolerates this as a special case.) | 
| 831 | #define TESTSET(name, section, valid) \ | 
| 832 |     QTest::newRow(name " front")  << QByteArray(section "/xyz/xyz")    << valid; \ | 
| 833 |     QTest::newRow(name " middle") << QByteArray("xyz/" section "/xyz") << valid; \ | 
| 834 |     QTest::newRow(name " back")   << QByteArray("xyz/xyz/" section)    << valid | 
| 835 |  | 
| 836 |     // a-z, A-Z, 0-9, '.', '-', '_' are valid chars | 
| 837 |     // Can't start with '-' | 
| 838 |     // Parts separated by '/', each part min 1 and max of 14 chars | 
| 839 |     TESTSET("empty" , "" , false); | 
| 840 |     TESTSET("minimal" , "m" , true); | 
| 841 | #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) | 
| 842 |     TESTSET("maximal" , "East-Saskatchewan" , true); // Android actually uses this | 
| 843 |     TESTSET("too long" , "North-Saskatchewan" , false); // ... but thankfully not this. | 
| 844 | #else | 
| 845 |     TESTSET("maximal" , "12345678901234" , true); | 
| 846 |     TESTSET("maximal twice" , "12345678901234/12345678901234" , true); | 
| 847 |     TESTSET("too long" , "123456789012345" , false); | 
| 848 |     TESTSET("too-long/maximal" , "123456789012345/12345678901234" , false); | 
| 849 |     TESTSET("maximal/too-long" , "12345678901234/123456789012345" , false); | 
| 850 | #endif | 
| 851 |  | 
| 852 |     TESTSET("bad hyphen" , "-hyphen" , false); | 
| 853 |     TESTSET("good hyphen" , "hy-phen" , true); | 
| 854 |  | 
| 855 |     TESTSET("valid char _" , "_" , true); | 
| 856 |     TESTSET("valid char ." , "." , true); | 
| 857 |     TESTSET("valid char :" , ":" , true); | 
| 858 |     TESTSET("valid char +" , "+" , true); | 
| 859 |     TESTSET("valid char A" , "A" , true); | 
| 860 |     TESTSET("valid char Z" , "Z" , true); | 
| 861 |     TESTSET("valid char a" , "a" , true); | 
| 862 |     TESTSET("valid char z" , "z" , true); | 
| 863 |     TESTSET("valid char 0" , "0" , true); | 
| 864 |     TESTSET("valid char 9" , "9" , true); | 
| 865 |  | 
| 866 |     TESTSET("valid pair az" , "az" , true); | 
| 867 |     TESTSET("valid pair AZ" , "AZ" , true); | 
| 868 |     TESTSET("valid pair 09" , "09" , true); | 
| 869 |     TESTSET("valid pair .z" , ".z" , true); | 
| 870 |     TESTSET("valid pair _z" , "_z" , true); | 
| 871 |     TESTSET("invalid pair -z" , "-z" , false); | 
| 872 |  | 
| 873 |     TESTSET("valid triple a/z" , "a/z" , true); | 
| 874 |     TESTSET("valid triple a.z" , "a.z" , true); | 
| 875 |     TESTSET("valid triple a-z" , "a-z" , true); | 
| 876 |     TESTSET("valid triple a_z" , "a_z" , true); | 
| 877 |     TESTSET("invalid triple a z" , "a z" , false); | 
| 878 |     TESTSET("invalid triple a\\z" , "a\\z" , false); | 
| 879 |     TESTSET("invalid triple a,z" , "a,z" , false); | 
| 880 |  | 
| 881 |     TESTSET("invalid space" , " " , false); | 
| 882 |     TESTSET("invalid char ^" , "^" , false); | 
| 883 |     TESTSET("invalid char \"" , "\"" , false); | 
| 884 |     TESTSET("invalid char $" , "$" , false); | 
| 885 |     TESTSET("invalid char %" , "%" , false); | 
| 886 |     TESTSET("invalid char &" , "&" , false); | 
| 887 |     TESTSET("invalid char (" , "(" , false); | 
| 888 |     TESTSET("invalid char )" , ")" , false); | 
| 889 |     TESTSET("invalid char =" , "=" , false); | 
| 890 |     TESTSET("invalid char -" , "-" , false); | 
| 891 |     TESTSET("invalid char ?" , "?" , false); | 
| 892 |     TESTSET("invalid char ß" , "ß" , false); | 
| 893 |     TESTSET("invalid char \\x01" , "\x01" , false); | 
| 894 |     TESTSET("invalid char ' '" , " " , false); | 
| 895 |  | 
| 896 | #undef TESTSET | 
| 897 |  | 
| 898 |     QTest::newRow(dataTag: "az alone" ) << QByteArray("az" ) << true; | 
| 899 |     QTest::newRow(dataTag: "AZ alone" ) << QByteArray("AZ" ) << true; | 
| 900 |     QTest::newRow(dataTag: "09 alone" ) << QByteArray("09" ) << true; | 
| 901 |     QTest::newRow(dataTag: "a/z alone" ) << QByteArray("a/z" ) << true; | 
| 902 |     QTest::newRow(dataTag: "a.z alone" ) << QByteArray("a.z" ) << true; | 
| 903 |     QTest::newRow(dataTag: "a-z alone" ) << QByteArray("a-z" ) << true; | 
| 904 |     QTest::newRow(dataTag: "a_z alone" ) << QByteArray("a_z" ) << true; | 
| 905 |     QTest::newRow(dataTag: ".z alone" ) << QByteArray(".z" ) << true; | 
| 906 |     QTest::newRow(dataTag: "_z alone" ) << QByteArray("_z" ) << true; | 
| 907 |     QTest::newRow(dataTag: "a z alone" ) << QByteArray("a z" ) << false; | 
| 908 |     QTest::newRow(dataTag: "a\\z alone" ) << QByteArray("a\\z" ) << false; | 
| 909 |     QTest::newRow(dataTag: "a,z alone" ) << QByteArray("a,z" ) << false; | 
| 910 |     QTest::newRow(dataTag: "/z alone" ) << QByteArray("/z" ) << false; | 
| 911 |     QTest::newRow(dataTag: "-z alone" ) << QByteArray("-z" ) << false; | 
| 912 | #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) | 
| 913 |     QTest::newRow("long alone" ) << QByteArray("12345678901234567" ) << true; | 
| 914 |     QTest::newRow("over-long alone" ) << QByteArray("123456789012345678" ) << false; | 
| 915 | #else | 
| 916 |     QTest::newRow(dataTag: "long alone" ) << QByteArray("12345678901234" ) << true; | 
| 917 |     QTest::newRow(dataTag: "over-long alone" ) << QByteArray("123456789012345" ) << false; | 
| 918 | #endif | 
| 919 |  | 
| 920 | #else | 
| 921 |     QSKIP("This test requires a Qt -developer-build." ); | 
| 922 | #endif // QT_BUILD_INTERNAL | 
| 923 | } | 
| 924 |  | 
| 925 | void tst_QTimeZone::isValidId() | 
| 926 | { | 
| 927 | #ifdef QT_BUILD_INTERNAL | 
| 928 |     QFETCH(QByteArray, input); | 
| 929 |     QFETCH(bool, valid); | 
| 930 |  | 
| 931 |     QCOMPARE(QTimeZonePrivate::isValidId(input), valid); | 
| 932 | #endif | 
| 933 | } | 
| 934 |  | 
| 935 | void tst_QTimeZone::malformed() | 
| 936 | { | 
| 937 |     // Regression test for QTBUG-92808 | 
| 938 |     // Strings that look enough like a POSIX zone specifier that the constructor | 
| 939 |     // accepts them, but the specifier is invalid. | 
| 940 |     // Must not crash or trigger assertions when calling offsetFromUtc() | 
| 941 |     const QDateTime now = QDateTime::currentDateTime(); | 
| 942 |     QTimeZone barf("QUT4tCZ0 , /" ); | 
| 943 |     if (barf.isValid()) | 
| 944 |         barf.offsetFromUtc(atDateTime: now); | 
| 945 |     barf = QTimeZone("QtC+09,,MA" ); | 
| 946 |     if (barf.isValid()) | 
| 947 |         barf.offsetFromUtc(atDateTime: now); | 
| 948 | } | 
| 949 |  | 
| 950 | void tst_QTimeZone::utcTest() | 
| 951 | { | 
| 952 | #ifdef QT_BUILD_INTERNAL | 
| 953 |     // Test default UTC constructor | 
| 954 |     QUtcTimeZonePrivate tzp; | 
| 955 |     QCOMPARE(tzp.isValid(),   true); | 
| 956 |     QCOMPARE(tzp.id(), QByteArray("UTC" )); | 
| 957 |     QCOMPARE(tzp.country(), QLocale::AnyCountry); | 
| 958 |     QCOMPARE(tzp.abbreviation(0), QString("UTC" )); | 
| 959 |     QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::LongName, QString()), QString("UTC" )); | 
| 960 |     QCOMPARE(tzp.offsetFromUtc(0), 0); | 
| 961 |     QCOMPARE(tzp.standardTimeOffset(0), 0); | 
| 962 |     QCOMPARE(tzp.daylightTimeOffset(0), 0); | 
| 963 |     QCOMPARE(tzp.hasDaylightTime(), false); | 
| 964 |     QCOMPARE(tzp.hasTransitions(), false); | 
| 965 |  | 
| 966 |     // Test create from UTC Offset (uses minimal id, skipping minutes if 0) | 
| 967 |     QDateTime now = QDateTime::currentDateTime(); | 
| 968 |     QTimeZone tz(36000); | 
| 969 |     QVERIFY(tz.isValid()); | 
| 970 |     QCOMPARE(tz.id(), QByteArray("UTC+10" )); | 
| 971 |     QCOMPARE(tz.offsetFromUtc(now), 36000); | 
| 972 |     QCOMPARE(tz.standardTimeOffset(now), 36000); | 
| 973 |     QCOMPARE(tz.daylightTimeOffset(now), 0); | 
| 974 |  | 
| 975 |     // Test invalid UTC offset, must be in range -14 to +14 hours | 
| 976 |     int min = -14*60*60; | 
| 977 |     int max = 14*60*60; | 
| 978 |     QCOMPARE(QTimeZone(min - 1).isValid(), false); | 
| 979 |     QCOMPARE(QTimeZone(min).isValid(), true); | 
| 980 |     QCOMPARE(QTimeZone(min + 1).isValid(), true); | 
| 981 |     QCOMPARE(QTimeZone(max - 1).isValid(), true); | 
| 982 |     QCOMPARE(QTimeZone(max).isValid(), true); | 
| 983 |     QCOMPARE(QTimeZone(max + 1).isValid(), false); | 
| 984 |  | 
| 985 |     // Test create from standard name (preserves :00 for minutes in id): | 
| 986 |     tz = QTimeZone("UTC+10:00" ); | 
| 987 |     QVERIFY(tz.isValid()); | 
| 988 |     QCOMPARE(tz.id(), QByteArray("UTC+10:00" )); | 
| 989 |     QCOMPARE(tz.offsetFromUtc(now), 36000); | 
| 990 |     QCOMPARE(tz.standardTimeOffset(now), 36000); | 
| 991 |     QCOMPARE(tz.daylightTimeOffset(now), 0); | 
| 992 |  | 
| 993 |     // Test create custom zone | 
| 994 |     tz = QTimeZone("QST" , 123456, "Qt Standard Time" , "QST" , QLocale::Norway, "Qt Testing" ); | 
| 995 |     QCOMPARE(tz.isValid(),   true); | 
| 996 |     QCOMPARE(tz.id(), QByteArray("QST" )); | 
| 997 |     QCOMPARE(tz.comment(), QString("Qt Testing" )); | 
| 998 |     QCOMPARE(tz.country(), QLocale::Norway); | 
| 999 |     QCOMPARE(tz.abbreviation(now), QString("QST" )); | 
| 1000 |     QCOMPARE(tz.displayName(QTimeZone::StandardTime, QTimeZone::LongName, QString()), | 
| 1001 |              QString("Qt Standard Time" )); | 
| 1002 |     QCOMPARE(tz.offsetFromUtc(now), 123456); | 
| 1003 |     QCOMPARE(tz.standardTimeOffset(now), 123456); | 
| 1004 |     QCOMPARE(tz.daylightTimeOffset(now), 0); | 
| 1005 | #endif // QT_BUILD_INTERNAL | 
| 1006 | } | 
| 1007 |  | 
| 1008 | void tst_QTimeZone::icuTest() | 
| 1009 | { | 
| 1010 | #if defined(QT_BUILD_INTERNAL) && QT_CONFIG(icu) | 
| 1011 |     // Known datetimes | 
| 1012 |     qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); | 
| 1013 |     qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); | 
| 1014 |  | 
| 1015 |     // Test default constructor | 
| 1016 |     QIcuTimeZonePrivate tzpd; | 
| 1017 |     QVERIFY(tzpd.isValid()); | 
| 1018 |  | 
| 1019 |     // Test invalid constructor | 
| 1020 |     QIcuTimeZonePrivate tzpi("Gondwana/Erewhon" ); | 
| 1021 |     QCOMPARE(tzpi.isValid(), false); | 
| 1022 |  | 
| 1023 |     // Test named constructor | 
| 1024 |     QIcuTimeZonePrivate tzp("Europe/Berlin" ); | 
| 1025 |     QVERIFY(tzp.isValid()); | 
| 1026 |  | 
| 1027 |     // Only test names in debug mode, names used can vary by ICU version installed | 
| 1028 |     if (debug) { | 
| 1029 |         // Test display names by type | 
| 1030 |         QLocale enUS("en_US" ); | 
| 1031 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::LongName, enUS), | 
| 1032 |                 QString("Central European Standard Time" )); | 
| 1033 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::ShortName, enUS), | 
| 1034 |                 QString("GMT+01:00" )); | 
| 1035 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::OffsetName, enUS), | 
| 1036 |                 QString("UTC+01:00" )); | 
| 1037 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::LongName, enUS), | 
| 1038 |                 QString("Central European Summer Time" )); | 
| 1039 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, enUS), | 
| 1040 |                 QString("GMT+02:00" )); | 
| 1041 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::OffsetName, enUS), | 
| 1042 |                 QString("UTC+02:00" )); | 
| 1043 |         // ICU C api does not support Generic Time yet, C++ api does | 
| 1044 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::LongName, enUS), | 
| 1045 |                 QString("Central European Standard Time" )); | 
| 1046 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::ShortName, enUS), | 
| 1047 |                 QString("GMT+01:00" )); | 
| 1048 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::OffsetName, enUS), | 
| 1049 |                 QString("UTC+01:00" )); | 
| 1050 |  | 
| 1051 |         // Test Abbreviations | 
| 1052 |         QCOMPARE(tzp.abbreviation(std), QString("CET" )); | 
| 1053 |         QCOMPARE(tzp.abbreviation(dst), QString("CEST" )); | 
| 1054 |     } | 
| 1055 |  | 
| 1056 |     testCetPrivate(tzp); | 
| 1057 |     testEpochTranPrivate(tzp: QIcuTimeZonePrivate("America/Toronto" )); | 
| 1058 | #endif // icu | 
| 1059 | } | 
| 1060 |  | 
| 1061 | void tst_QTimeZone::tzTest() | 
| 1062 | { | 
| 1063 | #if defined QT_BUILD_INTERNAL && defined Q_OS_UNIX && !defined Q_OS_DARWIN && !defined Q_OS_ANDROID | 
| 1064 |     // Known datetimes | 
| 1065 |     qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); | 
| 1066 |     qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); | 
| 1067 |  | 
| 1068 |     // Test default constructor | 
| 1069 |     QTzTimeZonePrivate tzpd; | 
| 1070 |     QVERIFY(tzpd.isValid()); | 
| 1071 |  | 
| 1072 |     // Test invalid constructor | 
| 1073 |     QTzTimeZonePrivate tzpi("Gondwana/Erewhon" ); | 
| 1074 |     QCOMPARE(tzpi.isValid(), false); | 
| 1075 |  | 
| 1076 |     // Test named constructor | 
| 1077 |     QTzTimeZonePrivate tzp("Europe/Berlin" ); | 
| 1078 |     QVERIFY(tzp.isValid()); | 
| 1079 |  | 
| 1080 |     // Test POSIX-format value for $TZ: | 
| 1081 |     QTzTimeZonePrivate tzposix("MET-1METDST-2,M3.5.0/02:00:00,M10.5.0/03:00:00" ); | 
| 1082 |     QVERIFY(tzposix.isValid()); | 
| 1083 |  | 
| 1084 |     QTimeZone tzBrazil("BRT+3" ); // parts of Northern Brazil, as a POSIX rule | 
| 1085 |     QVERIFY(tzBrazil.isValid()); | 
| 1086 |     QCOMPARE(tzBrazil.offsetFromUtc(QDateTime(QDate(1111, 11, 11).startOfDay())), -10800); | 
| 1087 |  | 
| 1088 |     // Test display names by type, either ICU or abbreviation only | 
| 1089 |     QLocale enUS("en_US" ); | 
| 1090 |     // Only test names in debug mode, names used can vary by ICU version installed | 
| 1091 |     if (debug) { | 
| 1092 | #if QT_CONFIG(icu) | 
| 1093 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::LongName, enUS), | 
| 1094 |                 QString("Central European Standard Time" )); | 
| 1095 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::ShortName, enUS), | 
| 1096 |                 QString("GMT+01:00" )); | 
| 1097 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::OffsetName, enUS), | 
| 1098 |                 QString("UTC+01:00" )); | 
| 1099 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::LongName, enUS), | 
| 1100 |                 QString("Central European Summer Time" )); | 
| 1101 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, enUS), | 
| 1102 |                 QString("GMT+02:00" )); | 
| 1103 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::OffsetName, enUS), | 
| 1104 |                 QString("UTC+02:00" )); | 
| 1105 |         // ICU C api does not support Generic Time yet, C++ api does | 
| 1106 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::LongName, enUS), | 
| 1107 |                 QString("Central European Standard Time" )); | 
| 1108 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::ShortName, enUS), | 
| 1109 |                 QString("GMT+01:00" )); | 
| 1110 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::OffsetName, enUS), | 
| 1111 |                 QString("UTC+01:00" )); | 
| 1112 | #else | 
| 1113 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::LongName, enUS), | 
| 1114 |                 QString("CET" )); | 
| 1115 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::ShortName, enUS), | 
| 1116 |                 QString("CET" )); | 
| 1117 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::OffsetName, enUS), | 
| 1118 |                 QString("CET" )); | 
| 1119 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::LongName, enUS), | 
| 1120 |                 QString("CEST" )); | 
| 1121 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, enUS), | 
| 1122 |                 QString("CEST" )); | 
| 1123 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::OffsetName, enUS), | 
| 1124 |                 QString("CEST" )); | 
| 1125 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::LongName, enUS), | 
| 1126 |                 QString("CET" )); | 
| 1127 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::ShortName, enUS), | 
| 1128 |                 QString("CET" )); | 
| 1129 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::OffsetName, enUS), | 
| 1130 |                 QString("CET" )); | 
| 1131 | #endif // icu | 
| 1132 |  | 
| 1133 |         // Test Abbreviations | 
| 1134 |         QCOMPARE(tzp.abbreviation(std), QString("CET" )); | 
| 1135 |         QCOMPARE(tzp.abbreviation(dst), QString("CEST" )); | 
| 1136 |     } | 
| 1137 |  | 
| 1138 |     testCetPrivate(tzp); | 
| 1139 |     testEpochTranPrivate(tzp: QTzTimeZonePrivate("America/Toronto" )); | 
| 1140 |  | 
| 1141 |     // Test first and last transition rule | 
| 1142 |     // Warning: This could vary depending on age of TZ file! | 
| 1143 |  | 
| 1144 |     // Test low date uses first rule found | 
| 1145 |     // Note: Depending on the OS in question, the database may be carrying the | 
| 1146 |     // Local Mean Time. which for Berlin is 0:53:28 | 
| 1147 |     QTimeZonePrivate::Data dat = tzp.data(forMSecsSinceEpoch: -9999999999999); | 
| 1148 |     QCOMPARE(dat.atMSecsSinceEpoch, (qint64)-9999999999999); | 
| 1149 |     QCOMPARE(dat.daylightTimeOffset, 0); | 
| 1150 |     if (dat.abbreviation == "LMT" ) { | 
| 1151 |         QCOMPARE(dat.standardTimeOffset, 3208); | 
| 1152 |     } else { | 
| 1153 |         QCOMPARE(dat.standardTimeOffset, 3600); | 
| 1154 |  | 
| 1155 |         // Test previous to low value is invalid | 
| 1156 |         dat = tzp.previousTransition(beforeMSecsSinceEpoch: -9999999999999); | 
| 1157 |         QCOMPARE(dat.atMSecsSinceEpoch, std::numeric_limits<qint64>::min()); | 
| 1158 |         QCOMPARE(dat.standardTimeOffset, std::numeric_limits<int>::min()); | 
| 1159 |         QCOMPARE(dat.daylightTimeOffset, std::numeric_limits<int>::min()); | 
| 1160 |     } | 
| 1161 |  | 
| 1162 |     dat = tzp.nextTransition(afterMSecsSinceEpoch: -9999999999999); | 
| 1163 |     QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::OffsetFromUTC, 3600), | 
| 1164 |              QDateTime(QDate(1893, 4, 1), QTime(0, 6, 32), Qt::OffsetFromUTC, 3600)); | 
| 1165 |     QCOMPARE(dat.standardTimeOffset, 3600); | 
| 1166 |     QCOMPARE(dat.daylightTimeOffset, 0); | 
| 1167 |  | 
| 1168 |     // Date-times late enough to exercise POSIX rules: | 
| 1169 |     qint64 stdHi = QDate(2100, 1, 1).startOfDay(spec: Qt::UTC).toMSecsSinceEpoch(); | 
| 1170 |     qint64 dstHi = QDate(2100, 6, 1).startOfDay(spec: Qt::UTC).toMSecsSinceEpoch(); | 
| 1171 |     // Relevant last Sundays in October and March: | 
| 1172 |     QCOMPARE(Qt::DayOfWeek(QDate(2099, 10, 25).dayOfWeek()), Qt::Sunday); | 
| 1173 |     QCOMPARE(Qt::DayOfWeek(QDate(2100, 3, 28).dayOfWeek()), Qt::Sunday); | 
| 1174 |     QCOMPARE(Qt::DayOfWeek(QDate(2100, 10, 31).dayOfWeek()), Qt::Sunday); | 
| 1175 |  | 
| 1176 |     dat = tzp.data(forMSecsSinceEpoch: stdHi); | 
| 1177 |     QCOMPARE(dat.atMSecsSinceEpoch - stdHi, (qint64)0); | 
| 1178 |     QCOMPARE(dat.offsetFromUtc, 3600); | 
| 1179 |     QCOMPARE(dat.standardTimeOffset, 3600); | 
| 1180 |     QCOMPARE(dat.daylightTimeOffset, 0); | 
| 1181 |  | 
| 1182 |     dat = tzp.data(forMSecsSinceEpoch: dstHi); | 
| 1183 |     QCOMPARE(dat.atMSecsSinceEpoch - dstHi, (qint64)0); | 
| 1184 |     QCOMPARE(dat.offsetFromUtc, 7200); | 
| 1185 |     QCOMPARE(dat.standardTimeOffset, 3600); | 
| 1186 |     QCOMPARE(dat.daylightTimeOffset, 3600); | 
| 1187 |  | 
| 1188 |     dat = tzp.previousTransition(beforeMSecsSinceEpoch: stdHi); | 
| 1189 |     QCOMPARE(dat.abbreviation, QStringLiteral("CET" )); | 
| 1190 |     QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::UTC), | 
| 1191 |              QDateTime(QDate(2099, 10, 25), QTime(3, 0), Qt::OffsetFromUTC, 7200)); | 
| 1192 |     QCOMPARE(dat.offsetFromUtc, 3600); | 
| 1193 |     QCOMPARE(dat.standardTimeOffset, 3600); | 
| 1194 |     QCOMPARE(dat.daylightTimeOffset, 0); | 
| 1195 |  | 
| 1196 |     dat = tzp.previousTransition(beforeMSecsSinceEpoch: dstHi); | 
| 1197 |     QCOMPARE(dat.abbreviation, QStringLiteral("CEST" )); | 
| 1198 |     QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::UTC), | 
| 1199 |              QDateTime(QDate(2100, 3, 28), QTime(2, 0), Qt::OffsetFromUTC, 3600)); | 
| 1200 |     QCOMPARE(dat.offsetFromUtc, 7200); | 
| 1201 |     QCOMPARE(dat.standardTimeOffset, 3600); | 
| 1202 |     QCOMPARE(dat.daylightTimeOffset, 3600); | 
| 1203 |  | 
| 1204 |     dat = tzp.nextTransition(afterMSecsSinceEpoch: stdHi); | 
| 1205 |     QCOMPARE(dat.abbreviation, QStringLiteral("CEST" )); | 
| 1206 |     QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::UTC), | 
| 1207 |              QDateTime(QDate(2100, 3, 28), QTime(2, 0), Qt::OffsetFromUTC, 3600)); | 
| 1208 |     QCOMPARE(dat.offsetFromUtc, 7200); | 
| 1209 |     QCOMPARE(dat.standardTimeOffset, 3600); | 
| 1210 |     QCOMPARE(dat.daylightTimeOffset, 3600); | 
| 1211 |  | 
| 1212 |     dat = tzp.nextTransition(afterMSecsSinceEpoch: dstHi); | 
| 1213 |     QCOMPARE(dat.abbreviation, QStringLiteral("CET" )); | 
| 1214 |     QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::OffsetFromUTC, 3600), | 
| 1215 |              QDateTime(QDate(2100, 10, 31), QTime(3, 0), Qt::OffsetFromUTC, 7200)); | 
| 1216 |     QCOMPARE(dat.offsetFromUtc, 3600); | 
| 1217 |     QCOMPARE(dat.standardTimeOffset, 3600); | 
| 1218 |     QCOMPARE(dat.daylightTimeOffset, 0); | 
| 1219 |  | 
| 1220 |     // Test TZ timezone vs UTC timezone for fractionary negative offset | 
| 1221 |     QTzTimeZonePrivate  tztz1("America/Caracas" ); | 
| 1222 |     QUtcTimeZonePrivate tzutc1("UTC-04:30" ); | 
| 1223 |     QVERIFY(tztz1.isValid()); | 
| 1224 |     QVERIFY(tzutc1.isValid()); | 
| 1225 |     QTzTimeZonePrivate::Data datatz1 = tztz1.data(forMSecsSinceEpoch: std); | 
| 1226 |     QTzTimeZonePrivate::Data datautc1 = tzutc1.data(forMSecsSinceEpoch: std); | 
| 1227 |     QCOMPARE(datatz1.offsetFromUtc, datautc1.offsetFromUtc); | 
| 1228 |  | 
| 1229 |     // Test TZ timezone vs UTC timezone for fractionary positive offset | 
| 1230 |     QTzTimeZonePrivate  tztz2("Asia/Calcutta" ); | 
| 1231 |     QUtcTimeZonePrivate tzutc2("UTC+05:30" ); | 
| 1232 |     QVERIFY(tztz2.isValid()); | 
| 1233 |     QVERIFY(tzutc2.isValid()); | 
| 1234 |     QTzTimeZonePrivate::Data datatz2 = tztz2.data(forMSecsSinceEpoch: std); | 
| 1235 |     QTzTimeZonePrivate::Data datautc2 = tzutc2.data(forMSecsSinceEpoch: std); | 
| 1236 |     QCOMPARE(datatz2.offsetFromUtc, datautc2.offsetFromUtc); | 
| 1237 |  | 
| 1238 |     // Test a timezone with a name that isn't all letters | 
| 1239 |     QTzTimeZonePrivate tzBarnaul("Asia/Barnaul" ); | 
| 1240 |     if (tzBarnaul.isValid()) { | 
| 1241 |         QCOMPARE(tzBarnaul.data(std).abbreviation, QString("+07" )); | 
| 1242 |  | 
| 1243 |         // first full day of the new rule (tzdata2016b) | 
| 1244 |         QDateTime dt(QDate(2016, 3, 28), QTime(0, 0, 0), Qt::UTC); | 
| 1245 |         QCOMPARE(tzBarnaul.data(dt.toMSecsSinceEpoch()).abbreviation, QString("+07" )); | 
| 1246 |     } | 
| 1247 | #endif // QT_BUILD_INTERNAL && Q_OS_UNIX && !Q_OS_DARWIN | 
| 1248 | } | 
| 1249 |  | 
| 1250 | void tst_QTimeZone::macTest() | 
| 1251 | { | 
| 1252 | #if defined(QT_BUILD_INTERNAL) && defined(Q_OS_DARWIN) | 
| 1253 |     // Known datetimes | 
| 1254 |     qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); | 
| 1255 |     qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); | 
| 1256 |  | 
| 1257 |     // Test default constructor | 
| 1258 |     QMacTimeZonePrivate tzpd; | 
| 1259 |     QVERIFY(tzpd.isValid()); | 
| 1260 |  | 
| 1261 |     // Test invalid constructor | 
| 1262 |     QMacTimeZonePrivate tzpi("Gondwana/Erewhon" ); | 
| 1263 |     QCOMPARE(tzpi.isValid(), false); | 
| 1264 |  | 
| 1265 |     // Test named constructor | 
| 1266 |     QMacTimeZonePrivate tzp("Europe/Berlin" ); | 
| 1267 |     QVERIFY(tzp.isValid()); | 
| 1268 |  | 
| 1269 |     // Only test names in debug mode, names used can vary by version | 
| 1270 |     if (debug) { | 
| 1271 |         // Test display names by type | 
| 1272 |         QLocale enUS("en_US" ); | 
| 1273 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::LongName, enUS), | 
| 1274 |                 QString("Central European Standard Time" )); | 
| 1275 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::ShortName, enUS), | 
| 1276 |                 QString("GMT+01:00" )); | 
| 1277 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::OffsetName, enUS), | 
| 1278 |                 QString("UTC+01:00" )); | 
| 1279 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::LongName, enUS), | 
| 1280 |                 QString("Central European Summer Time" )); | 
| 1281 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, enUS), | 
| 1282 |                 QString("GMT+02:00" )); | 
| 1283 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::OffsetName, enUS), | 
| 1284 |                 QString("UTC+02:00" )); | 
| 1285 |         // ICU C api does not support Generic Time yet, C++ api does | 
| 1286 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::LongName, enUS), | 
| 1287 |                 QString("Central European Time" )); | 
| 1288 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::ShortName, enUS), | 
| 1289 |                 QString("Germany Time" )); | 
| 1290 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::OffsetName, enUS), | 
| 1291 |                 QString("UTC+01:00" )); | 
| 1292 |  | 
| 1293 |         // Test Abbreviations | 
| 1294 |         QCOMPARE(tzp.abbreviation(std), QString("CET" )); | 
| 1295 |         QCOMPARE(tzp.abbreviation(dst), QString("CEST" )); | 
| 1296 |     } | 
| 1297 |  | 
| 1298 |     testCetPrivate(tzp); | 
| 1299 |     testEpochTranPrivate(QMacTimeZonePrivate("America/Toronto" )); | 
| 1300 | #endif // QT_BUILD_INTERNAL && Q_OS_DARWIN | 
| 1301 | } | 
| 1302 |  | 
| 1303 | void tst_QTimeZone::darwinTypes() | 
| 1304 | { | 
| 1305 | #ifndef Q_OS_DARWIN | 
| 1306 |     QSKIP("This is an Apple-only test" ); | 
| 1307 | #else | 
| 1308 |     extern void tst_QTimeZone_darwinTypes(); // in tst_qtimezone_darwin.mm | 
| 1309 |     tst_QTimeZone_darwinTypes(); | 
| 1310 | #endif | 
| 1311 | } | 
| 1312 |  | 
| 1313 | void tst_QTimeZone::winTest() | 
| 1314 | { | 
| 1315 | #if defined(QT_BUILD_INTERNAL) && defined(USING_WIN_TZ) | 
| 1316 |     // Known datetimes | 
| 1317 |     qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); | 
| 1318 |     qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); | 
| 1319 |  | 
| 1320 |     // Test default constructor | 
| 1321 |     QWinTimeZonePrivate tzpd; | 
| 1322 |     if (debug) | 
| 1323 |         qDebug() << "System ID = "  << tzpd.id() | 
| 1324 |                  << tzpd.displayName(QTimeZone::StandardTime, QTimeZone::LongName, QLocale()) | 
| 1325 |                  << tzpd.displayName(QTimeZone::GenericTime, QTimeZone::LongName, QLocale()); | 
| 1326 |     QVERIFY(tzpd.isValid()); | 
| 1327 |  | 
| 1328 |     // Test invalid constructor | 
| 1329 |     QWinTimeZonePrivate tzpi("Gondwana/Erewhon" ); | 
| 1330 |     QCOMPARE(tzpi.isValid(), false); | 
| 1331 |  | 
| 1332 |     // Test named constructor | 
| 1333 |     QWinTimeZonePrivate tzp("Europe/Berlin" ); | 
| 1334 |     QVERIFY(tzp.isValid()); | 
| 1335 |  | 
| 1336 |     // Only test names in debug mode, names used can vary by version | 
| 1337 |     if (debug) { | 
| 1338 |         // Test display names by type | 
| 1339 |         QLocale enUS("en_US" ); | 
| 1340 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::LongName, enUS), | 
| 1341 |                 QString("W. Europe Standard Time" )); | 
| 1342 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::ShortName, enUS), | 
| 1343 |                 QString("W. Europe Standard Time" )); | 
| 1344 |         QCOMPARE(tzp.displayName(QTimeZone::StandardTime, QTimeZone::OffsetName, enUS), | 
| 1345 |                 QString("UTC+01:00" )); | 
| 1346 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::LongName, enUS), | 
| 1347 |                 QString("W. Europe Daylight Time" )); | 
| 1348 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, enUS), | 
| 1349 |                 QString("W. Europe Daylight Time" )); | 
| 1350 |         QCOMPARE(tzp.displayName(QTimeZone::DaylightTime, QTimeZone::OffsetName, enUS), | 
| 1351 |                 QString("UTC+02:00" )); | 
| 1352 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::LongName, enUS), | 
| 1353 |                 QString("(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna" )); | 
| 1354 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::ShortName, enUS), | 
| 1355 |                 QString("(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna" )); | 
| 1356 |         QCOMPARE(tzp.displayName(QTimeZone::GenericTime, QTimeZone::OffsetName, enUS), | 
| 1357 |                 QString("UTC+01:00" )); | 
| 1358 |  | 
| 1359 |         // Test Abbreviations | 
| 1360 |         QCOMPARE(tzp.abbreviation(std), QString("W. Europe Standard Time" )); | 
| 1361 |         QCOMPARE(tzp.abbreviation(dst), QString("W. Europe Daylight Time" )); | 
| 1362 |     } | 
| 1363 |  | 
| 1364 |     testCetPrivate(tzp); | 
| 1365 |     testEpochTranPrivate(QWinTimeZonePrivate("America/Toronto" )); | 
| 1366 | #endif // QT_BUILD_INTERNAL && USING_WIN_TZ | 
| 1367 | } | 
| 1368 |  | 
| 1369 | #ifdef QT_BUILD_INTERNAL | 
| 1370 | // Test each private produces the same basic results for CET | 
| 1371 | void tst_QTimeZone::testCetPrivate(const QTimeZonePrivate &tzp) | 
| 1372 | { | 
| 1373 |     // Known datetimes | 
| 1374 |     qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); | 
| 1375 |     qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); | 
| 1376 |     qint64 prev = QDateTime(QDate(2011, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); | 
| 1377 |  | 
| 1378 |     QCOMPARE(tzp.offsetFromUtc(std), 3600); | 
| 1379 |     QCOMPARE(tzp.offsetFromUtc(dst), 7200); | 
| 1380 |  | 
| 1381 |     QCOMPARE(tzp.standardTimeOffset(std), 3600); | 
| 1382 |     QCOMPARE(tzp.standardTimeOffset(dst), 3600); | 
| 1383 |  | 
| 1384 |     QCOMPARE(tzp.daylightTimeOffset(std), 0); | 
| 1385 |     QCOMPARE(tzp.daylightTimeOffset(dst), 3600); | 
| 1386 |  | 
| 1387 |     QCOMPARE(tzp.hasDaylightTime(), true); | 
| 1388 |     QCOMPARE(tzp.isDaylightTime(std), false); | 
| 1389 |     QCOMPARE(tzp.isDaylightTime(dst), true); | 
| 1390 |  | 
| 1391 |     QTimeZonePrivate::Data dat = tzp.data(forMSecsSinceEpoch: std); | 
| 1392 |     QCOMPARE(dat.atMSecsSinceEpoch, std); | 
| 1393 |     QCOMPARE(dat.offsetFromUtc, 3600); | 
| 1394 |     QCOMPARE(dat.standardTimeOffset, 3600); | 
| 1395 |     QCOMPARE(dat.daylightTimeOffset, 0); | 
| 1396 |     QCOMPARE(dat.abbreviation, tzp.abbreviation(std)); | 
| 1397 |  | 
| 1398 |     dat = tzp.data(forMSecsSinceEpoch: dst); | 
| 1399 |     QCOMPARE(dat.atMSecsSinceEpoch, dst); | 
| 1400 |     QCOMPARE(dat.offsetFromUtc, 7200); | 
| 1401 |     QCOMPARE(dat.standardTimeOffset, 3600); | 
| 1402 |     QCOMPARE(dat.daylightTimeOffset, 3600); | 
| 1403 |     QCOMPARE(dat.abbreviation, tzp.abbreviation(dst)); | 
| 1404 |  | 
| 1405 |     // Only test transitions if host system supports them | 
| 1406 |     if (tzp.hasTransitions()) { | 
| 1407 |         QTimeZonePrivate::Data tran = tzp.nextTransition(afterMSecsSinceEpoch: std); | 
| 1408 |         // 2012-03-25 02:00 CET, +1 -> +2 | 
| 1409 |         QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC), | 
| 1410 |                  QDateTime(QDate(2012, 3, 25), QTime(2, 0), Qt::OffsetFromUTC, 3600)); | 
| 1411 |         QCOMPARE(tran.offsetFromUtc, 7200); | 
| 1412 |         QCOMPARE(tran.standardTimeOffset, 3600); | 
| 1413 |         QCOMPARE(tran.daylightTimeOffset, 3600); | 
| 1414 |  | 
| 1415 |         tran = tzp.nextTransition(afterMSecsSinceEpoch: dst); | 
| 1416 |         // 2012-10-28 03:00 CEST, +2 -> +1 | 
| 1417 |         QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC), | 
| 1418 |                  QDateTime(QDate(2012, 10, 28), QTime(3, 0), Qt::OffsetFromUTC, 2 * 3600)); | 
| 1419 |         QCOMPARE(tran.offsetFromUtc, 3600); | 
| 1420 |         QCOMPARE(tran.standardTimeOffset, 3600); | 
| 1421 |         QCOMPARE(tran.daylightTimeOffset, 0); | 
| 1422 |  | 
| 1423 |         tran = tzp.previousTransition(beforeMSecsSinceEpoch: std); | 
| 1424 |         // 2011-10-30 03:00 CEST, +2 -> +1 | 
| 1425 |         QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC), | 
| 1426 |                  QDateTime(QDate(2011, 10, 30), QTime(3, 0), Qt::OffsetFromUTC, 2 * 3600)); | 
| 1427 |         QCOMPARE(tran.offsetFromUtc, 3600); | 
| 1428 |         QCOMPARE(tran.standardTimeOffset, 3600); | 
| 1429 |         QCOMPARE(tran.daylightTimeOffset, 0); | 
| 1430 |  | 
| 1431 |         tran = tzp.previousTransition(beforeMSecsSinceEpoch: dst); | 
| 1432 |         // 2012-03-25 02:00 CET, +1 -> +2 (again) | 
| 1433 |         QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC), | 
| 1434 |                  QDateTime(QDate(2012, 3, 25), QTime(2, 0), Qt::OffsetFromUTC, 3600)); | 
| 1435 |         QCOMPARE(tran.offsetFromUtc, 7200); | 
| 1436 |         QCOMPARE(tran.standardTimeOffset, 3600); | 
| 1437 |         QCOMPARE(tran.daylightTimeOffset, 3600); | 
| 1438 |  | 
| 1439 |         QTimeZonePrivate::DataList expected; | 
| 1440 |         // 2011-03-27 02:00 CET, +1 -> +2 | 
| 1441 |         tran.atMSecsSinceEpoch = QDateTime(QDate(2011, 3, 27), QTime(2, 0), | 
| 1442 |                                            Qt::OffsetFromUTC, 3600).toMSecsSinceEpoch(); | 
| 1443 |         tran.offsetFromUtc = 7200; | 
| 1444 |         tran.standardTimeOffset = 3600; | 
| 1445 |         tran.daylightTimeOffset = 3600; | 
| 1446 |         expected << tran; | 
| 1447 |         // 2011-10-30 03:00 CEST, +2 -> +1 | 
| 1448 |         tran.atMSecsSinceEpoch = QDateTime(QDate(2011, 10, 30), QTime(3, 0), | 
| 1449 |                                            Qt::OffsetFromUTC, 2 * 3600).toMSecsSinceEpoch(); | 
| 1450 |         tran.offsetFromUtc = 3600; | 
| 1451 |         tran.standardTimeOffset = 3600; | 
| 1452 |         tran.daylightTimeOffset = 0; | 
| 1453 |         expected << tran; | 
| 1454 |         QTimeZonePrivate::DataList result = tzp.transitions(fromMSecsSinceEpoch: prev, toMSecsSinceEpoch: std); | 
| 1455 |         QCOMPARE(result.count(), expected.count()); | 
| 1456 |         for (int i = 0; i < expected.count(); ++i) { | 
| 1457 |             QCOMPARE(QDateTime::fromMSecsSinceEpoch(result.at(i).atMSecsSinceEpoch, | 
| 1458 |                                                     Qt::OffsetFromUTC, 3600), | 
| 1459 |                      QDateTime::fromMSecsSinceEpoch(expected.at(i).atMSecsSinceEpoch, | 
| 1460 |                                                     Qt::OffsetFromUTC, 3600)); | 
| 1461 |             QCOMPARE(result.at(i).offsetFromUtc, expected.at(i).offsetFromUtc); | 
| 1462 |             QCOMPARE(result.at(i).standardTimeOffset, expected.at(i).standardTimeOffset); | 
| 1463 |             QCOMPARE(result.at(i).daylightTimeOffset, expected.at(i).daylightTimeOffset); | 
| 1464 |         } | 
| 1465 |     } | 
| 1466 | } | 
| 1467 |  | 
| 1468 | // Needs a zone with DST around the epoch; currently America/Toronto (EST5EDT) | 
| 1469 | void tst_QTimeZone::testEpochTranPrivate(const QTimeZonePrivate &tzp) | 
| 1470 | { | 
| 1471 |     if (!tzp.hasTransitions()) | 
| 1472 |         return; // test only viable for transitions | 
| 1473 |  | 
| 1474 |     QTimeZonePrivate::Data tran = tzp.nextTransition(afterMSecsSinceEpoch: 0); // i.e. first after epoch | 
| 1475 |     // 1970-04-26 02:00 EST, -5 -> -4 | 
| 1476 |     const QDateTime after = QDateTime(QDate(1970, 4, 26), QTime(2, 0), Qt::OffsetFromUTC, -5 * 3600); | 
| 1477 |     const QDateTime found = QDateTime::fromMSecsSinceEpoch(msecs: tran.atMSecsSinceEpoch, spec: Qt::UTC); | 
| 1478 | #ifdef USING_WIN_TZ // MS gets the date wrong: 5th April instead of 26th. | 
| 1479 |     QCOMPARE(found.toOffsetFromUtc(-5 * 3600).time(), after.time()); | 
| 1480 | #else | 
| 1481 |     QCOMPARE(found, after); | 
| 1482 | #endif | 
| 1483 |     QCOMPARE(tran.offsetFromUtc, -4 * 3600); | 
| 1484 |     QCOMPARE(tran.standardTimeOffset, -5 * 3600); | 
| 1485 |     QCOMPARE(tran.daylightTimeOffset, 3600); | 
| 1486 |  | 
| 1487 |     // Pre-epoch time-zones might not be supported at all: | 
| 1488 |     tran = tzp.nextTransition(afterMSecsSinceEpoch: QDateTime(QDate(1601, 1, 1), QTime(0, 0), | 
| 1489 |                                         Qt::UTC).toMSecsSinceEpoch()); | 
| 1490 |     if (tran.atMSecsSinceEpoch != QTimeZonePrivate::invalidMSecs() | 
| 1491 |         // Toronto *did* have a transition before 1970 (DST since 1918): | 
| 1492 |         && tran.atMSecsSinceEpoch < 0) { | 
| 1493 |         // ... but, if they are, we should be able to search back to them: | 
| 1494 |         tran = tzp.previousTransition(beforeMSecsSinceEpoch: 0); // i.e. last before epoch | 
| 1495 |         // 1969-10-26 02:00 EDT, -4 -> -5 | 
| 1496 |         QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC), | 
| 1497 |                  QDateTime(QDate(1969, 10, 26), QTime(2, 0), Qt::OffsetFromUTC, -4 * 3600)); | 
| 1498 |         QCOMPARE(tran.offsetFromUtc, -5 * 3600); | 
| 1499 |         QCOMPARE(tran.standardTimeOffset, -5 * 3600); | 
| 1500 |         QCOMPARE(tran.daylightTimeOffset, 0); | 
| 1501 |     } else { | 
| 1502 |         // Do not use QSKIP(): that would discard the rest of this sub-test's caller. | 
| 1503 |         qDebug() << "No support for pre-epoch time-zone transitions" ; | 
| 1504 |     } | 
| 1505 | } | 
| 1506 | #endif // QT_BUILD_INTERNAL | 
| 1507 |  | 
| 1508 | QTEST_APPLESS_MAIN(tst_QTimeZone) | 
| 1509 | #include "tst_qtimezone.moc" | 
| 1510 |  |