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 |
65 | Q_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 | |
76 | QT_BEGIN_NAMESPACE |
77 | |
78 | class Q_AUTOTEST_EXPORT QTimeZonePrivate : public QSharedData |
79 | { |
80 | public: |
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 () 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 | |
170 | protected: |
171 | QByteArray m_id; |
172 | }; |
173 | Q_DECLARE_TYPEINFO(QTimeZonePrivate::Data, Q_MOVABLE_TYPE); |
174 | |
175 | template<> QTimeZonePrivate *QSharedDataPointer<QTimeZonePrivate>::clone(); |
176 | |
177 | class Q_AUTOTEST_EXPORT QUtcTimeZonePrivate final : public QTimeZonePrivate |
178 | { |
179 | public: |
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 &); |
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 () 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 | |
220 | private: |
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 &); |
225 | |
226 | QString m_name; |
227 | QString m_abbreviation; |
228 | QString ; |
229 | QLocale::Country m_country; |
230 | int m_offsetFromUtc; |
231 | }; |
232 | |
233 | #if QT_CONFIG(icu) |
234 | class Q_AUTOTEST_EXPORT QIcuTimeZonePrivate final : public QTimeZonePrivate |
235 | { |
236 | public: |
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 | |
270 | private: |
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)) |
278 | struct QTzTransitionTime |
279 | { |
280 | qint64 atMSecsSinceEpoch; |
281 | quint8 ruleIndex; |
282 | }; |
283 | Q_DECLARE_TYPEINFO(QTzTransitionTime, Q_PRIMITIVE_TYPE); |
284 | struct QTzTransitionRule |
285 | { |
286 | int stdOffset; |
287 | int dstOffset; |
288 | quint8 abbreviationIndex; |
289 | }; |
290 | Q_DECLARE_TYPEINFO(QTzTransitionRule, Q_PRIMITIVE_TYPE); |
291 | Q_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; } |
293 | Q_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. |
298 | struct QTzTimeZoneCacheEntry |
299 | { |
300 | QVector<QTzTransitionTime> m_tranTimes; |
301 | QVector<QTzTransitionRule> m_tranRules; |
302 | QList<QByteArray> m_abbreviations; |
303 | QByteArray m_posixRule; |
304 | }; |
305 | |
306 | class Q_AUTOTEST_EXPORT QTzTimeZonePrivate final : public QTimeZonePrivate |
307 | { |
308 | QTzTimeZonePrivate(const QTzTimeZonePrivate &) = default; |
309 | public: |
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 () 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 | |
348 | private: |
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 |
367 | class Q_AUTOTEST_EXPORT QMacTimeZonePrivate final : public QTimeZonePrivate |
368 | { |
369 | public: |
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 | |
404 | private: |
405 | void init(const QByteArray &zoneId); |
406 | |
407 | NSTimeZone *m_nstz; |
408 | }; |
409 | #endif // Q_OS_MAC |
410 | |
411 | #ifdef Q_OS_WIN |
412 | class Q_AUTOTEST_EXPORT QWinTimeZonePrivate final : public QTimeZonePrivate |
413 | { |
414 | public: |
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 | |
455 | private: |
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) |
469 | class QAndroidTimeZonePrivate final : public QTimeZonePrivate |
470 | { |
471 | public: |
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 | |
502 | private: |
503 | void init(const QByteArray &zoneId); |
504 | |
505 | QJNIObjectPrivate androidTimeZone; |
506 | |
507 | }; |
508 | #endif // Q_OS_ANDROID |
509 | |
510 | QT_END_NAMESPACE |
511 | |
512 | #endif // QTIMEZONEPRIVATE_P_H |
513 | |