1/****************************************************************************
2**
3** Copyright (C) 2021 The Qt Company Ltd.
4** Copyright (C) 2013 John Layt <jlayt@kde.org>
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41
42#ifndef QTIMEZONEPRIVATE_P_H
43#define QTIMEZONEPRIVATE_P_H
44
45//
46// W A R N I N G
47// -------------
48//
49// This file is not part of the Qt API. It exists for the convenience
50// of internal files. This header file may change from version to version
51// without notice, or even be removed.
52//
53// We mean it.
54//
55
56#include "qtimezone.h"
57#include "private/qlocale_p.h"
58#include "qvector.h"
59
60#if QT_CONFIG(icu)
61#include <unicode/ucal.h>
62#endif
63
64#ifdef Q_OS_DARWIN
65Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone);
66#endif // Q_OS_DARWIN
67
68#ifdef Q_OS_WIN
69#include <qt_windows.h>
70#endif // Q_OS_WIN
71
72#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
73#include <QtCore/private/qjni_p.h>
74#endif
75
76QT_BEGIN_NAMESPACE
77
78class Q_AUTOTEST_EXPORT QTimeZonePrivate : public QSharedData
79{
80public:
81 //Version of QTimeZone::OffsetData struct using msecs for efficiency
82 struct Data {
83 QString abbreviation;
84 qint64 atMSecsSinceEpoch;
85 int offsetFromUtc;
86 int standardTimeOffset;
87 int daylightTimeOffset;
88 };
89 typedef QVector<Data> DataList;
90
91 // Create null time zone
92 QTimeZonePrivate();
93 QTimeZonePrivate(const QTimeZonePrivate &other);
94 virtual ~QTimeZonePrivate();
95
96 virtual QTimeZonePrivate *clone() const;
97
98 bool operator==(const QTimeZonePrivate &other) const;
99 bool operator!=(const QTimeZonePrivate &other) const;
100
101 bool isValid() const;
102
103 QByteArray id() const;
104 virtual QLocale::Country country() const;
105 virtual QString comment() const;
106
107 virtual QString displayName(qint64 atMSecsSinceEpoch,
108 QTimeZone::NameType nameType,
109 const QLocale &locale) const;
110 virtual QString displayName(QTimeZone::TimeType timeType,
111 QTimeZone::NameType nameType,
112 const QLocale &locale) const;
113 virtual QString abbreviation(qint64 atMSecsSinceEpoch) const;
114
115 virtual int offsetFromUtc(qint64 atMSecsSinceEpoch) const;
116 virtual int standardTimeOffset(qint64 atMSecsSinceEpoch) const;
117 virtual int daylightTimeOffset(qint64 atMSecsSinceEpoch) const;
118
119 virtual bool hasDaylightTime() const;
120 virtual bool isDaylightTime(qint64 atMSecsSinceEpoch) const;
121
122 virtual Data data(qint64 forMSecsSinceEpoch) const;
123 Data dataForLocalTime(qint64 forLocalMSecs, int hint) const;
124
125 virtual bool hasTransitions() const;
126 virtual Data nextTransition(qint64 afterMSecsSinceEpoch) const;
127 virtual Data previousTransition(qint64 beforeMSecsSinceEpoch) const;
128 DataList transitions(qint64 fromMSecsSinceEpoch, qint64 toMSecsSinceEpoch) const;
129
130 virtual QByteArray systemTimeZoneId() const;
131
132 virtual bool isTimeZoneIdAvailable(const QByteArray &ianaId) const;
133 virtual QList<QByteArray> availableTimeZoneIds() const;
134 virtual QList<QByteArray> availableTimeZoneIds(QLocale::Country country) const;
135 virtual QList<QByteArray> availableTimeZoneIds(int utcOffset) const;
136
137 virtual void serialize(QDataStream &ds) const;
138
139 // Static Utility Methods
140 static inline qint64 maxMSecs() { return std::numeric_limits<qint64>::max(); }
141 static inline qint64 minMSecs() { return std::numeric_limits<qint64>::min() + 1; }
142 static inline qint64 invalidMSecs() { return std::numeric_limits<qint64>::min(); }
143 static inline qint64 invalidSeconds() { return std::numeric_limits<int>::min(); }
144 static Data invalidData();
145 static QTimeZone::OffsetData invalidOffsetData();
146 static QTimeZone::OffsetData toOffsetData(const Data &data);
147 static bool isValidId(const QByteArray &ianaId);
148 static QString isoOffsetFormat(int offsetFromUtc,
149 QTimeZone::NameType mode = QTimeZone::OffsetName);
150
151 static QByteArray ianaIdToWindowsId(const QByteArray &ianaId);
152 static QByteArray windowsIdToDefaultIanaId(const QByteArray &windowsId);
153 static QByteArray windowsIdToDefaultIanaId(const QByteArray &windowsId,
154 QLocale::Country country);
155 static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId);
156 static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId,
157 QLocale::Country country);
158
159 // returns "UTC" QString and QByteArray
160 Q_REQUIRED_RESULT static inline QString utcQString()
161 {
162 return QStringLiteral("UTC");
163 }
164
165 Q_REQUIRED_RESULT static inline QByteArray utcQByteArray()
166 {
167 return QByteArrayLiteral("UTC");
168 }
169
170protected:
171 QByteArray m_id;
172};
173Q_DECLARE_TYPEINFO(QTimeZonePrivate::Data, Q_MOVABLE_TYPE);
174
175template<> QTimeZonePrivate *QSharedDataPointer<QTimeZonePrivate>::clone();
176
177class Q_AUTOTEST_EXPORT QUtcTimeZonePrivate final : public QTimeZonePrivate
178{
179public:
180 // Create default UTC time zone
181 QUtcTimeZonePrivate();
182 // Create named time zone
183 QUtcTimeZonePrivate(const QByteArray &utcId);
184 // Create offset from UTC
185 QUtcTimeZonePrivate(qint32 offsetSeconds);
186 // Create custom offset from UTC
187 QUtcTimeZonePrivate(const QByteArray &zoneId, int offsetSeconds, const QString &name,
188 const QString &abbreviation, QLocale::Country country,
189 const QString &comment);
190 QUtcTimeZonePrivate(const QUtcTimeZonePrivate &other);
191 virtual ~QUtcTimeZonePrivate();
192
193 // Fall-back for UTC[+-]\d+(:\d+){,2} IDs.
194 static qint64 offsetFromUtcString(const QByteArray &id);
195
196 QUtcTimeZonePrivate *clone() const override;
197
198 Data data(qint64 forMSecsSinceEpoch) const override;
199
200 QLocale::Country country() const override;
201 QString comment() const override;
202
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::Country 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);
222 void init(const QByteArray &zoneId, int offsetSeconds, const QString &name,
223 const QString &abbreviation, QLocale::Country country,
224 const QString &comment);
225
226 QString m_name;
227 QString m_abbreviation;
228 QString m_comment;
229 QLocale::Country m_country;
230 int m_offsetFromUtc;
231};
232
233#if QT_CONFIG(icu)
234class Q_AUTOTEST_EXPORT QIcuTimeZonePrivate final : public QTimeZonePrivate
235{
236public:
237 // Create default time zone
238 QIcuTimeZonePrivate();
239 // Create named time zone
240 QIcuTimeZonePrivate(const QByteArray &ianaId);
241 QIcuTimeZonePrivate(const QIcuTimeZonePrivate &other);
242 ~QIcuTimeZonePrivate();
243
244 QIcuTimeZonePrivate *clone() const override;
245
246 using QTimeZonePrivate::displayName;
247 QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
248 const QLocale &locale) const override;
249 QString abbreviation(qint64 atMSecsSinceEpoch) const override;
250
251 int offsetFromUtc(qint64 atMSecsSinceEpoch) const override;
252 int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
253 int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override;
254
255 bool hasDaylightTime() const override;
256 bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
257
258 Data data(qint64 forMSecsSinceEpoch) const override;
259
260 bool hasTransitions() const override;
261 Data nextTransition(qint64 afterMSecsSinceEpoch) const override;
262 Data previousTransition(qint64 beforeMSecsSinceEpoch) const override;
263
264 QByteArray systemTimeZoneId() const override;
265
266 QList<QByteArray> availableTimeZoneIds() const override;
267 QList<QByteArray> availableTimeZoneIds(QLocale::Country country) const override;
268 QList<QByteArray> availableTimeZoneIds(int offsetFromUtc) const override;
269
270private:
271 void init(const QByteArray &ianaId);
272
273 UCalendar *m_ucal;
274};
275#endif
276
277#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_EMBEDDED))
278struct QTzTransitionTime
279{
280 qint64 atMSecsSinceEpoch;
281 quint8 ruleIndex;
282};
283Q_DECLARE_TYPEINFO(QTzTransitionTime, Q_PRIMITIVE_TYPE);
284struct QTzTransitionRule
285{
286 int stdOffset;
287 int dstOffset;
288 quint8 abbreviationIndex;
289};
290Q_DECLARE_TYPEINFO(QTzTransitionRule, Q_PRIMITIVE_TYPE);
291Q_DECL_CONSTEXPR inline bool operator==(const QTzTransitionRule &lhs, const QTzTransitionRule &rhs) noexcept
292{ return lhs.stdOffset == rhs.stdOffset && lhs.dstOffset == rhs.dstOffset && lhs.abbreviationIndex == rhs.abbreviationIndex; }
293Q_DECL_CONSTEXPR inline bool operator!=(const QTzTransitionRule &lhs, const QTzTransitionRule &rhs) noexcept
294{ return !operator==(lhs, rhs); }
295
296// These are stored separately from QTzTimeZonePrivate so that they can be
297// cached, avoiding the need to re-parse them from disk constantly.
298struct QTzTimeZoneCacheEntry
299{
300 QVector<QTzTransitionTime> m_tranTimes;
301 QVector<QTzTransitionRule> m_tranRules;
302 QList<QByteArray> m_abbreviations;
303 QByteArray m_posixRule;
304};
305
306class Q_AUTOTEST_EXPORT QTzTimeZonePrivate final : public QTimeZonePrivate
307{
308 QTzTimeZonePrivate(const QTzTimeZonePrivate &) = default;
309public:
310 // Create default time zone
311 QTzTimeZonePrivate();
312 // Create named time zone
313 QTzTimeZonePrivate(const QByteArray &ianaId);
314 ~QTzTimeZonePrivate();
315
316 QTzTimeZonePrivate *clone() const override;
317
318 QLocale::Country country() const override;
319 QString comment() const override;
320
321 QString displayName(qint64 atMSecsSinceEpoch,
322 QTimeZone::NameType nameType,
323 const QLocale &locale) const override;
324 QString displayName(QTimeZone::TimeType timeType,
325 QTimeZone::NameType nameType,
326 const QLocale &locale) const override;
327 QString abbreviation(qint64 atMSecsSinceEpoch) const override;
328
329 int offsetFromUtc(qint64 atMSecsSinceEpoch) const override;
330 int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
331 int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override;
332
333 bool hasDaylightTime() const override;
334 bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
335
336 Data data(qint64 forMSecsSinceEpoch) const override;
337
338 bool hasTransitions() const override;
339 Data nextTransition(qint64 afterMSecsSinceEpoch) const override;
340 Data previousTransition(qint64 beforeMSecsSinceEpoch) const override;
341
342 QByteArray systemTimeZoneId() const override;
343
344 bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override;
345 QList<QByteArray> availableTimeZoneIds() const override;
346 QList<QByteArray> availableTimeZoneIds(QLocale::Country country) const override;
347
348private:
349 static QByteArray staticSystemTimeZoneId();
350 QVector<QTimeZonePrivate::Data> getPosixTransitions(qint64 msNear) const;
351
352 Data dataForTzTransition(QTzTransitionTime tran) const;
353#if QT_CONFIG(icu)
354# ifdef __cpp_lib_is_final
355 static_assert(std::is_final<QIcuTimeZonePrivate>::value,
356 "if QIcuTimeZonePrivate isn't final, we may need to specialize "
357 "QExplicitlySharedDataPointer::clone() to call QTimeZonePrivate::clone()");
358# endif
359 mutable QExplicitlySharedDataPointer<const QIcuTimeZonePrivate> m_icu;
360#endif
361 QTzTimeZoneCacheEntry cached_data;
362 QVector<QTzTransitionTime> tranCache() const { return cached_data.m_tranTimes; }
363};
364#endif // Q_OS_UNIX
365
366#ifdef Q_OS_MAC
367class Q_AUTOTEST_EXPORT QMacTimeZonePrivate final : public QTimeZonePrivate
368{
369public:
370 // Create default time zone
371 QMacTimeZonePrivate();
372 // Create named time zone
373 QMacTimeZonePrivate(const QByteArray &ianaId);
374 QMacTimeZonePrivate(const QMacTimeZonePrivate &other);
375 ~QMacTimeZonePrivate();
376
377 QMacTimeZonePrivate *clone() const override;
378
379 QString comment() const override;
380
381 QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
382 const QLocale &locale) const override;
383 QString abbreviation(qint64 atMSecsSinceEpoch) const override;
384
385 int offsetFromUtc(qint64 atMSecsSinceEpoch) const override;
386 int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
387 int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override;
388
389 bool hasDaylightTime() const override;
390 bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
391
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
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_MAC
410
411#ifdef Q_OS_WIN
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 QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
435 const QLocale &locale) const override;
436 QString abbreviation(qint64 atMSecsSinceEpoch) const override;
437
438 int offsetFromUtc(qint64 atMSecsSinceEpoch) const override;
439 int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
440 int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override;
441
442 bool hasDaylightTime() const override;
443 bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
444
445 Data data(qint64 forMSecsSinceEpoch) const override;
446
447 bool hasTransitions() const override;
448 Data nextTransition(qint64 afterMSecsSinceEpoch) const override;
449 Data previousTransition(qint64 beforeMSecsSinceEpoch) const override;
450
451 QByteArray systemTimeZoneId() const override;
452
453 QList<QByteArray> availableTimeZoneIds() const override;
454
455private:
456 void init(const QByteArray &ianaId);
457 QTimeZonePrivate::Data ruleToData(const QWinTransitionRule &rule, qint64 atMSecsSinceEpoch,
458 QTimeZone::TimeType type, bool fakeDst = false) const;
459
460 QByteArray m_windowsId;
461 QString m_displayName;
462 QString m_standardName;
463 QString m_daylightName;
464 QList<QWinTransitionRule> m_tranRules;
465};
466#endif // Q_OS_WIN
467
468#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
469class QAndroidTimeZonePrivate final : public QTimeZonePrivate
470{
471public:
472 // Create default time zone
473 QAndroidTimeZonePrivate();
474 // Create named time zone
475 QAndroidTimeZonePrivate(const QByteArray &ianaId);
476 QAndroidTimeZonePrivate(const QAndroidTimeZonePrivate &other);
477 ~QAndroidTimeZonePrivate();
478
479 QAndroidTimeZonePrivate *clone() const override;
480
481 QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
482 const QLocale &locale) const override;
483 QString abbreviation(qint64 atMSecsSinceEpoch) const override;
484
485 int offsetFromUtc(qint64 atMSecsSinceEpoch) const override;
486 int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
487 int daylightTimeOffset(qint64 atMSecsSinceEpoch) const override;
488
489 bool hasDaylightTime() const override;
490 bool isDaylightTime(qint64 atMSecsSinceEpoch) const override;
491
492 Data data(qint64 forMSecsSinceEpoch) const override;
493
494 bool hasTransitions() const override;
495 Data nextTransition(qint64 afterMSecsSinceEpoch) const override;
496 Data previousTransition(qint64 beforeMSecsSinceEpoch) const override;
497
498 QByteArray systemTimeZoneId() const override;
499
500 QList<QByteArray> availableTimeZoneIds() const override;
501
502private:
503 void init(const QByteArray &zoneId);
504
505 QJNIObjectPrivate androidTimeZone;
506
507};
508#endif // Q_OS_ANDROID
509
510QT_END_NAMESPACE
511
512#endif // QTIMEZONEPRIVATE_P_H
513

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