1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2013 John Layt <jlayt@kde.org>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5
6#ifndef QTIMEZONEPRIVATE_P_H
7#define QTIMEZONEPRIVATE_P_H
8
9//
10// W A R N I N G
11// -------------
12//
13// This file is not part of the Qt API. It exists for the convenience
14// of internal files. This header file may change from version to version
15// without notice, or even be removed.
16//
17// We mean it.
18//
19
20#include "qlist.h"
21#include "qtimezone.h"
22#include "private/qlocale_p.h"
23#include "private/qdatetime_p.h"
24
25#if QT_CONFIG(icu)
26#include <unicode/ucal.h>
27#endif
28
29#ifdef Q_OS_DARWIN
30Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone);
31#endif // Q_OS_DARWIN
32
33#ifdef Q_OS_WIN
34#include <qt_windows.h>
35#endif // Q_OS_WIN
36
37#ifdef Q_OS_ANDROID
38#include <QJniObject>
39#endif
40
41QT_REQUIRE_CONFIG(timezone);
42QT_BEGIN_NAMESPACE
43
44class Q_AUTOTEST_EXPORT QTimeZonePrivate : public QSharedData
45{
46public:
47 // Version of QTimeZone::OffsetData struct using msecs for efficiency
48 struct Data {
49 QString abbreviation;
50 qint64 atMSecsSinceEpoch;
51 int offsetFromUtc;
52 int standardTimeOffset;
53 int daylightTimeOffset;
54 Data()
55 : atMSecsSinceEpoch(QTimeZonePrivate::invalidMSecs()),
56 offsetFromUtc(QTimeZonePrivate::invalidSeconds()),
57 standardTimeOffset(QTimeZonePrivate::invalidSeconds()),
58 daylightTimeOffset(QTimeZonePrivate::invalidSeconds())
59 {}
60 Data(const QString &name, qint64 when, int offset, int standard)
61 : abbreviation(name),
62 atMSecsSinceEpoch(when),
63 offsetFromUtc(offset),
64 standardTimeOffset(standard),
65 daylightTimeOffset(offset - standard)
66 {}
67 };
68 typedef QList<Data> DataList;
69
70 // Create null time zone
71 QTimeZonePrivate();
72 QTimeZonePrivate(const QTimeZonePrivate &other);
73 virtual ~QTimeZonePrivate();
74
75 virtual QTimeZonePrivate *clone() const;
76
77 bool operator==(const QTimeZonePrivate &other) const;
78 bool operator!=(const QTimeZonePrivate &other) const;
79
80 bool isValid() const;
81
82 QByteArray id() const;
83 virtual QLocale::Territory territory() const;
84 virtual QString comment() const;
85
86 virtual QString displayName(qint64 atMSecsSinceEpoch,
87 QTimeZone::NameType nameType,
88 const QLocale &locale) const;
89 virtual QString displayName(QTimeZone::TimeType timeType,
90 QTimeZone::NameType nameType,
91 const QLocale &locale) const;
92 virtual QString abbreviation(qint64 atMSecsSinceEpoch) const;
93
94 virtual int offsetFromUtc(qint64 atMSecsSinceEpoch) const;
95 virtual int standardTimeOffset(qint64 atMSecsSinceEpoch) const;
96 virtual int daylightTimeOffset(qint64 atMSecsSinceEpoch) const;
97
98 virtual bool hasDaylightTime() const;
99 virtual bool isDaylightTime(qint64 atMSecsSinceEpoch) const;
100
101 virtual Data data(qint64 forMSecsSinceEpoch) const;
102 virtual Data data(QTimeZone::TimeType timeType) const;
103 virtual bool isDataLocale(const QLocale &locale) const;
104 QDateTimePrivate::ZoneState stateAtZoneTime(qint64 forLocalMSecs,
105 QDateTimePrivate::TransitionOptions resolve) const;
106
107 virtual bool hasTransitions() const;
108 virtual Data nextTransition(qint64 afterMSecsSinceEpoch) const;
109 virtual Data previousTransition(qint64 beforeMSecsSinceEpoch) const;
110 DataList transitions(qint64 fromMSecsSinceEpoch, qint64 toMSecsSinceEpoch) const;
111
112 virtual QByteArray systemTimeZoneId() const;
113
114 virtual bool isTimeZoneIdAvailable(const QByteArray &ianaId) const;
115 virtual QList<QByteArray> availableTimeZoneIds() const;
116 virtual QList<QByteArray> availableTimeZoneIds(QLocale::Territory territory) const;
117 virtual QList<QByteArray> availableTimeZoneIds(int utcOffset) const;
118
119 virtual void serialize(QDataStream &ds) const;
120
121 // Static Utility Methods
122 [[nodiscard]] static constexpr qint64 maxMSecs()
123 { return (std::numeric_limits<qint64>::max)(); }
124 [[nodiscard]] static constexpr qint64 minMSecs()
125 { return (std::numeric_limits<qint64>::min)() + 1; }
126 [[nodiscard]] static constexpr qint64 invalidMSecs()
127 { return (std::numeric_limits<qint64>::min)(); }
128 [[nodiscard]] static constexpr int invalidSeconds()
129 { return (std::numeric_limits<int>::min)(); }
130 static QTimeZone::OffsetData invalidOffsetData();
131 static QTimeZone::OffsetData toOffsetData(const Data &data);
132 static bool isValidId(const QByteArray &ianaId);
133 static QString isoOffsetFormat(int offsetFromUtc,
134 QTimeZone::NameType mode = QTimeZone::OffsetName);
135
136 static QByteArray aliasToIana(QByteArrayView alias);
137 static QByteArray ianaIdToWindowsId(const QByteArray &ianaId);
138 static QByteArray windowsIdToDefaultIanaId(const QByteArray &windowsId);
139 static QByteArray windowsIdToDefaultIanaId(const QByteArray &windowsId,
140 QLocale::Territory territory);
141 static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId);
142 static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId,
143 QLocale::Territory territory);
144
145 // returns "UTC" QString and QByteArray
146 [[nodiscard]] static inline QString utcQString()
147 {
148 return QStringLiteral("UTC");
149 }
150
151 [[nodiscard]] static inline QByteArray utcQByteArray()
152 {
153 return QByteArrayLiteral("UTC");
154 }
155
156#if QT_CONFIG(timezone_locale)
157private:
158 // Defined in qtimezonelocale.cpp
159 QString localeName(qint64 atMSecsSinceEpoch, int offsetFromUtc,
160 QTimeZone::TimeType timeType,
161 QTimeZone::NameType nameType,
162 const QLocale &locale) const;
163#endif // L10n helpers.
164
165protected:
166 QByteArray m_id;
167};
168Q_DECLARE_TYPEINFO(QTimeZonePrivate::Data, Q_RELOCATABLE_TYPE);
169
170template<> QTimeZonePrivate *QSharedDataPointer<QTimeZonePrivate>::clone();
171
172class Q_AUTOTEST_EXPORT QUtcTimeZonePrivate final : public QTimeZonePrivate
173{
174public:
175 // Create default UTC time zone
176 QUtcTimeZonePrivate();
177 // Create named time zone
178 QUtcTimeZonePrivate(const QByteArray &utcId);
179 // Create offset from UTC
180 QUtcTimeZonePrivate(qint32 offsetSeconds);
181 // Create custom offset from UTC
182 QUtcTimeZonePrivate(const QByteArray &zoneId, int offsetSeconds, const QString &name,
183 const QString &abbreviation, QLocale::Territory territory,
184 const QString &comment);
185 QUtcTimeZonePrivate(const QUtcTimeZonePrivate &other);
186 virtual ~QUtcTimeZonePrivate();
187
188 // Fall-back for UTC[+-]\d+(:\d+){,2} IDs.
189 static qint64 offsetFromUtcString(QByteArrayView id);
190
191 QUtcTimeZonePrivate *clone() const override;
192
193 Data data(qint64 forMSecsSinceEpoch) const override;
194 Data data(QTimeZone::TimeType timeType) const override;
195 bool isDataLocale(const QLocale &locale) const override;
196
197 QLocale::Territory territory() const override;
198 QString comment() const override;
199
200 QString displayName(qint64 atMSecsSinceEpoch,
201 QTimeZone::NameType nameType,
202 const QLocale &locale) const override;
203 QString displayName(QTimeZone::TimeType timeType,
204 QTimeZone::NameType nameType,
205 const QLocale &locale) const override;
206 QString abbreviation(qint64 atMSecsSinceEpoch) const override;
207
208 int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
209 int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override;
210
211 QByteArray systemTimeZoneId() const override;
212
213 bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override;
214 QList<QByteArray> availableTimeZoneIds() const override;
215 QList<QByteArray> availableTimeZoneIds(QLocale::Territory country) const override;
216 QList<QByteArray> availableTimeZoneIds(int utcOffset) const override;
217
218 void serialize(QDataStream &ds) const override;
219
220private:
221 void init(const QByteArray &zoneId, int offsetSeconds, const QString &name,
222 const QString &abbreviation, QLocale::Territory territory,
223 const QString &comment);
224
225 QString m_name;
226 QString m_abbreviation;
227 QString m_comment;
228 QLocale::Territory m_territory;
229 int m_offsetFromUtc;
230};
231
232// TODO: shuffle (almost reverse) order of and rework #if-ery here to use #elif
233// and match the #if-ery in each of QTZ's newBackendTimeZone() cascades for
234// backend selection.
235#if QT_CONFIG(icu) && !defined(Q_OS_UNIX)
236class Q_AUTOTEST_EXPORT QIcuTimeZonePrivate final : public QTimeZonePrivate
237{
238public:
239 // Create default time zone
240 QIcuTimeZonePrivate();
241 // Create named time zone
242 QIcuTimeZonePrivate(const QByteArray &ianaId);
243 QIcuTimeZonePrivate(const QIcuTimeZonePrivate &other);
244 ~QIcuTimeZonePrivate();
245
246 QIcuTimeZonePrivate *clone() const override;
247
248 using QTimeZonePrivate::displayName;
249 QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
250 const QLocale &locale) const override;
251
252 int offsetFromUtc(qint64 atMSecsSinceEpoch) const override;
253 int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
254 int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override;
255
256 bool hasDaylightTime() const override;
257 bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
258
259 using QTimeZonePrivate::data;
260 Data data(qint64 forMSecsSinceEpoch) const override;
261
262 bool hasTransitions() const override;
263 Data nextTransition(qint64 afterMSecsSinceEpoch) const override;
264 Data previousTransition(qint64 beforeMSecsSinceEpoch) const override;
265
266 QByteArray systemTimeZoneId() const override;
267
268 bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override;
269 QList<QByteArray> availableTimeZoneIds() const override;
270 QList<QByteArray> availableTimeZoneIds(QLocale::Territory territory) const override;
271 QList<QByteArray> availableTimeZoneIds(int offsetFromUtc) const override;
272
273private:
274 void init(const QByteArray &ianaId);
275
276 UCalendar *m_ucal;
277};
278#endif // ICU not on Unix.
279
280#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID)
281struct QTzTransitionTime
282{
283 qint64 atMSecsSinceEpoch;
284 quint8 ruleIndex;
285};
286Q_DECLARE_TYPEINFO(QTzTransitionTime, Q_PRIMITIVE_TYPE);
287struct QTzTransitionRule
288{
289 int stdOffset = 0;
290 int dstOffset = 0;
291 quint8 abbreviationIndex = 0;
292};
293Q_DECLARE_TYPEINFO(QTzTransitionRule, Q_PRIMITIVE_TYPE);
294constexpr inline bool operator==(const QTzTransitionRule &lhs, const QTzTransitionRule &rhs) noexcept
295{ return lhs.stdOffset == rhs.stdOffset && lhs.dstOffset == rhs.dstOffset && lhs.abbreviationIndex == rhs.abbreviationIndex; }
296constexpr inline bool operator!=(const QTzTransitionRule &lhs, const QTzTransitionRule &rhs) noexcept
297{ return !operator==(lhs, rhs); }
298
299// These are stored separately from QTzTimeZonePrivate so that they can be
300// cached, avoiding the need to re-parse them from disk constantly.
301struct QTzTimeZoneCacheEntry
302{
303 QList<QTzTransitionTime> m_tranTimes;
304 QList<QTzTransitionRule> m_tranRules;
305 QList<QByteArray> m_abbreviations;
306 QByteArray m_posixRule;
307 QTzTransitionRule m_preZoneRule;
308 bool m_hasDst = false;
309};
310
311class Q_AUTOTEST_EXPORT QTzTimeZonePrivate final : public QTimeZonePrivate
312{
313 QTzTimeZonePrivate(const QTzTimeZonePrivate &) = default;
314public:
315 // Create default time zone
316 QTzTimeZonePrivate();
317 // Create named time zone
318 QTzTimeZonePrivate(const QByteArray &ianaId);
319 ~QTzTimeZonePrivate();
320
321 QTzTimeZonePrivate *clone() const override;
322
323 QLocale::Territory territory() const override;
324 QString comment() const override;
325
326 using QTimeZonePrivate::displayName;
327 QString displayName(QTimeZone::TimeType timeType,
328 QTimeZone::NameType nameType,
329 const QLocale &locale) const override;
330 QString abbreviation(qint64 atMSecsSinceEpoch) const override;
331
332 int offsetFromUtc(qint64 atMSecsSinceEpoch) const override;
333 int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
334 int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override;
335
336 bool hasDaylightTime() const override;
337 bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
338
339 Data data(qint64 forMSecsSinceEpoch) const override;
340 Data data(QTimeZone::TimeType timeType) const override;
341 bool isDataLocale(const QLocale &locale) const override;
342
343 bool hasTransitions() const override;
344 Data nextTransition(qint64 afterMSecsSinceEpoch) const override;
345 Data previousTransition(qint64 beforeMSecsSinceEpoch) const override;
346
347 QByteArray systemTimeZoneId() const override;
348
349 bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override;
350 QList<QByteArray> availableTimeZoneIds() const override;
351 QList<QByteArray> availableTimeZoneIds(QLocale::Territory territory) const override;
352
353private:
354 static QByteArray staticSystemTimeZoneId();
355 QList<QTimeZonePrivate::Data> getPosixTransitions(qint64 msNear) const;
356
357 Data dataForTzTransition(QTzTransitionTime tran) const;
358 Data dataFromRule(QTzTransitionRule rule, qint64 msecsSinceEpoch) const;
359 QTzTimeZoneCacheEntry cached_data;
360 const QList<QTzTransitionTime> &tranCache() const { return cached_data.m_tranTimes; }
361};
362#endif // Q_OS_UNIX
363
364#ifdef Q_OS_DARWIN
365class Q_AUTOTEST_EXPORT QMacTimeZonePrivate final : public QTimeZonePrivate
366{
367public:
368 // Create default time zone
369 QMacTimeZonePrivate();
370 // Create named time zone
371 QMacTimeZonePrivate(const QByteArray &ianaId);
372 QMacTimeZonePrivate(const QMacTimeZonePrivate &other);
373 ~QMacTimeZonePrivate();
374
375 QMacTimeZonePrivate *clone() const override;
376
377 QString comment() const override;
378
379 using QTimeZonePrivate::displayName;
380 QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
381 const QLocale &locale) const override;
382 QString abbreviation(qint64 atMSecsSinceEpoch) const override;
383
384 int offsetFromUtc(qint64 atMSecsSinceEpoch) const override;
385 int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
386 int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override;
387
388 bool hasDaylightTime() const override;
389 bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
390
391 using QTimeZonePrivate::data;
392 Data data(qint64 forMSecsSinceEpoch) const override;
393
394 bool hasTransitions() const override;
395 Data nextTransition(qint64 afterMSecsSinceEpoch) const override;
396 Data previousTransition(qint64 beforeMSecsSinceEpoch) const override;
397
398 QByteArray systemTimeZoneId() const override;
399 bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override;
400 QList<QByteArray> availableTimeZoneIds() const override;
401
402 NSTimeZone *nsTimeZone() const;
403
404private:
405 void init(const QByteArray &zoneId);
406
407 NSTimeZone *m_nstz;
408};
409#endif // Q_OS_DARWIN
410
411#if defined(Q_OS_WIN) && !QT_CONFIG(icu)
412class Q_AUTOTEST_EXPORT QWinTimeZonePrivate final : public QTimeZonePrivate
413{
414public:
415 struct QWinTransitionRule {
416 int startYear;
417 int standardTimeBias;
418 int daylightTimeBias;
419 SYSTEMTIME standardTimeRule;
420 SYSTEMTIME daylightTimeRule;
421 };
422
423 // Create default time zone
424 QWinTimeZonePrivate();
425 // Create named time zone
426 QWinTimeZonePrivate(const QByteArray &ianaId);
427 QWinTimeZonePrivate(const QWinTimeZonePrivate &other);
428 ~QWinTimeZonePrivate();
429
430 QWinTimeZonePrivate *clone() const override;
431
432 QString comment() const override;
433
434 using QTimeZonePrivate::displayName;
435 QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
436 const QLocale &locale) const override;
437 QString abbreviation(qint64 atMSecsSinceEpoch) const override;
438
439 int offsetFromUtc(qint64 atMSecsSinceEpoch) const override;
440 int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
441 int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override;
442
443 bool hasDaylightTime() const override;
444 bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
445
446 using QTimeZonePrivate::data;
447 Data data(qint64 forMSecsSinceEpoch) const override;
448
449 bool hasTransitions() const override;
450 Data nextTransition(qint64 afterMSecsSinceEpoch) const override;
451 Data previousTransition(qint64 beforeMSecsSinceEpoch) const override;
452
453 QByteArray systemTimeZoneId() const override;
454
455 QList<QByteArray> availableTimeZoneIds() const override;
456
457 // For use within implementation's TransitionTimePair:
458 QTimeZonePrivate::Data ruleToData(const QWinTransitionRule &rule, qint64 atMSecsSinceEpoch,
459 QTimeZone::TimeType type, bool fakeDst = false) const;
460private:
461 void init(const QByteArray &ianaId);
462
463 QByteArray m_windowsId;
464 QString m_displayName;
465 QString m_standardName;
466 QString m_daylightName;
467 QList<QWinTransitionRule> m_tranRules;
468};
469#endif // Q_OS_WIN && !icu
470
471#ifdef Q_OS_ANDROID
472class QAndroidTimeZonePrivate final : public QTimeZonePrivate
473{
474public:
475 // Create default time zone
476 QAndroidTimeZonePrivate();
477 // Create named time zone
478 QAndroidTimeZonePrivate(const QByteArray &ianaId);
479 QAndroidTimeZonePrivate(const QAndroidTimeZonePrivate &other);
480 ~QAndroidTimeZonePrivate();
481
482 QAndroidTimeZonePrivate *clone() const override;
483
484 using QTimeZonePrivate::displayName;
485 QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
486 const QLocale &locale) const override;
487 QString abbreviation(qint64 atMSecsSinceEpoch) const override;
488
489 int offsetFromUtc(qint64 atMSecsSinceEpoch) const override;
490 int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
491 int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override;
492
493 bool hasDaylightTime() const override;
494 bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
495
496 using QTimeZonePrivate::data;
497 Data data(qint64 forMSecsSinceEpoch) const override;
498
499 QByteArray systemTimeZoneId() const override;
500 bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override;
501 QList<QByteArray> availableTimeZoneIds() const override;
502
503private:
504 void init(const QByteArray &zoneId);
505
506 QJniObject androidTimeZone;
507
508};
509#endif // Q_OS_ANDROID
510
511QT_END_NAMESPACE
512
513#endif // QTIMEZONEPRIVATE_P_H
514

source code of qtbase/src/corelib/time/qtimezoneprivate_p.h