/usr/include/QtCore/qtimezone.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (C) 2017 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 | | #ifndef QTIMEZONE_H |
6 | | #define QTIMEZONE_H |
7 | | |
8 | | #include <QtCore/qcompare.h> |
9 | | #include <QtCore/qdatetime.h> |
10 | | #include <QtCore/qlocale.h> |
11 | | #include <QtCore/qswap.h> |
12 | | #include <QtCore/qtclasshelpermacros.h> |
13 | | |
14 | | #include <chrono> |
15 | | |
16 | | #if QT_CONFIG(timezone) && (defined(Q_OS_DARWIN) || defined(Q_QDOC)) |
17 | | Q_FORWARD_DECLARE_CF_TYPE(CFTimeZone); |
18 | | Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone); |
19 | | #endif |
20 | | |
21 | | QT_BEGIN_NAMESPACE |
22 | | |
23 | | class QTimeZonePrivate; |
24 | | |
25 | | class Q_CORE_EXPORT QTimeZone |
26 | | { |
27 | | struct ShortData |
28 | | { |
29 | | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN |
30 | | quintptr mode : 2; |
31 | | #endif |
32 | | qintptr offset : sizeof(void *) * 8 - 2; |
33 | | |
34 | | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
35 | | quintptr mode : 2; |
36 | | #endif |
37 | | |
38 | | // mode is a cycled Qt::TimeSpec, (int(spec) + 1) % 4, so that zero |
39 | | // (lowest bits of a pointer) matches spec being Qt::TimeZone, for which |
40 | | // Data holds a QTZP pointer instead of ShortData. |
41 | | // Passing Qt::TimeZone gets the equivalent of a null QTZP; it is not short. |
42 | | constexpr ShortData(Qt::TimeSpec spec, int secondsAhead = 0) |
43 | | #if Q_BYTE_ORDER == Q_BIG_ENDIAN |
44 | | : offset(spec == Qt::OffsetFromUTC ? secondsAhead : 0), |
45 | | mode((int(spec) + 1) & 3) |
46 | | #else |
47 | 621k | : mode((int(spec) + 1) & 3), |
48 | 621k | offset(spec == Qt::OffsetFromUTC ? secondsAhead : 0) |
49 | | #endif |
50 | 621k | { |
51 | 621k | } |
52 | | friend constexpr bool operator==(ShortData lhs, ShortData rhs) |
53 | | { return lhs.mode == rhs.mode && lhs.offset == rhs.offset; } |
54 | | constexpr Qt::TimeSpec spec() const { return Qt::TimeSpec((mode + 3) & 3); } |
55 | | }; |
56 | | |
57 | | union Data |
58 | | { |
59 | | Data() noexcept; |
60 | 621k | Data(ShortData sd) : s(sd) {} |
61 | | Data(const Data &other) noexcept; |
62 | 0 | Data(Data &&other) noexcept : d(std::exchange(other.d, nullptr)) {} |
63 | | Data &operator=(const Data &other) noexcept; |
64 | 0 | Data &operator=(Data &&other) noexcept { swap(other); return *this; } |
65 | | ~Data(); |
66 | | |
67 | | void swap(Data &other) noexcept { qt_ptr_swap(d, other.d); } |
68 | | // isShort() is equivalent to s.spec() != Qt::TimeZone |
69 | | bool isShort() const { return s.mode; } // a.k.a. quintptr(d) & 3 |
70 | | |
71 | | // Typse must support: out << wrap("C-strings"); |
72 | | template <typename Stream, typename Wrap> |
73 | | void serialize(Stream &out, const Wrap &wrap) const; |
74 | | |
75 | | Data(QTimeZonePrivate *dptr) noexcept; |
76 | | Data &operator=(QTimeZonePrivate *dptr) noexcept; |
77 | | const QTimeZonePrivate *operator->() const { Q_ASSERT(!isShort()); return d; } |
78 | | QTimeZonePrivate *operator->() { Q_ASSERT(!isShort()); return d; } |
79 | | |
80 | | QTimeZonePrivate *d = nullptr; |
81 | | ShortData s; |
82 | | }; |
83 | 791 | QTimeZone(ShortData sd) : d(sd) {} |
84 | | |
85 | | public: |
86 | | // Sane UTC offsets range from -16 to +16 hours: |
87 | | static constexpr int MinUtcOffsetSecs = -16 * 3600; |
88 | | // No known modern zone > 12 hrs West of Greenwich. |
89 | | // Until 1844, Asia/Manila (in The Philippines) was at 15:56 West. |
90 | | static constexpr int MaxUtcOffsetSecs = +16 * 3600; |
91 | | // No known modern zone > 14 hrs East of Greenwich. |
92 | | // Until 1867, America/Metlakatla (in Alaska) was at 15:13:42 East. |
93 | | |
94 | | enum Initialization { LocalTime, UTC }; |
95 | | |
96 | | QTimeZone() noexcept; |
97 | | Q_IMPLICIT QTimeZone(Initialization spec) noexcept |
98 | | : d(ShortData(spec == UTC ? Qt::UTC : Qt::LocalTime)) {} |
99 | | |
100 | | #if QT_CONFIG(timezone) |
101 | | explicit QTimeZone(int offsetSeconds); |
102 | | explicit QTimeZone(const QByteArray &ianaId); |
103 | | QTimeZone(const QByteArray &zoneId, int offsetSeconds, const QString &name, |
104 | | const QString &abbreviation, QLocale::Territory territory = QLocale::AnyTerritory, |
105 | | const QString &comment = QString()); |
106 | | #endif // timezone backends |
107 | | |
108 | | QTimeZone(const QTimeZone &other) noexcept; |
109 | 0 | QTimeZone(QTimeZone &&other) noexcept : d(std::move(other.d)) {} |
110 | | ~QTimeZone(); |
111 | | |
112 | | QTimeZone &operator=(const QTimeZone &other); |
113 | | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QTimeZone) |
114 | | |
115 | | void swap(QTimeZone &other) noexcept |
116 | | { d.swap(other.d); } |
117 | | |
118 | | #if QT_CORE_REMOVED_SINCE(6, 7) |
119 | | bool operator==(const QTimeZone &other) const; |
120 | | bool operator!=(const QTimeZone &other) const; |
121 | | #endif |
122 | | |
123 | | bool isValid() const; |
124 | | |
125 | | static QTimeZone fromDurationAheadOfUtc(std::chrono::seconds offset) |
126 | 791 | { |
127 | 791 | return QTimeZone((offset.count() >= MinUtcOffsetSecs && offset.count() <= MaxUtcOffsetSecs) |
128 | 791 | ? ShortData(offset.count() ? Qt::OffsetFromUTC : Qt::UTC, |
129 | 711 | int(offset.count())) |
130 | 791 | : ShortData(Qt::TimeZone)); |
131 | 791 | } |
132 | | static QTimeZone fromSecondsAheadOfUtc(int offset) |
133 | 791 | { |
134 | 791 | return fromDurationAheadOfUtc(std::chrono::seconds{offset}); |
135 | 791 | } |
136 | | constexpr Qt::TimeSpec timeSpec() const noexcept { return d.s.spec(); } |
137 | | constexpr int fixedSecondsAheadOfUtc() const noexcept |
138 | | { return timeSpec() == Qt::OffsetFromUTC ? int(d.s.offset) : 0; } |
139 | | |
140 | | static constexpr bool isUtcOrFixedOffset(Qt::TimeSpec spec) noexcept |
141 | | { return spec == Qt::UTC || spec == Qt::OffsetFromUTC; } |
142 | | constexpr bool isUtcOrFixedOffset() const noexcept { return isUtcOrFixedOffset(timeSpec()); } |
143 | | |
144 | | #if QT_CONFIG(timezone) |
145 | | QTimeZone asBackendZone() const; |
146 | | |
147 | | enum TimeType { |
148 | | StandardTime = 0, |
149 | | DaylightTime = 1, |
150 | | GenericTime = 2 |
151 | | }; |
152 | | |
153 | | enum NameType { |
154 | | DefaultName = 0, |
155 | | LongName = 1, |
156 | | ShortName = 2, |
157 | | OffsetName = 3 |
158 | | }; |
159 | | |
160 | | struct OffsetData { |
161 | | QString abbreviation; |
162 | | QDateTime atUtc; |
163 | | int offsetFromUtc; |
164 | | int standardTimeOffset; |
165 | | int daylightTimeOffset; |
166 | | }; |
167 | | typedef QList<OffsetData> OffsetDataList; |
168 | | |
169 | | bool hasAlternativeName(QByteArrayView alias) const; |
170 | | QByteArray id() const; |
171 | | QLocale::Territory territory() const; |
172 | | # if QT_DEPRECATED_SINCE(6, 6) |
173 | | QT_DEPRECATED_VERSION_X_6_6("Use territory() instead") |
174 | | QLocale::Country country() const; |
175 | | # endif |
176 | | QString comment() const; |
177 | | |
178 | | QString displayName(const QDateTime &atDateTime, NameType nameType = DefaultName, |
179 | | const QLocale &locale = QLocale()) const; |
180 | | QString displayName(TimeType timeType, NameType nameType = DefaultName, |
181 | | const QLocale &locale = QLocale()) const; |
182 | | QString abbreviation(const QDateTime &atDateTime) const; |
183 | | |
184 | | int offsetFromUtc(const QDateTime &atDateTime) const; |
185 | | int standardTimeOffset(const QDateTime &atDateTime) const; |
186 | | int daylightTimeOffset(const QDateTime &atDateTime) const; |
187 | | |
188 | | bool hasDaylightTime() const; |
189 | | bool isDaylightTime(const QDateTime &atDateTime) const; |
190 | | |
191 | | OffsetData offsetData(const QDateTime &forDateTime) const; |
192 | | |
193 | | bool hasTransitions() const; |
194 | | OffsetData nextTransition(const QDateTime &afterDateTime) const; |
195 | | OffsetData previousTransition(const QDateTime &beforeDateTime) const; |
196 | | OffsetDataList transitions(const QDateTime &fromDateTime, const QDateTime &toDateTime) const; |
197 | | |
198 | | static QByteArray systemTimeZoneId(); |
199 | | static QTimeZone systemTimeZone(); |
200 | | static QTimeZone utc(); |
201 | | |
202 | | static bool isTimeZoneIdAvailable(const QByteArray &ianaId); |
203 | | |
204 | | static QList<QByteArray> availableTimeZoneIds(); |
205 | | static QList<QByteArray> availableTimeZoneIds(QLocale::Territory territory); |
206 | | static QList<QByteArray> availableTimeZoneIds(int offsetSeconds); |
207 | | |
208 | | static QByteArray ianaIdToWindowsId(const QByteArray &ianaId); |
209 | | static QByteArray windowsIdToDefaultIanaId(const QByteArray &windowsId); |
210 | | static QByteArray windowsIdToDefaultIanaId(const QByteArray &windowsId, |
211 | | QLocale::Territory territory); |
212 | | static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId); |
213 | | static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId, |
214 | | QLocale::Territory territory); |
215 | | |
216 | | # if defined(Q_OS_DARWIN) || defined(Q_QDOC) |
217 | | static QTimeZone fromCFTimeZone(CFTimeZoneRef timeZone); |
218 | | CFTimeZoneRef toCFTimeZone() const Q_DECL_CF_RETURNS_RETAINED; |
219 | | static QTimeZone fromNSTimeZone(const NSTimeZone *timeZone); |
220 | | NSTimeZone *toNSTimeZone() const Q_DECL_NS_RETURNS_AUTORELEASED; |
221 | | # endif |
222 | | |
223 | | # if __cpp_lib_chrono >= 201907L || defined(Q_QDOC) |
224 | | QT_POST_CXX17_API_IN_EXPORTED_CLASS |
225 | | static QTimeZone fromStdTimeZonePtr(const std::chrono::time_zone *timeZone) |
226 | | { |
227 | | if (!timeZone) |
228 | | return QTimeZone(); |
229 | | const std::string_view timeZoneName = timeZone->name(); |
230 | | return QTimeZone(QByteArrayView(timeZoneName).toByteArray()); |
231 | | } |
232 | | # endif |
233 | | #endif // feature timezone |
234 | | private: |
235 | | friend Q_CORE_EXPORT bool comparesEqual(const QTimeZone &lhs, const QTimeZone &rhs) noexcept; |
236 | | Q_DECLARE_EQUALITY_COMPARABLE(QTimeZone) |
237 | | |
238 | | #ifndef QT_NO_DATASTREAM |
239 | | friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &ds, const QTimeZone &tz); |
240 | | #endif |
241 | | #ifndef QT_NO_DEBUG_STREAM |
242 | | friend Q_CORE_EXPORT QDebug operator<<(QDebug dbg, const QTimeZone &tz); |
243 | | #endif |
244 | | QTimeZone(QTimeZonePrivate &dd); |
245 | | friend class QTimeZonePrivate; |
246 | | friend class QDateTime; |
247 | | friend class QDateTimePrivate; |
248 | | Data d; |
249 | | }; |
250 | | |
251 | | #if QT_CONFIG(timezone) |
252 | | Q_DECLARE_TYPEINFO(QTimeZone::OffsetData, Q_RELOCATABLE_TYPE); |
253 | | #endif |
254 | | Q_DECLARE_SHARED(QTimeZone) |
255 | | |
256 | | #ifndef QT_NO_DATASTREAM |
257 | | Q_CORE_EXPORT QDataStream &operator<<(QDataStream &ds, const QTimeZone &tz); |
258 | | Q_CORE_EXPORT QDataStream &operator>>(QDataStream &ds, QTimeZone &tz); |
259 | | #endif |
260 | | |
261 | | #ifndef QT_NO_DEBUG_STREAM |
262 | | Q_CORE_EXPORT QDebug operator<<(QDebug dbg, const QTimeZone &tz); |
263 | | #endif |
264 | | |
265 | | #if QT_CONFIG(timezone) && __cpp_lib_chrono >= 201907L |
266 | | // zoned_time |
267 | | template <typename> // QT_POST_CXX17_API_IN_EXPORTED_CLASS |
268 | | inline QDateTime QDateTime::fromStdZonedTime(const std::chrono::zoned_time< |
269 | | std::chrono::milliseconds, |
270 | | const std::chrono::time_zone * |
271 | | > &time) |
272 | | { |
273 | | const auto sysTime = time.get_sys_time(); |
274 | | const QTimeZone timeZone = QTimeZone::fromStdTimeZonePtr(time.get_time_zone()); |
275 | | return fromMSecsSinceEpoch(sysTime.time_since_epoch().count(), timeZone); |
276 | | } |
277 | | #endif |
278 | | |
279 | | QT_END_NAMESPACE |
280 | | |
281 | | #endif // QTIMEZONE_H |