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 |
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 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 () 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 | |
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 &); |
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 () 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 &); |
223 | |
224 | QString m_name; |
225 | QString m_abbreviation; |
226 | QString ; |
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 | 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 | 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 | QList<QTzTransitionTime> m_tranTimes; |
298 | QList<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 () 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 | 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 |
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 | |