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