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

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