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