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 "qtimezone.h"
56 #include "private/qlocale_p.h"
57 #include "qvector.h"
58 
59 #if QT_CONFIG(icu)
60 #include <unicode/ucal.h>
61 #endif
62 
63 #ifdef Q_OS_DARWIN
64 Q_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 
75 QT_BEGIN_NAMESPACE
76 
77 class Q_AUTOTEST_EXPORT QTimeZonePrivate : public QSharedData
78 {
79 public:
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 QVector<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
maxMSecs()139     static inline qint64 maxMSecs() { return std::numeric_limits<qint64>::max(); }
minMSecs()140     static inline qint64 minMSecs() { return std::numeric_limits<qint64>::min() + 1; }
invalidMSecs()141     static inline qint64 invalidMSecs() { return std::numeric_limits<qint64>::min(); }
invalidSeconds()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
utcQString()158     Q_REQUIRED_RESULT static inline QString utcQString()
159     {
160         return QStringLiteral("UTC");
161     }
162 
utcQByteArray()163     Q_REQUIRED_RESULT static inline QByteArray utcQByteArray()
164     {
165         return QByteArrayLiteral("UTC");
166     }
167 
168 protected:
169     QByteArray m_id;
170 };
171 Q_DECLARE_TYPEINFO(QTimeZonePrivate::Data, Q_MOVABLE_TYPE);
172 
173 template<> QTimeZonePrivate *QSharedDataPointer<QTimeZonePrivate>::clone();
174 
175 class Q_AUTOTEST_EXPORT QUtcTimeZonePrivate final : public QTimeZonePrivate
176 {
177 public:
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 
218 private:
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)
232 class Q_AUTOTEST_EXPORT QIcuTimeZonePrivate final : public QTimeZonePrivate
233 {
234 public:
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 
267 private:
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))
275 struct QTzTransitionTime
276 {
277     qint64 atMSecsSinceEpoch;
278     quint8 ruleIndex;
279 };
280 Q_DECLARE_TYPEINFO(QTzTransitionTime, Q_PRIMITIVE_TYPE);
281 struct QTzTransitionRule
282 {
283     int stdOffset;
284     int dstOffset;
285     quint8 abbreviationIndex;
286 };
287 Q_DECLARE_TYPEINFO(QTzTransitionRule, Q_PRIMITIVE_TYPE);
288 Q_DECL_CONSTEXPR inline bool operator==(const QTzTransitionRule &lhs, const QTzTransitionRule &rhs) noexcept
289 { return lhs.stdOffset == rhs.stdOffset && lhs.dstOffset == rhs.dstOffset && lhs.abbreviationIndex == rhs.abbreviationIndex; }
290 Q_DECL_CONSTEXPR 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.
295 struct QTzTimeZoneCacheEntry
296 {
297     QVector<QTzTransitionTime> m_tranTimes;
298     QVector<QTzTransitionRule> m_tranRules;
299     QList<QByteArray> m_abbreviations;
300     QByteArray m_posixRule;
301 };
302 
303 class Q_AUTOTEST_EXPORT QTzTimeZonePrivate final : public QTimeZonePrivate
304 {
305     QTzTimeZonePrivate(const QTzTimeZonePrivate &) = default;
306 public:
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 
345 private:
346     void init(const QByteArray &ianaId);
347     QVector<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;
tranCache()354     QVector<QTzTransitionTime> tranCache() const { return cached_data.m_tranTimes; }
355 };
356 #endif // Q_OS_UNIX
357 
358 #ifdef Q_OS_MAC
359 class Q_AUTOTEST_EXPORT QMacTimeZonePrivate final : public QTimeZonePrivate
360 {
361 public:
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 
396 private:
397     void init(const QByteArray &zoneId);
398 
399     NSTimeZone *m_nstz;
400 };
401 #endif // Q_OS_MAC
402 
403 #ifdef Q_OS_WIN
404 class Q_AUTOTEST_EXPORT QWinTimeZonePrivate final : public QTimeZonePrivate
405 {
406 public:
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 
447 private:
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)
461 class QAndroidTimeZonePrivate final : public QTimeZonePrivate
462 {
463 public:
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 
494 private:
495     void init(const QByteArray &zoneId);
496 
497     QJNIObjectPrivate androidTimeZone;
498 
499 };
500 #endif // Q_OS_ANDROID
501 
502 QT_END_NAMESPACE
503 
504 #endif // QTIMEZONEPRIVATE_P_H
505