8# include "qtimezoneprivate_p.h"
11#include <QtCore/qdatastream.h>
12#include <QtCore/qdatetime.h>
20static_assert(!std::is_constructible_v<QTimeZone, Qt::TimeSpec>);
21using namespace Qt::StringLiterals;
23#if QT_CONFIG(timezone)
25static QTimeZonePrivate *newBackendTimeZone()
27#if QT_CONFIG(timezone_tzdb)
28 return new QChronoTimeZonePrivate();
29#elif defined(Q_OS_DARWIN)
30 return new QMacTimeZonePrivate();
31#elif defined(Q_OS_ANDROID)
32 return new QAndroidTimeZonePrivate();
33#elif defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS)
34 return new QTzTimeZonePrivate();
36 return new QIcuTimeZonePrivate();
37#elif defined(Q_OS_WIN)
38 return new QWinTimeZonePrivate();
40 return new QUtcTimeZonePrivate();
45static QTimeZonePrivate *newBackendTimeZone(
const QByteArray &ianaId)
47 Q_ASSERT(!ianaId.isEmpty());
48#if QT_CONFIG(timezone_tzdb)
49 return new QChronoTimeZonePrivate(ianaId);
50#elif defined(Q_OS_DARWIN)
51 return new QMacTimeZonePrivate(ianaId);
52#elif defined(Q_OS_ANDROID)
53 return new QAndroidTimeZonePrivate(ianaId);
54#elif defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS)
55 return new QTzTimeZonePrivate(ianaId);
57 return new QIcuTimeZonePrivate(ianaId);
58#elif defined(Q_OS_WIN)
59 return new QWinTimeZonePrivate(ianaId);
61 return new QUtcTimeZonePrivate(ianaId);
65class QTimeZoneSingleton
68 QTimeZoneSingleton() : backend(newBackendTimeZone()) {}
75 QExplicitlySharedDataPointer<QTimeZonePrivate> backend;
79Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz);
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
267
268
269
270
271
272
273
274
275
276
277
278
279
281#if QT_CONFIG(timezone)
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
367
368
369
370
371
372
375QTimeZone::Data::Data()
noexcept : d(
nullptr)
378 static_assert(
int(Qt::TimeZone) == 3);
381QTimeZone::Data::Data(
const Data &other)
noexcept
383#if QT_CONFIG(timezone)
384 if (!other.isShort() && other.d)
390QTimeZone::Data::Data(QTimeZonePrivate *dptr)
noexcept
393#if QT_CONFIG(timezone)
399QTimeZone::Data::~Data()
401#if QT_CONFIG(timezone)
402 if (!isShort() && d && !d->ref.deref())
408QTimeZone::Data &QTimeZone::Data::operator=(
const Data &other)
noexcept
410#if QT_CONFIG(timezone)
411 if (!other.isShort())
412 return *
this = other.d;
413 if (!isShort() && d && !d->ref.deref())
421
422
424QTimeZone::QTimeZone()
noexcept
427 static_assert(
sizeof(ShortData) <=
sizeof(Data::d));
429 static_assert(qintptr(1) << (
sizeof(
void *) * 8 - 2) >= MaxUtcOffsetSecs);
432#if QT_CONFIG(timezone)
433QTimeZone::Data &QTimeZone::Data::operator=(QTimeZonePrivate *dptr)
noexcept
438 if (d && !d->ref.deref())
444 Q_ASSERT(!isShort());
449
450
451
452
453
454
455
456
457
458
459
461QTimeZone::QTimeZone(
const QByteArray &ianaId)
465 d =
new QUtcTimeZonePrivate(ianaId);
468 if (ianaId.isEmpty()) {
469 d = newBackendTimeZone();
471 d = newBackendTimeZone(ianaId);
474 const QByteArray name = QTimeZonePrivate::aliasToIana(ianaId);
475 if (!name.isEmpty() && name != ianaId)
476 d = newBackendTimeZone(name);
483 qint64 offset = QUtcTimeZonePrivate::offsetFromUtcString(ianaId);
484 if (offset != QTimeZonePrivate::invalidSeconds()) {
486 qint32 seconds = qint32(offset);
487 Q_ASSERT(qint64(seconds) == offset);
489 d =
new QUtcTimeZonePrivate(seconds);
495
496
497
498
499
500
501
502
503
504
505
506
508QTimeZone::QTimeZone(
int offsetSeconds)
509 : d((offsetSeconds >= MinUtcOffsetSecs && offsetSeconds <= MaxUtcOffsetSecs)
510 ?
new QUtcTimeZonePrivate(offsetSeconds) :
nullptr)
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
538QTimeZone::QTimeZone(
const QByteArray &zoneId,
int offsetSeconds,
const QString &name,
539 const QString &abbreviation, QLocale::Territory territory,
const QString &comment)
540 : d(QUtcTimeZonePrivate().isTimeZoneIdAvailable(zoneId)
541 || global_tz->backend->isTimeZoneIdAvailable(zoneId)
543 :
new QUtcTimeZonePrivate(zoneId, offsetSeconds, name, abbreviation, territory, comment))
548
549
550
551
552
553
555QTimeZone::QTimeZone(QTimeZonePrivate &dd)
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
583QTimeZone QTimeZone::asBackendZone()
const
585 switch (timeSpec()) {
589 return systemTimeZone();
592 case Qt::OffsetFromUTC:
593 return QTimeZone(*
new QUtcTimeZonePrivate(
int(d.s.offset)));
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
620
621
622
623
624
625
626
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
651
652
653
654
655
656
657
658
659
660
661
662
665
666
667
668
669
670
671
672
675
676
677
678
679
682
683
684
685
686
687
688
689
690
691
694
695
697QTimeZone::QTimeZone(
const QTimeZone &other)
noexcept
703
704
705
706
709
710
712QTimeZone::~QTimeZone()
717
718
719
722
723
725QTimeZone &QTimeZone::operator=(
const QTimeZone &other)
732
733
734
735
736
739
740
741
742
743
744
745
746
747
750
751
752
753
754
755
756
757
758
763 return rhs.d.isShort() && lhs.d.s == rhs.d.s;
765 if (!rhs.d.isShort()) {
766 if (lhs.d.d == rhs.d.d)
768#if QT_CONFIG(timezone)
769 return lhs.d.d && rhs.d.d && *lhs.d.d == *rhs.d.d;
777
778
780bool QTimeZone::isValid()
const
782#if QT_CONFIG(timezone)
784 return d.d && d->isValid();
789#if QT_CONFIG(timezone)
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
821QByteArray QTimeZone::id()
const
824 switch (d.s.spec()) {
826 return QTimeZonePrivate::utcQByteArray();
828 return systemTimeZoneId();
829 case Qt::OffsetFromUTC:
830 return QUtcTimeZonePrivate(d.s.offset).id();
842
843
844
845
846
847
848
849
850
851
852
853
854
855bool QTimeZone::hasAlternativeName(QByteArrayView alias)
const
859 QByteArray mine = QTimeZonePrivate::aliasToIana(id());
861 if (!mine.isEmpty() && alias == mine)
863 QByteArray its = QTimeZonePrivate::aliasToIana(alias);
866 return !its.isEmpty() && its == (mine.isEmpty() ? id() : mine);
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884QLocale::Territory QTimeZone::territory()
const
887 if (d.s.spec() == Qt::LocalTime)
888 return systemTimeZone().territory();
889 }
else if (isValid()) {
890 return d->territory();
892 return QLocale::AnyTerritory;
895#if QT_DEPRECATED_SINCE(6
, 6
)
897
898
899
900
901
902
904QLocale::Country QTimeZone::country()
const
911
912
913
914
915
916
917
918
920QString QTimeZone::comment()
const
924 }
else if (isValid()) {
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
953QString QTimeZone::displayName(
const QDateTime &atDateTime, NameType nameType,
954 const QLocale &locale)
const
957 switch (d.s.spec()) {
959 return systemTimeZone().displayName(atDateTime, nameType, locale);
961 case Qt::OffsetFromUTC:
962 return QUtcTimeZonePrivate(d.s.offset).displayName(
963 atDateTime.toMSecsSinceEpoch(), nameType, locale);
968 }
else if (isValid()) {
969 return d->displayName(atDateTime.toMSecsSinceEpoch(), nameType, locale);
976
977
978
979
980
981
982
983
984
985
987QString QTimeZone::displayName(TimeType timeType, NameType nameType,
988 const QLocale &locale)
const
991 switch (d.s.spec()) {
993 return systemTimeZone().displayName(timeType, nameType, locale);
995 case Qt::OffsetFromUTC:
996 return QUtcTimeZonePrivate(d.s.offset).displayName(timeType, nameType, locale);
1001 }
else if (isValid()) {
1002 return d->displayName(timeType, nameType, locale);
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1023QString QTimeZone::abbreviation(
const QDateTime &atDateTime)
const
1026 switch (d.s.spec()) {
1028 return systemTimeZone().abbreviation(atDateTime);
1030 case Qt::OffsetFromUTC:
1031 return QUtcTimeZonePrivate(d.s.offset).abbreviation(atDateTime.toMSecsSinceEpoch());
1036 }
else if (isValid()) {
1037 return d->abbreviation(atDateTime.toMSecsSinceEpoch());
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1059int QTimeZone::offsetFromUtc(
const QDateTime &atDateTime)
const
1062 switch (d.s.spec()) {
1064 return systemTimeZone().offsetFromUtc(atDateTime);
1066 case Qt::OffsetFromUTC:
1072 }
else if (isValid()) {
1073 const int offset = d->offsetFromUtc(atDateTime.toMSecsSinceEpoch());
1074 if (offset != QTimeZonePrivate::invalidSeconds())
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1094int QTimeZone::standardTimeOffset(
const QDateTime &atDateTime)
const
1097 switch (d.s.spec()) {
1099 return systemTimeZone().standardTimeOffset(atDateTime);
1101 case Qt::OffsetFromUTC:
1107 }
else if (isValid()) {
1108 const int offset = d->standardTimeOffset(atDateTime.toMSecsSinceEpoch());
1109 if (offset != QTimeZonePrivate::invalidSeconds())
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1129int QTimeZone::daylightTimeOffset(
const QDateTime &atDateTime)
const
1132 switch (d.s.spec()) {
1134 return systemTimeZone().daylightTimeOffset(atDateTime);
1136 case Qt::OffsetFromUTC:
1142 }
else if (hasDaylightTime()) {
1143 const int offset = d->daylightTimeOffset(atDateTime.toMSecsSinceEpoch());
1144 if (offset != QTimeZonePrivate::invalidSeconds())
1151
1152
1153
1154
1155
1156
1158bool QTimeZone::hasDaylightTime()
const
1161 switch (d.s.spec()) {
1163 return systemTimeZone().hasDaylightTime();
1165 case Qt::OffsetFromUTC:
1171 }
else if (isValid()) {
1172 return d->hasDaylightTime();
1178
1179
1180
1181
1182
1183
1185bool QTimeZone::isDaylightTime(
const QDateTime &atDateTime)
const
1188 switch (d.s.spec()) {
1190 return systemTimeZone().isDaylightTime(atDateTime);
1192 case Qt::OffsetFromUTC:
1198 }
else if (hasDaylightTime()) {
1199 return d->isDaylightTime(atDateTime.toMSecsSinceEpoch());
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1218QTimeZone::OffsetData QTimeZone::offsetData(
const QDateTime &forDateTime)
const
1221 switch (d.s.spec()) {
1223 return systemTimeZone().offsetData(forDateTime);
1225 case Qt::OffsetFromUTC:
1226 return { abbreviation(forDateTime), forDateTime,
int(d.s.offset),
int(d.s.offset), 0 };
1233 return QTimeZonePrivate::toOffsetData(d->data(forDateTime.toMSecsSinceEpoch()));
1235 return QTimeZonePrivate::invalidOffsetData();
1239
1240
1241
1242
1243
1244
1245
1246
1247
1249bool QTimeZone::hasTransitions()
const
1252 switch (d.s.spec()) {
1254 return systemTimeZone().hasTransitions();
1256 case Qt::OffsetFromUTC:
1262 }
else if (isValid()) {
1263 return d->hasTransitions();
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1283QTimeZone::OffsetData QTimeZone::nextTransition(
const QDateTime &afterDateTime)
const
1286 switch (d.s.spec()) {
1288 return systemTimeZone().nextTransition(afterDateTime);
1290 case Qt::OffsetFromUTC:
1296 }
else if (hasTransitions()) {
1297 return QTimeZonePrivate::toOffsetData(d->nextTransition(afterDateTime.toMSecsSinceEpoch()));
1300 return QTimeZonePrivate::invalidOffsetData();
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1318QTimeZone::OffsetData QTimeZone::previousTransition(
const QDateTime &beforeDateTime)
const
1321 switch (d.s.spec()) {
1323 return systemTimeZone().previousTransition(beforeDateTime);
1325 case Qt::OffsetFromUTC:
1331 }
else if (hasTransitions()) {
1332 return QTimeZonePrivate::toOffsetData(
1333 d->previousTransition(beforeDateTime.toMSecsSinceEpoch()));
1336 return QTimeZonePrivate::invalidOffsetData();
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1351QTimeZone::OffsetDataList QTimeZone::transitions(
const QDateTime &fromDateTime,
1352 const QDateTime &toDateTime)
const
1354 OffsetDataList list;
1356 switch (d.s.spec()) {
1358 return systemTimeZone().transitions(fromDateTime, toDateTime);
1360 case Qt::OffsetFromUTC:
1366 }
else if (hasTransitions()) {
1367 const QTimeZonePrivate::DataList plist = d->transitions(fromDateTime.toMSecsSinceEpoch(),
1368 toDateTime.toMSecsSinceEpoch());
1369 list.reserve(plist.size());
1370 for (
const QTimeZonePrivate::Data &pdata : plist)
1371 list.append(QTimeZonePrivate::toOffsetData(pdata));
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1403QByteArray QTimeZone::systemTimeZoneId()
1405 QByteArray sys = global_tz->backend->systemTimeZoneId();
1409 return global_tz->backend->id();
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430QTimeZone QTimeZone::systemTimeZone()
1433 const QByteArray sysId = global_tz->backend->systemTimeZoneId();
1434 const auto sys = sysId.isEmpty() ? QTimeZone(global_tz->backend) : QTimeZone(sysId);
1435 if (!sys.isValid()) {
1436 static bool neverWarned =
true;
1439 neverWarned =
false;
1440 qWarning(
"Unable to determine system time zone: "
1441 "please check your system configuration.");
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459QTimeZone QTimeZonePrivate::utcQTimeZone()
1461 return QTimeZone(*
new QUtcTimeZonePrivate());
1464Q_GLOBAL_STATIC(QTimeZone, utcTimeZone, QTimeZonePrivate::utcQTimeZone());
1466QTimeZone QTimeZone::utc()
1468 if (Q_UNLIKELY(utcTimeZone.isDestroyed()))
1469 return QTimeZonePrivate::utcQTimeZone();
1470 return *utcTimeZone;
1474
1475
1476
1477
1478
1479
1480
1481
1482
1484bool QTimeZone::isTimeZoneIdAvailable(
const QByteArray &ianaId)
1486#if defined(Q_OS_UNIX) && !(QT_CONFIG(timezone_tzdb) || defined(Q_OS_DARWIN)
1487 || defined(Q_OS_ANDROID) || defined(Q_OS_VXWORKS))
1494 if (!QTimeZonePrivate::isValidId(ianaId))
1497 return QUtcTimeZonePrivate().isTimeZoneIdAvailable(ianaId)
1498 || QUtcTimeZonePrivate::offsetFromUtcString(ianaId) != QTimeZonePrivate::invalidSeconds()
1499 || global_tz->backend->isTimeZoneIdAvailable(ianaId);
1502[[maybe_unused]]
static bool isUniqueSorted(
const QList<QByteArray> &seq)
1507 return std::is_sorted(seq.begin(), seq.end(), std::less_equal<QByteArray>());
1510static QList<QByteArray> set_union(
const QList<QByteArray> &l1,
const QList<QByteArray> &l2)
1512 Q_ASSERT(isUniqueSorted(l1));
1513 Q_ASSERT(isUniqueSorted(l2));
1514 QList<QByteArray> result;
1515 result.reserve(l1.size() + l2.size());
1516 std::set_union(l1.begin(), l1.end(),
1517 l2.begin(), l2.end(),
1518 std::back_inserter(result));
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1534QList<QByteArray> QTimeZone::availableTimeZoneIds()
1538 return set_union(QUtcTimeZonePrivate().availableTimeZoneIds(),
1539 global_tz->backend->availableTimeZoneIds());
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1556QList<QByteArray> QTimeZone::availableTimeZoneIds(QLocale::Territory territory)
1558 return set_union(QUtcTimeZonePrivate().availableTimeZoneIds(territory),
1559 global_tz->backend->availableTimeZoneIds(territory));
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1575QList<QByteArray> QTimeZone::availableTimeZoneIds(
int offsetSeconds)
1577 return set_union(QUtcTimeZonePrivate().availableTimeZoneIds(offsetSeconds),
1578 global_tz->backend->availableTimeZoneIds(offsetSeconds));
1582
1583
1584
1585
1586
1587
1589QByteArray QTimeZone::ianaIdToWindowsId(
const QByteArray &ianaId)
1591 return QTimeZonePrivate::ianaIdToWindowsId(ianaId);
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1607QByteArray QTimeZone::windowsIdToDefaultIanaId(
const QByteArray &windowsId)
1609 return QTimeZonePrivate::windowsIdToDefaultIanaId(windowsId);
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1632QByteArray QTimeZone::windowsIdToDefaultIanaId(
const QByteArray &windowsId,
1633 QLocale::Territory territory)
1635 return QTimeZonePrivate::windowsIdToDefaultIanaId(windowsId, territory);
1639
1640
1641
1642
1643
1644
1645
1646
1648QList<QByteArray> QTimeZone::windowsIdToIanaIds(
const QByteArray &windowsId)
1650 return QTimeZonePrivate::windowsIdToIanaIds(windowsId);
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1669QList<QByteArray> QTimeZone::windowsIdToIanaIds(
const QByteArray &windowsId,
1670 QLocale::Territory territory)
1672 return QTimeZonePrivate::windowsIdToIanaIds(windowsId, territory);
1676
1677
1678
1679
1680
1681
1682
1683
1684
1687template <
typename Stream,
typename Wrap>
1688void QTimeZone::Data::serialize(Stream &out,
const Wrap &wrap)
const
1693 out << wrap(
"QTimeZone::UTC");
1696 out << wrap(
"QTimeZone::LocalTime");
1698 case Qt::OffsetFromUTC:
1699 out << wrap(
"AheadOfUtcBy") <<
int(s.offset);
1707#if QT_CONFIG(timezone)
1708 if constexpr (std::is_same<Stream, QDataStream>::value) {
1713 out << QString::fromUtf8(d ? QByteArrayView(d->id()) : QByteArrayView());
1718#ifndef QT_NO_DATASTREAM
1724 const auto toQString = [](
const char *text) {
1725 return QString(QLatin1StringView(text));
1728 tz.d.serialize(ds, toQString);
1739 if (ianaId == invalidId()) {
1741 }
else if (ianaId ==
"OffsetFromUtc"_L1) {
1744 QString abbreviation;
1747 ds >> ianaId >> utcOffset >> name >> abbreviation >> territory >> comment;
1748#if QT_CONFIG(timezone)
1752 tz = QTimeZone(ianaId.toUtf8());
1753 if (!tz.isValid() || tz.hasDaylightTime()
1754 || tz.offsetFromUtc(QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC)) != utcOffset) {
1756 tz = QTimeZone(ianaId.toUtf8(), utcOffset, name, abbreviation,
1757 QLocale::Territory(territory), comment);
1760 tz = QTimeZone::fromSecondsAheadOfUtc(utcOffset);
1762 }
else if (ianaId ==
"AheadOfUtcBy"_L1) {
1765 tz = QTimeZone::fromSecondsAheadOfUtc(utcOffset);
1766 }
else if (ianaId ==
"QTimeZone::UTC"_L1) {
1767 tz = QTimeZone(QTimeZone::UTC);
1768 }
else if (ianaId ==
"QTimeZone::LocalTime"_L1) {
1769 tz = QTimeZone(QTimeZone::LocalTime);
1770#if QT_CONFIG(timezone)
1772 tz = QTimeZone(ianaId.toUtf8());
1779#ifndef QT_NO_DEBUG_STREAM
1782 QDebugStateSaver saver(dbg);
1783 const auto asIs = [](
const char *text) {
return text; };
1785 dbg.nospace() <<
"QTimeZone(";
1786 tz.d.serialize(dbg, asIs);
1787 dbg.nospace() <<
')';
QDebug operator<<(QDebug dbg, const QFileInfo &fi)
bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)
static QString invalidId()
QDataStream & operator<<(QDataStream &stream, const QImage &image)
[0]
QDataStream & operator>>(QDataStream &stream, QImage &image)