Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtimezone.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
5
6#include "qtimezone.h"
7#if QT_CONFIG(timezone)
8# include "qtimezoneprivate_p.h"
9#endif
10
11#include <QtCore/qdatastream.h>
12#include <QtCore/qdatetime.h>
13
14#include <qdebug.h>
15
16#include <algorithm>
17
18QT_BEGIN_NAMESPACE
19
20static_assert(!std::is_constructible_v<QTimeZone, Qt::TimeSpec>);
21using namespace Qt::StringLiterals;
22
23#if QT_CONFIG(timezone)
24// Create default time zone using appropriate backend
25static QTimeZonePrivate *newBackendTimeZone()
26{
27#if QT_CONFIG(timezone_tzdb)
28 return new QChronoTimeZonePrivate();
29#elif defined(Q_OS_DARWIN)
30 return new QMacTimeZonePrivate();
31#elif defined(Q_OS_ANDROID)
32 return new QAndroidTimeZonePrivate();
33#elif defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) && !defined(Q_OS_WASM)
34 return new QTzTimeZonePrivate();
35#elif QT_CONFIG(icu)
36 return new QIcuTimeZonePrivate();
37#elif defined(Q_OS_WIN)
38 return new QWinTimeZonePrivate();
39#else
40 return new QUtcTimeZonePrivate();
41#endif // Backend selection
42}
43
44// Create named time zone using appropriate backend
45static QTimeZonePrivate *newBackendTimeZone(const QByteArray &ianaId)
46{
47 Q_ASSERT(!ianaId.isEmpty());
48#if QT_CONFIG(timezone_tzdb)
49 return new QChronoTimeZonePrivate(ianaId);
50#elif defined(Q_OS_DARWIN)
51 return new QMacTimeZonePrivate(ianaId);
52#elif defined(Q_OS_ANDROID)
53 return new QAndroidTimeZonePrivate(ianaId);
54#elif defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) && !defined(Q_OS_WASM)
55 return new QTzTimeZonePrivate(ianaId);
56#elif QT_CONFIG(icu)
57 return new QIcuTimeZonePrivate(ianaId);
58#elif defined(Q_OS_WIN)
59 return new QWinTimeZonePrivate(ianaId);
60#else
61 return new QUtcTimeZonePrivate(ianaId);
62#endif // Backend selection
63}
64
65class QTimeZoneSingleton
66{
67public:
68 QTimeZoneSingleton() : backend(newBackendTimeZone()) {}
69
70 // The global_tz is the tz to use in static methods such as
71 // availableTimeZoneIds() and isTimeZoneIdAvailable() and to create named
72 // IANA time zones. This is usually the host system, but may be different if
73 // the host resources are insufficient. A simple UTC backend is used if no
74 // alternative is available.
75 QExplicitlySharedDataPointer<QTimeZonePrivate> backend;
76 // TODO QTBUG-56899: refresh should update this backend.
77};
78
79Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz);
80#endif // feature timezone
81
82/*!
83 \class QTimeZone
84 \inmodule QtCore
85 \since 5.2
86 \threadsafe
87
88 \brief QTimeZone identifies how a time representation relates to UTC.
89
90 \compares equality
91
92 When dates and times are combined, the meaning of the result depends on how
93 time is being represented. There are various international standards for
94 representing time; one of these, UTC, corresponds to the traditional
95 standard of solar mean time at Greenwich (a.k.a. GMT). All other time
96 systems supported by Qt are ultimately specified in relation to UTC. An
97 instance of this class provides a stateless calculator for conversions
98 between UTC and other time representations.
99
100 Some time representations are simply defined at a fixed offset to UTC.
101 Others are defined by governments for use within their jurisdictions. The
102 latter are properly known as time zones, but QTimeZone (since Qt 6.5) is
103 unifies their representation with that of general time systems. One time
104 zone generally supported on most operating systems is designated local time;
105 this is presumed to correspond to the time zone within which the user is
106 living.
107
108 For time zones other than local time, UTC and those at fixed offsets from
109 UTC, Qt can only provide support when the operating system provides some way
110 to access that information. When Qt is built, the \c timezone feature
111 controls whether such information is available. When it is not, some
112 constructors and methods of QTimeZone are excluded from its API; these are
113 documented as depending on feature \c timezone. Note that, even when Qt is
114 built with this feature enabled, it may be unavailable to users whose
115 systems are misconfigured, or where some standard packages (for example, the
116 \c tzdata package on Linux) are not installed. This feature is enabled by
117 default when time zone information is available.
118
119 This class is primarily designed for use in QDateTime; most applications
120 will not need to access this class directly and should instead use an
121 instance of it when constructing a QDateTime.
122
123 \note For consistency with QDateTime, QTimeZone does not account for leap
124 seconds.
125
126 \section1 Remarks
127
128 QTimeZone, like QDateTime, measures offsets from UTC in seconds. This
129 contrasts with their measurement of time generally, which they do in
130 milliseconds. Real-world time zones generally have UTC offsets that are
131 whole-number multiples of five minutes (300 seconds), at least since well
132 before 1970. A positive offset from UTC gives a time representation puts
133 noon on any given day before UTC noon on that day; a negative offset puts
134 noon after UTC noon on the same day.
135
136 \section2 Lightweight Time Representations
137
138 QTimeZone can represent UTC, local time and fixed offsets from UTC even when
139 feature \c timezone is disabled. The form in which it does so is also
140 available when the feature is enabled; it is a more lightweight form and
141 processing using it will typically be more efficient, unless methods only
142 available when feature \c timezone is enabled are being exercised. See \l
143 Initialization and \l QTimeZone::fromSecondsAheadOfUtc(int) for how to
144 construct these representations.
145
146 This documentation distinguishes between "time zone", used to describe a
147 time representation described by system-supplied or standard information,
148 and time representations more generally, which include these lightweight
149 forms. The methods available only when feature \c timezone is enabled are
150 apt to be cheaper for time zones than for lightweight time representations,
151 for which these methods may construct a suitable transient time zone object
152 to which to forward the query.
153
154 \section2 IANA Time Zone IDs
155
156 QTimeZone uses the IANA time zone IDs as defined in the IANA Time Zone
157 Database (http://www.iana.org/time-zones). This is to ensure a standard ID
158 across all supported platforms. Most platforms support the IANA IDs
159 and the IANA Database natively, but for Windows a mapping is required to
160 the native IDs. See below for more details.
161
162 The IANA IDs can and do change on a regular basis, and can vary depending
163 on how recently the host system data was updated. As such you cannot rely
164 on any given ID existing on any host system. You must use
165 availableTimeZoneIds() to determine what IANA IDs are available.
166
167 The IANA IDs and database are also know as the Olson IDs and database,
168 named after the original compiler of the database.
169
170 \section2 UTC Offset Time Zones
171
172 A default UTC time zone backend is provided which is always available when
173 feature \c timezone is enabled. This provides a set of generic Offset From
174 UTC time zones in the range UTC-16:00 to UTC+16:00. These time zones can be
175 created using either the standard ISO format names, such as "UTC+00:00", as
176 listed by availableTimeZoneIds(), or using a name of similar form in
177 combination with the number of offset seconds.
178
179 \section2 Windows Time Zones
180
181 Windows native time zone support is severely limited compared to the
182 standard IANA TZ Database. Windows time zones cover larger geographic
183 areas and are thus less accurate in their conversions. They also do not
184 support as much historical data and so may only be accurate for the
185 current year. In particular, when MS's zone data claims that DST was
186 observed prior to 1900 (this is historically known to be untrue), the
187 claim is ignored and the standard time (allegedly) in force in 1900 is
188 taken to have always been in effect.
189
190 QTimeZone uses a conversion table derived from the Unicode CLDR data to map
191 between IANA IDs and Windows IDs. Depending on your version of Windows
192 and Qt, this table may not be able to provide a valid conversion, in which
193 "UTC" will be returned.
194
195 QTimeZone provides a public API to use this conversion table. The Windows ID
196 used is the Windows Registry Key for the time zone which is also the MS
197 Exchange EWS ID as well, but is different to the Time Zone Name (TZID) and
198 COD code used by MS Exchange in versions before 2007.
199
200 \note When Qt is built with the ICU library, it is used in preference to the
201 Windows system APIs, bypassing all problems with those APIs using different
202 names.
203
204 \section2 WebAssembly
205
206 On WebAssembly, QTimeZone supports only UTC and fixed UTC-offset time zones
207 when represented in backend-based form. The IANA timezone database is not
208 available, so functions like availableTimeZoneIds() return only UTC offset
209 zones. The system time zone is obtained via JavaScript's
210 \c{Date.getTimezoneOffset()} and represented as a fixed offset (e.g.,
211 "UTC+02:00") rather than a geographic IANA ID. However,
212 QTimeZone(QTimeZone::LocalTime) still provides a faithful representation
213 of local time, as it relies on the platform's standard time functions.
214
215 \section2 System Time Zone
216
217 The method systemTimeZoneId() returns the current system IANA time zone
218 ID which on Unix-like systems will always be correct. On Windows this ID is
219 translated from the Windows system ID using an internal translation
220 table and the user's selected country. As a consequence there is a small
221 chance any Windows install may have IDs not known by Qt, in which case
222 "UTC" will be returned.
223
224 Creating a new QTimeZone instance using the system time zone ID will only
225 produce a fixed named copy of the time zone, it will not change if the
226 system time zone changes. QTimeZone::systemTimeZone() will return an
227 instance representing the zone named by this system ID. Note that
228 constructing a QDateTime using this system zone may behave differently than
229 constructing a QDateTime that uses Qt::LocalTime as its Qt::TimeSpec, as the
230 latter directly uses system APIs for accessing local time information, which
231 may behave differently (and, in particular, might adapt if the user adjusts
232 the system zone setting).
233
234 \section2 Time Zone Offsets
235
236 The difference between UTC and the local time in a time zone is expressed
237 as an offset in seconds from UTC, i.e. the number of seconds to add to UTC
238 to obtain the local time. The total offset is comprised of two component
239 parts, the standard time offset and the daylight-saving time offset. The
240 standard time offset is the number of seconds to add to UTC to obtain
241 standard time in the time zone. The daylight-saving time offset is the
242 number of seconds to add to the standard time offset to obtain
243 daylight-saving time (abbreviated DST and sometimes called "daylight time"
244 or "summer time") in the time zone. The usual case for DST (using
245 standard time in winter, DST in summer) has a positive daylight-saving
246 time offset. However, some zones have negative DST offsets, used in
247 winter, with summer using standard time.
248
249 Note that the standard and DST offsets for a time zone may change over time
250 as countries have changed DST laws or even their standard time offset.
251
252 \section2 License
253
254 This class includes data obtained from the CLDR data files under the terms
255 of the Unicode Data Files and Software License. See
256 \l{unicode-cldr}{Unicode Common Locale Data Repository (CLDR)} for details.
257
258 \sa QDateTime, QCalendar
259*/
260
261/*!
262 \variable QTimeZone::MinUtcOffsetSecs
263 \brief Timezone offsets from UTC are expected to be no lower than this.
264
265 The lowest UTC offset of any early 21st century timezone is -12 hours (Baker
266 Island, USA), or 12 hours west of Greenwich.
267
268 Historically, until 1844, The Philippines (then controlled by Spain) used
269 the same date as Spain's American holdings, so had offsets close to 16 hours
270 west of Greenwich. As The Philippines was using local solar mean time, it is
271 possible some outlying territory of it may have been operating at more than
272 16 hours west of Greenwich, but no early 21st century timezone traces its
273 history back to such an extreme.
274
275 \sa MaxUtcOffsetSecs
276*/
277/*!
278 \variable QTimeZone::MaxUtcOffsetSecs
279 \brief Timezone offsets from UTC are expected to be no higher than this.
280
281 The highest UTC offset of any early 21st century timezone is +14 hours
282 (Christmas Island, Kiribati, Kiritimati), or 14 hours east of Greenwich.
283
284 Historically, before 1867, when Russia sold Alaska to America, Alaska used
285 the same date as Russia, so had offsets over 15 hours east of Greenwich. As
286 Alaska was using local solar mean time, its offsets varied, but all were
287 less than 16 hours east of Greenwich.
288
289 \sa MinUtcOffsetSecs
290*/
291
292#if QT_CONFIG(timezone)
293/*!
294 \enum QTimeZone::TimeType
295
296 A timezone's name may vary seasonally to indicate whether it is using its
297 standard offset from UTC or applying a daylight-saving adjustment to that
298 offset. In such cases, it typically also has an overall name that applies to
299 it regardless of season. When requesting the display name of a zone, this
300 type identifies which of those names to use. In time zones that do not apply
301 DST, all three values may return the same result.
302
303 \value StandardTime
304 The standard-time name of the zone.
305 For example, "Pacific Standard Time".
306 \value DaylightTime
307 The name of the zone when Daylight-Saving is in effect.
308 For example, "Pacific Daylight Time".
309 \value GenericTime
310 The name by which the zone is described independent of whether it is
311 applying any daylight-saving adjustment.
312 For example, "Pacific Time".
313
314 This type is only available when feature \c timezone is enabled.
315*/
316
317/*!
318 \enum QTimeZone::NameType
319
320 The type of time zone name.
321
322 \value DefaultName
323 The default form of the time zone name, one of LongName, ShortName or
324 OffsetName
325 \value LongName
326 The long form of the time zone name, e.g. "Central European Time"
327 \value ShortName
328 The short form of the time zone name, usually an abbreviation,
329 e.g. "CET", in locales that have one for the zone, otherwise a
330 compact GMT-offset form, e.g. "GMT+1"
331 \value OffsetName
332 The standard ISO offset form of the time zone name, e.g. "UTC+01:00"
333
334 This type is only available when feature \c timezone is enabled.
335*/
336
337/*!
338 \class QTimeZone::OffsetData
339 \inmodule QtCore
340
341 The time zone offset data for a given moment in time.
342
343 This provides the time zone offsets and abbreviation to use at a given
344 moment in time. When a function returns this type, it may use an invalid
345 datetime to indicate that the query it is answering has no valid answer, so
346 check \c{atUtc.isValid()} before using the results.
347
348 \list
349 \li OffsetData::atUtc The datetime of the offset data in UTC time.
350 \li OffsetData::offsetFromUtc The total offset from UTC in effect at the datetime.
351 \li OffsetData::standardTimeOffset The standard time offset component of the total offset.
352 \li OffsetData::daylightTimeOffset The DST offset component of the total offset.
353 \li OffsetData::abbreviation The abbreviation in effect at the datetime.
354 \endlist
355
356 For example, for time zone "Europe/Berlin" the OffsetDate in standard and DST might be:
357
358 \list
359 \li atUtc = QDateTime(QDate(2013, 1, 1), QTime(0, 0), QTimeZone::UTC)
360 \li offsetFromUtc = 3600
361 \li standardTimeOffset = 3600
362 \li daylightTimeOffset = 0
363 \li abbreviation = "CET"
364 \endlist
365
366 \list
367 \li atUtc = QDateTime(QDate(2013, 6, 1), QTime(0, 0), QTimeZone::UTC)
368 \li offsetFromUtc = 7200
369 \li standardTimeOffset = 3600
370 \li daylightTimeOffset = 3600
371 \li abbreviation = "CEST"
372 \endlist
373
374 This type is only available when feature \c timezone is enabled.
375*/
376
377/*!
378 \typedef QTimeZone::OffsetDataList
379
380 Synonym for QList<OffsetData>.
381
382 This type is only available when feature \c timezone is enabled.
383*/
384#endif // timezone backends
385
386QTimeZone::Data::Data() noexcept : d(nullptr)
387{
388 // Assumed by the conversion between spec and mode:
389 static_assert(int(Qt::TimeZone) == 3);
390}
391
392QTimeZone::Data::Data(const Data &other) noexcept
393{
394#if QT_CONFIG(timezone)
395 if (!other.isShort() && other.d)
396 other.d->ref.ref();
397#endif
398 d = other.d;
399}
400
401QTimeZone::Data::Data(QTimeZonePrivate *dptr) noexcept
402 : d(dptr)
403{
404#if QT_CONFIG(timezone)
405 if (d)
406 d->ref.ref();
407#endif
408}
409
410QTimeZone::Data::~Data()
411{
412#if QT_CONFIG(timezone)
413 if (!isShort() && d && !d->ref.deref())
414 delete d;
415 d = nullptr;
416#endif
417}
418
419QTimeZone::Data &QTimeZone::Data::operator=(const Data &other) noexcept
420{
421#if QT_CONFIG(timezone)
422 if (!other.isShort())
423 return *this = other.d;
424 if (!isShort() && d && !d->ref.deref())
425 delete d;
426#endif
427 d = other.d;
428 return *this;
429}
430
431/*!
432 Create a null/invalid time zone instance.
433*/
434
435QTimeZone::QTimeZone() noexcept
436{
437 // Assumed by (at least) Data::swap() and {copy,move} {assign,construct}:
438 static_assert(sizeof(ShortData) <= sizeof(Data::d));
439 // Needed for ShortData::offset to represent all valid offsets:
440 static_assert(qintptr(1) << (sizeof(void *) * 8 - 2) >= MaxUtcOffsetSecs);
441}
442
443#if QT_CONFIG(timezone)
444QTimeZone::Data &QTimeZone::Data::operator=(QTimeZonePrivate *dptr) noexcept
445{
446 if (!isShort()) {
447 if (d == dptr)
448 return *this;
449 if (d && !d->ref.deref())
450 delete d;
451 }
452 if (dptr)
453 dptr->ref.ref();
454 d = dptr;
455 Q_ASSERT(!isShort());
456 return *this;
457}
458
459/*!
460 Creates a time zone instance with the requested IANA ID \a ianaId.
461
462 The ID must be one of the available system IDs or a valid UTC-with-offset
463 ID, otherwise an invalid time zone will be returned. For UTC-with-offset
464 IDs, when they are not in fact IANA IDs, the \c{id()} of the resulting
465 instance may differ from the ID passed to the constructor.
466
467 This constructor is only available when feature \c timezone is enabled.
468
469 \sa availableTimeZoneIds(), id()
470*/
471
472QTimeZone::QTimeZone(const QByteArray &ianaId)
473{
474 // Try and see if it's a recognized UTC offset ID - just as quick by
475 // creating as by looking up.
476 d = new QUtcTimeZonePrivate(ianaId);
477 // If not recognized, try creating it with the system backend.
478 if (!d->isValid()) {
479 if (ianaId.isEmpty()) {
480 d = newBackendTimeZone();
481 } else { // Constructor MUST produce invalid for unsupported ID.
482 d = newBackendTimeZone(ianaId);
483 if (!d->isValid()) {
484 // We may have a legacy alias for a supported IANA ID:
485 QByteArrayView name = QTimeZonePrivate::aliasToIana(ianaId);
486 // Or an alias for an IANA ID that has a supported alias:
487 if (name.isEmpty() || name == ianaId)
488 name = global_tz->backend->availableAlias(ianaId);
489 if (!name.isEmpty() && name != ianaId)
490 d = newBackendTimeZone(name.toByteArray());
491 }
492 }
493 }
494 // Can also handle UTC with arbitrary (valid) offset, but only do so as
495 // fall-back, since either of the above may handle it more informatively.
496 if (!d->isValid()) {
497 qint64 offset = QUtcTimeZonePrivate::offsetFromUtcString(ianaId);
498 if (offset != QTimeZonePrivate::invalidSeconds()) {
499 // Should have abs(offset) < 24 * 60 * 60 = 86400.
500 qint32 seconds = qint32(offset);
501 Q_ASSERT(qint64(seconds) == offset);
502 // NB: this canonicalises the name, so it might not match ianaId
503 d = new QUtcTimeZonePrivate(seconds);
504 }
505 }
506}
507
508/*!
509 Creates a time zone instance with the given offset, \a offsetSeconds, from UTC.
510
511 The \a offsetSeconds from UTC must be in the range -16 hours to +16 hours
512 otherwise an invalid time zone will be returned.
513
514 This constructor is only available when feature \c timezone is enabled. The
515 returned instance is equivalent to the lightweight time representation
516 \c{QTimeZone::fromSecondsAheadOfUtc(offsetSeconds)}, albeit implemented as a
517 time zone.
518
519 \sa MinUtcOffsetSecs, MaxUtcOffsetSecs, id()
520*/
521
522QTimeZone::QTimeZone(int offsetSeconds)
523 : d((offsetSeconds >= MinUtcOffsetSecs && offsetSeconds <= MaxUtcOffsetSecs)
524 ? new QUtcTimeZonePrivate(offsetSeconds) : nullptr)
525{
526}
527
528/*!
529 Creates a custom time zone instance at fixed offset from UTC.
530
531 The returned time zone has an ID of \a zoneId and an offset from UTC of \a
532 offsetSeconds. The \a name will be the name used by displayName() for the
533 LongName, the \a abbreviation will be used by displayName() for the
534 ShortName and by abbreviation(), and the optional \a territory will be used
535 by territory(). The \a comment is an optional note that may be displayed in
536 a GUI to assist users in selecting a time zone.
537
538 The \a offsetSeconds from UTC must be in the range -16 hours to +16 hours.
539 The \a zoneId \e{must not} be an ID for which isTimeZoneIdAvailable() is
540 true, unless it is a UTC-offset name that doesn't appear in
541 availableTimeZoneIds().
542
543 If the custom time zone does not have a specific territory then set it to the
544 default value of QLocale::AnyTerritory.
545
546 This constructor is only available when feature \c timezone is enabled.
547
548 \sa id(), offsetFromUtc(), displayName(), abbreviation(), territory(), comment(),
549 MinUtcOffsetSecs, MaxUtcOffsetSecs
550*/
551
552QTimeZone::QTimeZone(const QByteArray &zoneId, int offsetSeconds, const QString &name,
553 const QString &abbreviation, QLocale::Territory territory, const QString &comment)
554 : d(QUtcTimeZonePrivate().isTimeZoneIdAvailable(zoneId)
555 || global_tz->backend->isTimeZoneIdAvailable(zoneId)
556 ? nullptr // Don't let client code hijack a real zone name.
557 : new QUtcTimeZonePrivate(zoneId, offsetSeconds, name, abbreviation, territory, comment))
558{
559}
560
561/*!
562 \internal
563
564 Private. Create time zone with given private backend
565
566 This constructor is only available when feature \c timezone is enabled.
567*/
568
569QTimeZone::QTimeZone(QTimeZonePrivate &dd)
570 : d(&dd)
571{
572}
573
574/*!
575 \since 6.5
576 Converts this QTimeZone to one whose timeSpec() is Qt::TimeZone.
577
578 In all cases, the result's \l timeSpec() is Qt::TimeZone. When this
579 QTimeZone's timeSpec() is Qt::TimeZone, this QTimeZone itself is returned.
580 If timeSpec() is Qt::LocalTime then systemTimeZone() is returned.
581
582 If timeSpec() is Qt::UTC, QTimeZone::utc() is returned. If it is
583 Qt::OffsetFromUTC then QTimeZone(int) is passed its offset and the result is
584 returned.
585
586 When using a lightweight time representation - local time, UTC time or time
587 at a fixed offset from UTC - using methods only supported when feature \c
588 timezone is enabled may be more expensive than using a corresponding time
589 zone. This method maps a lightweight time representation to a corresponding
590 time zone - that is, an instance based on system-supplied or standard data.
591
592 This method is only available when feature \c timezone is enabled.
593
594 \sa QTimeZone(QTimeZone::Initialization), fromSecondsAheadOfUtc()
595*/
596
597QTimeZone QTimeZone::asBackendZone() const
598{
599 switch (timeSpec()) {
600 case Qt::TimeZone:
601 return *this;
602 case Qt::LocalTime:
603 return systemTimeZone();
604 case Qt::UTC:
605 return utc();
606 case Qt::OffsetFromUTC:
607 return QTimeZone(*new QUtcTimeZonePrivate(int(d.s.offset)));
608 }
609 return QTimeZone();
610}
611#endif // timezone backends
612
613/*!
614 \since 6.5
615 \enum QTimeZone::Initialization
616
617 The type of the simplest lightweight time representations.
618
619 This enumeration identifies a type of lightweight time representation to
620 pass to a QTimeZone constructor, where no further data are required. They
621 correspond to the like-named members of Qt::TimeSpec.
622
623 \value LocalTime This time representation corresponds to the one implicitly
624 used by system functions using \c time_t and \c {struct tm}
625 value to map between local time and UTC time.
626
627 \value UTC This time representation, Coordinated Universal Time, is the base
628 representation to which civil time is referred in all supported
629 time representations. It is defined by the International
630 Telecommunication Union.
631*/
632
633/*!
634 \since 6.5
635 \fn QTimeZone::QTimeZone(Initialization spec) noexcept
636
637 Creates a lightweight instance describing UTC or local time.
638
639 \sa fromSecondsAheadOfUtc(), asBackendZone(), utc(), systemTimeZone()
640*/
641
642/*!
643 \since 6.5
644 \fn QTimeZone::fromSecondsAheadOfUtc(int offset)
645 \fn QTimeZone::fromDurationAheadOfUtc(std::chrono::seconds offset)
646
647 Returns a time representation at a fixed \a offset, in seconds, ahead of
648 UTC.
649
650 The \a offset from UTC must be in the range -16 hours to +16 hours otherwise
651 an invalid time zone will be returned. The returned QTimeZone is a
652 lightweight time representation, not a time zone (backed by system-supplied
653 or standard data).
654
655 If the offset is 0, the \l timeSpec() of the returned instance will be
656 Qt::UTC. Otherwise, if \a offset is valid, timeSpec() is
657 Qt::OffsetFromUTC. An invalid time zone, when returned, has Qt::TimeZone as
658 its timeSpec().
659
660 \sa QTimeZone(int), asBackendZone(), fixedSecondsAheadOfUtc(),
661 MinUtcOffsetSecs, MaxUtcOffsetSecs
662*/
663
664/*!
665 \since 6.5
666 \fn Qt::TimeSpec QTimeZone::timeSpec() const noexcept
667
668 Returns a Qt::TimeSpec identifying the type of time representation.
669
670 If the result is Qt::TimeZone, this time description is a time zone (backed
671 by system-supplied or standard data); otherwise, it is a lightweight time
672 representation. If the result is Qt::LocalTime it describes local time: see
673 Qt::TimeSpec for details.
674
675 \sa fixedSecondsAheadOfUtc(), asBackendZone()
676*/
677
678/*!
679 \since 6.5
680 \fn int QTimeZone::fixedSecondsAheadOfUtc() const noexcept
681
682 For a lightweight time representation whose \l timeSpec() is Qt::OffsetFromUTC,
683 this returns the fixed offset from UTC that it describes. For any other time
684 representation it returns 0, even if that time representation does have a
685 constant offset from UTC.
686*/
687
688/*!
689 \since 6.5
690 \fn QTimeZone::isUtcOrFixedOffset(Qt::TimeSpec spec) noexcept
691
692 Returns \c true if \a spec is Qt::UTC or Qt::OffsetFromUTC.
693*/
694
695/*!
696 \since 6.5
697 \fn QTimeZone::isUtcOrFixedOffset() const noexcept
698
699 Returns \c true if \l timeSpec() is Qt::UTC or Qt::OffsetFromUTC.
700
701 When it is true, the time description does not change over time, such as
702 having seasonal daylight-saving changes, as may happen for local time or a
703 time zone. Knowing this may save the calling code to need for various other
704 checks.
705*/
706
707/*!
708 Copy constructor: copy \a other to this.
709*/
710
711QTimeZone::QTimeZone(const QTimeZone &other) noexcept
712 : d(other.d)
713{
714}
715
716/*!
717 \fn QTimeZone::QTimeZone(QTimeZone &&other) noexcept
718
719 Move constructor of this from \a other.
720*/
721
722/*!
723 Destroys the time zone.
724*/
725
726QTimeZone::~QTimeZone()
727{
728}
729
730/*!
731 \fn QTimeZone::swap(QTimeZone &other) noexcept
732 \memberswap{time zone instance}
733*/
734
735/*!
736 Assignment operator, assign \a other to this.
737*/
738
739QTimeZone &QTimeZone::operator=(const QTimeZone &other)
740{
741 d = other.d;
742 return *this;
743}
744
745/*!
746 \fn QTimeZone &QTimeZone::operator=(QTimeZone &&other)
747
748 Move-assigns \a other to this QTimeZone instance, transferring the ownership
749 of its data to this instance.
750*/
751
752/*!
753 \fn bool QTimeZone::operator==(const QTimeZone &lhs, const QTimeZone &rhs)
754
755 Returns \c true if \a lhs time zone is equal to the \a rhs time zone.
756
757 Two representations are different if they are internally described
758 differently, even if they agree in their representation of all moments of
759 time. In particular, a lightweight time representation may coincide with a
760 time zone but the two will not be equal.
761*/
762
763/*!
764 \fn bool QTimeZone::operator!=(const QTimeZone &lhs, const QTimeZone &rhs)
765
766 Returns \c true if \a lhs time zone is not equal to the \a rhs time zone.
767
768 Two representations are different if they are internally described
769 differently, even if they agree in their representation of all moments of
770 time. In particular, a lightweight time representation may coincide with a
771 time zone but the two will not be equal.
772*/
773
774bool comparesEqual(const QTimeZone &lhs, const QTimeZone &rhs) noexcept
775{
776 if (lhs.d.isShort())
777 return rhs.d.isShort() && lhs.d.s == rhs.d.s;
778
779 if (!rhs.d.isShort()) {
780 if (lhs.d.d == rhs.d.d)
781 return true;
782#if QT_CONFIG(timezone)
783 return lhs.d.d && rhs.d.d && *lhs.d.d == *rhs.d.d;
784#endif
785 }
786
787 return false;
788}
789
790/*!
791 Returns \c true if this time zone is valid.
792*/
793
794bool QTimeZone::isValid() const
795{
796#if QT_CONFIG(timezone)
797 if (!d.isShort())
798 return d.d && d->isValid();
799#endif
800 return d.isShort();
801}
802
803#if QT_CONFIG(timezone)
804/*!
805 Returns the IANA ID for the time zone.
806
807 IANA IDs are used on all platforms. On Windows these are translated from
808 the Windows ID into the best match IANA ID for the time zone and territory.
809
810 If this timezone instance was not constructed from an IANA ID, its ID is
811 determined by how it was constructed. In most cases, the ID passed when
812 constructing the instance is used. (The constructor for a custom zone uses
813 the ID it is passed, which must not be an IANA ID.) There are two
814 exceptions.
815 \list
816 \li Instances constructed by passing only a UTC offset in seconds have no ID
817 passed when constructing.
818 \li The constructor taking only an IANA ID will also accept some UTC-offset
819 IDs that are not in fact IANA IDs: its handling of these is equivalent
820 to passing the corresponding offset in seconds, as for the first
821 exception.
822 \endlist
823
824 In the two exceptional cases, if there is an IANA UTC-offset zone with the
825 specified offset, the instance constructed uses that IANA zone's ID, even
826 though this may differ from the (non-IANA) UTC-offset ID passed to the
827 constructor. Otherwise, the instance uses an ID synthesized from its offset,
828 with the form UTC±hh:mm:ss, omitting any trailing :00 for zero seconds or
829 minutes. Again, this may differ from the UTC-offset ID passed to the
830 constructor.
831
832 This method is only available when feature \c timezone is enabled.
833*/
834
835QByteArray QTimeZone::id() const
836{
837 if (d.isShort()) {
838 switch (d.s.spec()) {
839 case Qt::UTC:
840 return QTimeZonePrivate::utcQByteArray();
841 case Qt::LocalTime:
842 return systemTimeZoneId();
843 case Qt::OffsetFromUTC:
844 return QUtcTimeZonePrivate(d.s.offset).id();
845 case Qt::TimeZone:
846 Q_UNREACHABLE();
847 break;
848 }
849 } else if (d.d) {
850 return d->id();
851 }
852 return QByteArray();
853}
854
855/*!
856 \since 6.8
857 Returns \c true if \a alias is an alternative name for this timezone.
858
859 The IANA (formerly Olson) database has renamed some zones during its
860 history. There are also some zones that only differed prior to 1970 but are
861 now treated as synonymous. Some backends may have data reaching to before
862 1970 and produce distinct zones in the latter case. Others may produce zones
863 indistinguishable except by id(). This method determines whether an ID
864 refers (at least since 1970) to the same zone that this timezone object
865 describes.
866
867 This method is only available when feature \c timezone is enabled.
868
869 \sa isTimeZoneIdAvailable()
870*/
871bool QTimeZone::hasAlternativeName(QByteArrayView alias) const
872{
873 const QByteArray me = id();
874 if (alias == me)
875 return true;
876 QByteArrayView mine = QTimeZonePrivate::aliasToIana(me);
877 // Empty if id() aliases to itself, which we've already checked:
878 if (mine.isEmpty())
879 mine = me; // To simplify the final conditional
880 else if (alias == mine)
881 return true;
882 QByteArrayView its = QTimeZonePrivate::aliasToIana(alias);
883 // Empty if alias aliases to itself, which we've already compared to id()
884 // and, where relevant, mine.
885 return !its.isEmpty() && its == mine;
886}
887
888/*!
889 \since 6.2
890
891 Returns the territory for the time zone.
892
893 A return of \l {QLocale::}{AnyTerritory} means the zone has no known
894 territorial association. In some cases this may be because the zone has no
895 associated territory - for example, UTC - or because the zone is used in
896 several territories - for example, CET. In other cases, the QTimeZone
897 backend may not know which territory the zone is associated with - for
898 example, because it is not the primary zone of the territory in which it is
899 used.
900
901 This method is only available when feature \c timezone is enabled.
902*/
903QLocale::Territory QTimeZone::territory() const
904{
905 if (d.isShort()) {
906 if (d.s.spec() == Qt::LocalTime)
907 return systemTimeZone().territory();
908 } else if (isValid()) {
909 return d->territory();
910 }
911 return QLocale::AnyTerritory;
912}
913
914#if QT_DEPRECATED_SINCE(6, 6)
915/*!
916 \deprecated [6.6] Use territory() instead.
917
918 Returns the territory for the time zone.
919
920 This method is only available when feature \c timezone is enabled.
921*/
922
923QLocale::Country QTimeZone::country() const
924{
925 return territory();
926}
927#endif
928
929/*!
930 Returns any comment for the time zone.
931
932 A comment may be provided by the host platform to assist users in
933 choosing the correct time zone. Depending on the platform this may not
934 be localized.
935
936 This method is only available when feature \c timezone is enabled.
937*/
938
939QString QTimeZone::comment() const
940{
941 if (d.isShort()) {
942 // TODO: anything ? Or just stick with empty string ?
943 } else if (isValid()) {
944 return d->comment();
945 }
946 return QString();
947}
948
949/*!
950 Returns the localized time zone display name.
951
952 The name returned is the one for the given \a locale, applicable at the
953 given \a atDateTime, and of the form indicated by \a nameType. The display
954 name may change depending on DST or historical events.
955//! [display-name-caveats]
956 If no suitably localized name of the given type is available, another name
957 type may be used, or an empty string may be returned.
958
959 If the \a locale is not provided, then the application default locale will
960 be used. For custom timezones created by client code, the data supplied to
961 the constructor are used, as no localization data will be available for it.
962 If this timezone is invalid, an empty string is returned. This may also
963 arise for the representation of local time if determining the system time
964 zone fails.
965
966 This method is only available when feature \c timezone is enabled.
967//! [display-name-caveats]
968
969 \sa abbreviation()
970*/
971
972QString QTimeZone::displayName(const QDateTime &atDateTime, NameType nameType,
973 const QLocale &locale) const
974{
975 if (d.isShort()) {
976 switch (d.s.spec()) {
977 case Qt::LocalTime:
978 return systemTimeZone().displayName(atDateTime, nameType, locale);
979 case Qt::UTC:
980 case Qt::OffsetFromUTC:
981 return QUtcTimeZonePrivate(d.s.offset).displayName(
982 atDateTime.toMSecsSinceEpoch(), nameType, locale);
983 case Qt::TimeZone:
984 Q_UNREACHABLE();
985 break;
986 }
987 } else if (isValid()) {
988 return d->displayName(atDateTime.toMSecsSinceEpoch(), nameType, locale);
989 }
990
991 return QString();
992}
993
994/*!
995 Returns the localized time zone display name.
996
997 The name returned is the one for the given \a locale, applicable when the
998 given \a timeType is in effect and of the form indicated by \a nameType.
999 Where the time zone display names have changed over time, the current names
1000 will be used.
1001 \include qtimezone.cpp display-name-caveats
1002
1003 \sa abbreviation()
1004*/
1005
1006QString QTimeZone::displayName(TimeType timeType, NameType nameType,
1007 const QLocale &locale) const
1008{
1009 if (d.isShort()) {
1010 switch (d.s.spec()) {
1011 case Qt::LocalTime:
1012 return systemTimeZone().displayName(timeType, nameType, locale);
1013 case Qt::UTC:
1014 case Qt::OffsetFromUTC:
1015 return QUtcTimeZonePrivate(d.s.offset).displayName(timeType, nameType, locale);
1016 case Qt::TimeZone:
1017 Q_UNREACHABLE();
1018 break;
1019 }
1020 } else if (isValid()) {
1021 return d->displayName(timeType, nameType, locale);
1022 }
1023
1024 return QString();
1025}
1026
1027/*!
1028 Returns the time zone abbreviation at the given \a atDateTime.
1029
1030 The abbreviation may change depending on DST or even historical events.
1031
1032 \note The abbreviation is not guaranteed to be unique to this time zone and
1033 should not be used in place of the ID or display name. The abbreviation may
1034 be localized, depending on the underlying operating system. To get consistent
1035 localization, use \c {displayName(atDateTime, QTimeZone::ShortName, locale)}.
1036
1037 This method is only available when feature \c timezone is enabled.
1038
1039 \sa displayName()
1040*/
1041
1042QString QTimeZone::abbreviation(const QDateTime &atDateTime) const
1043{
1044 if (d.isShort()) {
1045 switch (d.s.spec()) {
1046 case Qt::LocalTime:
1047 return systemTimeZone().abbreviation(atDateTime);
1048 case Qt::UTC:
1049 case Qt::OffsetFromUTC:
1050 return QUtcTimeZonePrivate(d.s.offset).abbreviation(atDateTime.toMSecsSinceEpoch());
1051 case Qt::TimeZone:
1052 Q_UNREACHABLE();
1053 break;
1054 }
1055 } else if (isValid()) {
1056 return d->abbreviation(atDateTime.toMSecsSinceEpoch());
1057 }
1058
1059 return QString();
1060}
1061
1062/*!
1063 Returns the total effective offset at the given \a atDateTime, i.e. the
1064 number of seconds to add to UTC to obtain the local time. This includes
1065 any DST offset that may be in effect, i.e. it is the sum of
1066 standardTimeOffset() and daylightTimeOffset() for the given datetime.
1067
1068 For example, for the time zone "Europe/Berlin" the standard time offset is
1069 +3600 seconds and the DST offset is +3600 seconds. During standard time
1070 offsetFromUtc() will return +3600 (UTC+01:00), and during DST it will
1071 return +7200 (UTC+02:00).
1072
1073 This method is only available when feature \c timezone is enabled.
1074
1075 \sa standardTimeOffset(), daylightTimeOffset()
1076*/
1077
1078int QTimeZone::offsetFromUtc(const QDateTime &atDateTime) const
1079{
1080 if (d.isShort()) {
1081 switch (d.s.spec()) {
1082 case Qt::LocalTime:
1083 return systemTimeZone().offsetFromUtc(atDateTime);
1084 case Qt::UTC:
1085 case Qt::OffsetFromUTC:
1086 return d.s.offset;
1087 case Qt::TimeZone:
1088 Q_UNREACHABLE();
1089 break;
1090 }
1091 } else if (isValid()) {
1092 const int offset = d->offsetFromUtc(atDateTime.toMSecsSinceEpoch());
1093 if (offset != QTimeZonePrivate::invalidSeconds())
1094 return offset;
1095 }
1096 return 0;
1097}
1098
1099/*!
1100 Returns the standard time offset at the given \a atDateTime, i.e. the
1101 number of seconds to add to UTC to obtain the local Standard Time. This
1102 excludes any DST offset that may be in effect.
1103
1104 For example, for the time zone "Europe/Berlin" the standard time offset is
1105 +3600 seconds. During both standard and DST offsetFromUtc() will return
1106 +3600 (UTC+01:00).
1107
1108 This method is only available when feature \c timezone is enabled.
1109
1110 \sa offsetFromUtc(), daylightTimeOffset()
1111*/
1112
1113int QTimeZone::standardTimeOffset(const QDateTime &atDateTime) const
1114{
1115 if (d.isShort()) {
1116 switch (d.s.spec()) {
1117 case Qt::LocalTime:
1118 return systemTimeZone().standardTimeOffset(atDateTime);
1119 case Qt::UTC:
1120 case Qt::OffsetFromUTC:
1121 return d.s.offset;
1122 case Qt::TimeZone:
1123 Q_UNREACHABLE();
1124 break;
1125 }
1126 } else if (isValid()) {
1127 const int offset = d->standardTimeOffset(atDateTime.toMSecsSinceEpoch());
1128 if (offset != QTimeZonePrivate::invalidSeconds())
1129 return offset;
1130 }
1131 return 0;
1132}
1133
1134/*!
1135 Returns the daylight-saving time offset at the given \a atDateTime,
1136 i.e. the number of seconds to add to the standard time offset to obtain the
1137 local daylight-saving time.
1138
1139 For example, for the time zone "Europe/Berlin" the DST offset is +3600
1140 seconds. During standard time daylightTimeOffset() will return 0, and when
1141 daylight-saving is in effect it will return +3600.
1142
1143 This method is only available when feature \c timezone is enabled.
1144
1145 \sa offsetFromUtc(), standardTimeOffset()
1146*/
1147
1148int QTimeZone::daylightTimeOffset(const QDateTime &atDateTime) const
1149{
1150 if (d.isShort()) {
1151 switch (d.s.spec()) {
1152 case Qt::LocalTime:
1153 return systemTimeZone().daylightTimeOffset(atDateTime);
1154 case Qt::UTC:
1155 case Qt::OffsetFromUTC:
1156 return 0;
1157 case Qt::TimeZone:
1158 Q_UNREACHABLE();
1159 break;
1160 }
1161 } else if (hasDaylightTime()) {
1162 const int offset = d->daylightTimeOffset(atDateTime.toMSecsSinceEpoch());
1163 if (offset != QTimeZonePrivate::invalidSeconds())
1164 return offset;
1165 }
1166 return 0;
1167}
1168
1169/*!
1170 Returns \c true if the time zone has practiced daylight-saving at any time.
1171
1172 This method is only available when feature \c timezone is enabled.
1173
1174 \sa isDaylightTime(), daylightTimeOffset()
1175*/
1176
1177bool QTimeZone::hasDaylightTime() const
1178{
1179 if (d.isShort()) {
1180 switch (d.s.spec()) {
1181 case Qt::LocalTime:
1182 return systemTimeZone().hasDaylightTime();
1183 case Qt::UTC:
1184 case Qt::OffsetFromUTC:
1185 return false;
1186 case Qt::TimeZone:
1187 Q_UNREACHABLE();
1188 break;
1189 }
1190 } else if (isValid()) {
1191 return d->hasDaylightTime();
1192 }
1193 return false;
1194}
1195
1196/*!
1197 Returns \c true if daylight-saving was in effect at the given \a atDateTime.
1198
1199 This method is only available when feature \c timezone is enabled.
1200
1201 \sa hasDaylightTime(), daylightTimeOffset()
1202*/
1203
1204bool QTimeZone::isDaylightTime(const QDateTime &atDateTime) const
1205{
1206 if (d.isShort()) {
1207 switch (d.s.spec()) {
1208 case Qt::LocalTime:
1209 return systemTimeZone().isDaylightTime(atDateTime);
1210 case Qt::UTC:
1211 case Qt::OffsetFromUTC:
1212 return false;
1213 case Qt::TimeZone:
1214 Q_UNREACHABLE();
1215 break;
1216 }
1217 } else if (hasDaylightTime()) {
1218 return d->isDaylightTime(atDateTime.toMSecsSinceEpoch());
1219 }
1220 return false;
1221}
1222
1223/*!
1224 Returns the effective offset details at the given \a forDateTime.
1225
1226 This is the equivalent of calling abbreviation() and all three offset
1227 functions individually but may be more efficient and may get a different
1228 localization for the abbreviation. If this data is not available for the
1229 given datetime, an invalid OffsetData will be returned with an invalid
1230 QDateTime as its \c atUtc.
1231
1232 This method is only available when feature \c timezone is enabled.
1233
1234 \sa offsetFromUtc(), standardTimeOffset(), daylightTimeOffset(), abbreviation()
1235*/
1236
1237QTimeZone::OffsetData QTimeZone::offsetData(const QDateTime &forDateTime) const
1238{
1239 if (d.isShort()) {
1240 switch (d.s.spec()) {
1241 case Qt::LocalTime:
1242 return systemTimeZone().offsetData(forDateTime);
1243 case Qt::UTC:
1244 case Qt::OffsetFromUTC:
1245 return { abbreviation(forDateTime), forDateTime, int(d.s.offset), int(d.s.offset), 0 };
1246 case Qt::TimeZone:
1247 Q_UNREACHABLE();
1248 break;
1249 }
1250 }
1251 if (isValid())
1252 return QTimeZonePrivate::toOffsetData(d->data(forDateTime.toMSecsSinceEpoch()));
1253
1254 return QTimeZonePrivate::invalidOffsetData();
1255}
1256
1257/*!
1258 Returns \c true if the system backend supports obtaining transitions.
1259
1260 Transitions are changes in the time-zone: these happen when DST turns on or
1261 off and when authorities alter the offsets for the time-zone.
1262
1263 This method is only available when feature \c timezone is enabled.
1264
1265 \sa nextTransition(), previousTransition(), transitions()
1266*/
1267
1268bool QTimeZone::hasTransitions() const
1269{
1270 if (d.isShort()) {
1271 switch (d.s.spec()) {
1272 case Qt::LocalTime:
1273 return systemTimeZone().hasTransitions();
1274 case Qt::UTC:
1275 case Qt::OffsetFromUTC:
1276 return false;
1277 case Qt::TimeZone:
1278 Q_UNREACHABLE();
1279 break;
1280 }
1281 } else if (isValid()) {
1282 return d->hasTransitions();
1283 }
1284 return false;
1285}
1286
1287/*!
1288 Returns the first time zone Transition after the given \a afterDateTime.
1289 This is most useful when you have a Transition time and wish to find the
1290 Transition after it.
1291
1292 If there is no transition after the given \a afterDateTime then an invalid
1293 OffsetData will be returned with an invalid QDateTime as its \c atUtc.
1294
1295 The given \a afterDateTime is exclusive.
1296
1297 This method is only available when feature \c timezone is enabled.
1298
1299 \sa hasTransitions(), previousTransition(), transitions()
1300*/
1301
1302QTimeZone::OffsetData QTimeZone::nextTransition(const QDateTime &afterDateTime) const
1303{
1304 if (d.isShort()) {
1305 switch (d.s.spec()) {
1306 case Qt::LocalTime:
1307 return systemTimeZone().nextTransition(afterDateTime);
1308 case Qt::UTC:
1309 case Qt::OffsetFromUTC:
1310 break;
1311 case Qt::TimeZone:
1312 Q_UNREACHABLE();
1313 break;
1314 }
1315 } else if (hasTransitions()) {
1316 return QTimeZonePrivate::toOffsetData(d->nextTransition(afterDateTime.toMSecsSinceEpoch()));
1317 }
1318
1319 return QTimeZonePrivate::invalidOffsetData();
1320}
1321
1322/*!
1323 Returns the first time zone Transition before the given \a beforeDateTime.
1324 This is most useful when you have a Transition time and wish to find the
1325 Transition before it.
1326
1327 If there is no transition before the given \a beforeDateTime then an invalid
1328 OffsetData will be returned with an invalid QDateTime as its \c atUtc.
1329
1330 The given \a beforeDateTime is exclusive.
1331
1332 This method is only available when feature \c timezone is enabled.
1333
1334 \sa hasTransitions(), nextTransition(), transitions()
1335*/
1336
1337QTimeZone::OffsetData QTimeZone::previousTransition(const QDateTime &beforeDateTime) const
1338{
1339 if (d.isShort()) {
1340 switch (d.s.spec()) {
1341 case Qt::LocalTime:
1342 return systemTimeZone().previousTransition(beforeDateTime);
1343 case Qt::UTC:
1344 case Qt::OffsetFromUTC:
1345 break;
1346 case Qt::TimeZone:
1347 Q_UNREACHABLE();
1348 break;
1349 }
1350 } else if (hasTransitions()) {
1351 return QTimeZonePrivate::toOffsetData(
1352 d->previousTransition(beforeDateTime.toMSecsSinceEpoch()));
1353 }
1354
1355 return QTimeZonePrivate::invalidOffsetData();
1356}
1357
1358/*!
1359 Returns a list of all time zone transitions between the given datetimes.
1360
1361 The given \a fromDateTime and \a toDateTime are inclusive. The \c atUtc
1362 member of each entry describes the moment of the transition, at which the
1363 offsets and abbreviation given by other members take effect.
1364
1365 This method is only available when feature \c timezone is enabled.
1366
1367 \sa hasTransitions(), nextTransition(), previousTransition()
1368*/
1369
1370QTimeZone::OffsetDataList QTimeZone::transitions(const QDateTime &fromDateTime,
1371 const QDateTime &toDateTime) const
1372{
1373 OffsetDataList list;
1374 if (d.isShort()) {
1375 switch (d.s.spec()) {
1376 case Qt::LocalTime:
1377 return systemTimeZone().transitions(fromDateTime, toDateTime);
1378 case Qt::UTC:
1379 case Qt::OffsetFromUTC:
1380 break;
1381 case Qt::TimeZone:
1382 Q_UNREACHABLE();
1383 break;
1384 }
1385 } else if (hasTransitions()) {
1386 const QTimeZonePrivate::DataList plist = d->transitions(fromDateTime.toMSecsSinceEpoch(),
1387 toDateTime.toMSecsSinceEpoch());
1388 list.reserve(plist.size());
1389 for (const QTimeZonePrivate::Data &pdata : plist)
1390 list.append(QTimeZonePrivate::toOffsetData(pdata));
1391 }
1392 return list;
1393}
1394
1395// Static methods
1396
1397/*!
1398 Returns the current system time zone IANA ID.
1399
1400 Equivalent to calling systemTimeZone().id(), but may bypass some computation
1401 to obtain it. Constructing a QTimeZone from the returned byte array will
1402 produce the same result as systemTimeZone().
1403
1404 If the backend is unable to determine the correct system zone, the result is
1405 empty. In this case, systemTimeZone().isValid() is false and a warning is
1406 output if either this method of systemTimeZone() is called.
1407
1408 If the backend is able to determine the correct system zone but not its
1409 name, an empty byte array is returned. For example, on Windows, the system
1410 native ID is converted to an IANA ID - if the system ID isn't known to the
1411 internal translation code, the result shall be empty. In this case,
1412 systemTimeZone().isValid() shall be true.
1413
1414 This method is only available when feature \c timezone is enabled.
1415
1416 \note Prior to Qt 6.7, when the result could not be determined, the
1417 misleading result "UTC" was returned.
1418
1419 \sa systemTimeZone()
1420*/
1421
1422QByteArray QTimeZone::systemTimeZoneId()
1423{
1424 QByteArray sys = global_tz->backend->systemTimeZoneId();
1425 if (!sys.isEmpty())
1426 return sys;
1427 // The system zone, despite the empty ID, may know its real ID anyway:
1428 return global_tz->backend->id();
1429}
1430
1431/*!
1432 \since 5.5
1433
1434 Returns a QTimeZone object that describes local system time.
1435
1436 This method is only available when feature \c timezone is enabled. The
1437 returned instance is usually equivalent to the lightweight time
1438 representation \c {QTimeZone(QTimeZone::LocalTime)}, albeit implemented as a
1439 time zone.
1440
1441 The returned object will not change to reflect any subsequent change to the
1442 system time zone. It represents the local time that was in effect when
1443 asBackendZone() was called. On misconfigured systems, such as those that
1444 lack the timezone data relied on by the backend for which Qt was compiled,
1445 it may be invalid. In such a case, a warning is output.
1446
1447 \sa utc(), Initialization, asBackendZone(), systemTimeZoneId()
1448*/
1449QTimeZone QTimeZone::systemTimeZone()
1450{
1451 // Short-cut constructor's handling of empty ID:
1452 const QByteArray sysId = global_tz->backend->systemTimeZoneId();
1453 const auto sys = sysId.isEmpty() ? QTimeZone(global_tz->backend) : QTimeZone(sysId);
1454 if (!sys.isValid()) {
1455 static bool neverWarned = true;
1456 if (neverWarned) {
1457 // Racey but, at worst, merely repeats the warning.
1458 neverWarned = false;
1459 qWarning("Unable to determine system time zone: "
1460 "please check your system configuration.");
1461 }
1462 }
1463 return sys;
1464}
1465
1466/*!
1467 \fn QTimeZone QTimeZone::utc()
1468 \since 5.5
1469 Returns a QTimeZone object that describes UTC as a time zone.
1470
1471 This method is only available when feature \c timezone is enabled. It is
1472 equivalent to passing 0 to QTimeZone(int offsetSeconds) and to the
1473 lightweight time representation QTimeZone(QTimeZone::UTC), albeit
1474 implemented as a time zone, unlike the latter.
1475
1476 \sa systemTimeZone(), Initialization, asBackendZone()
1477*/
1478QTimeZone QTimeZonePrivate::utcQTimeZone()
1479{
1480 return QTimeZone(*new QUtcTimeZonePrivate());
1481}
1482
1483Q_GLOBAL_STATIC(QTimeZone, utcTimeZone, QTimeZonePrivate::utcQTimeZone());
1484
1485QTimeZone QTimeZone::utc()
1486{
1487 if (Q_UNLIKELY(utcTimeZone.isDestroyed()))
1488 return QTimeZonePrivate::utcQTimeZone(); // create a new, unshared one
1489 return *utcTimeZone; // take a shallow copy
1490}
1491
1492/*!
1493 Returns \c true if a given time zone \a ianaId is available on this system.
1494
1495 This may be true for some texts that are not in fact IANA IDs, notably
1496 UTC-offset IDs, and known aliases for supported IANA IDs that are not listed
1497 in \l availableTimeZoneIds().
1498
1499 This method is only available when feature \c timezone is enabled.
1500
1501 \sa availableTimeZoneIds(), hasAlternativeName()
1502*/
1503
1504bool QTimeZone::isTimeZoneIdAvailable(QByteArrayView ianaId)
1505{
1506#if defined(Q_OS_UNIX) && !(QT_CONFIG(timezone_tzdb) || defined(Q_OS_DARWIN)
1507 || defined(Q_OS_ANDROID) || defined(Q_OS_VXWORKS))
1508 // Keep #if-ery consistent with selection of QTzTimeZonePrivate in
1509 // newBackendTimeZone(). Skip the pre-check, as the TZ backend accepts POSIX
1510 // zone IDs, which need not be valid IANA IDs. See also QTBUG-112006.
1511#else
1512 // isValidId is not strictly required, but faster to weed out invalid
1513 // IDs as availableTimeZoneIds() may be slow
1514 if (!QTimeZonePrivate::isValidId(ianaId))
1515 return false;
1516#endif
1517 if (QUtcTimeZonePrivate().isTimeZoneIdAvailable(ianaId)
1518 || QUtcTimeZonePrivate::offsetFromUtcString(ianaId) != QTimeZonePrivate::invalidSeconds()
1519 || global_tz->backend->isTimeZoneIdAvailable(ianaId)) {
1520 return true;
1521 }
1522 if (const auto name = QTimeZonePrivate::aliasToIana(ianaId); !name.isEmpty()) {
1523 return QUtcTimeZonePrivate().isTimeZoneIdAvailable(name)
1524 || global_tz->backend->isTimeZoneIdAvailable(name);
1525 }
1526
1527 QByteArrayView known = global_tz->backend->availableAlias(ianaId);
1528 return !known.isEmpty();
1529}
1530
1531[[maybe_unused]] static bool isUniqueSorted(const QList<QByteArray> &seq)
1532{
1533 // Since [..., b, a, ...] isn't unique-sorted if a <= b, at least the
1534 // suggested implementations of is_sorted() and is_sorted_until() imply a
1535 // non-unique sorted list will fail is_sorted() with <= comparison.
1536 return std::is_sorted(seq.begin(), seq.end(), std::less_equal<QByteArray>());
1537}
1538
1539static QList<QByteArray> set_union(const QList<QByteArray> &l1, const QList<QByteArray> &l2)
1540{
1541 Q_ASSERT(isUniqueSorted(l1));
1542 Q_ASSERT(isUniqueSorted(l2));
1543 QList<QByteArray> result;
1544 result.reserve(l1.size() + l2.size());
1545 std::set_union(l1.begin(), l1.end(),
1546 l2.begin(), l2.end(),
1547 std::back_inserter(result));
1548 return result;
1549}
1550
1551/*!
1552 Returns a list of available time zone IDs on this system.
1553
1554 This includes an IANA ID for each zone supported by the system timezone
1555 information source, plus some aliases of these and a limited set of
1556 commonly-used UTC-offset IDs.
1557
1558 The QTimeZone constructor will also accept some UTC-offset IDs that are not
1559 in the list returned - it would be impractical to list all possible
1560 UTC-offset IDs. It also accepts known aliases for supported IANA IDs, some
1561 of which may not appear in this list. Such IDs are also accepted by
1562 isTimeZoneIdAvailable().
1563
1564 Where the Unicode Consortium's Common Locale Data Repository (CLDR) regards
1565 a supported IANA ID as an alias for its stable name for the zone, this
1566 stable name for the zone is also included in the list (even though it may be
1567 out of date), both for stability and as cross-platform common ground where
1568 different system timezone information sources use different aliases for the
1569 same zone.
1570
1571 This method is only available when feature \c timezone is enabled.
1572
1573 \sa isTimeZoneIdAvailable(), hasAlternativeName()
1574*/
1575
1576QList<QByteArray> QTimeZone::availableTimeZoneIds()
1577{
1578 // Backends MUST implement availableTimeZoneIds().
1579 // The return from each backend MUST be sorted and unique.
1580 return set_union(QUtcTimeZonePrivate().availableTimeZoneIds(),
1581 global_tz->backend->availableTimeZoneIds());
1582}
1583
1584/*!
1585 Returns a list of all available IANA time zone IDs for a given \a territory.
1586
1587 As a special case, a \a territory of \l {QLocale::} {AnyTerritory} selects
1588 those time zones that have a non-territorial association, such as UTC, while
1589 \l {QLocale::}{World} selects those time-zones for which there is a global
1590 default IANA ID. If you require a list of all time zone IDs for all
1591 territories then use the standard availableTimeZoneIds() method.
1592
1593 This method is only available when feature \c timezone is enabled.
1594
1595 \sa isTimeZoneIdAvailable(), territory()
1596*/
1597
1598QList<QByteArray> QTimeZone::availableTimeZoneIds(QLocale::Territory territory)
1599{
1600 return set_union(QUtcTimeZonePrivate().availableTimeZoneIds(territory),
1601 global_tz->backend->availableTimeZoneIds(territory));
1602}
1603
1604/*!
1605 Returns a list of all available IANA time zone IDs with a given standard
1606 time offset of \a offsetSeconds.
1607
1608 Where the given offset is supported, \c{QTimeZone(offsetSeconds).id()} is
1609 included in the list, even if it is not an IANA ID. This only arises when
1610 there is no IANA UTC-offset ID with the given offset.
1611
1612 This method is only available when feature \c timezone is enabled.
1613
1614 \sa isTimeZoneIdAvailable(), QTimeZone(int)
1615*/
1616
1617QList<QByteArray> QTimeZone::availableTimeZoneIds(int offsetSeconds)
1618{
1619 return set_union(QUtcTimeZonePrivate().availableTimeZoneIds(offsetSeconds),
1620 global_tz->backend->availableTimeZoneIds(offsetSeconds));
1621}
1622
1623/*!
1624 Returns the Windows ID equivalent to the given \a ianaId.
1625
1626 This method is only available when feature \c timezone is enabled.
1627
1628 \sa windowsIdToDefaultIanaId(), windowsIdToIanaIds()
1629*/
1630
1631QByteArray QTimeZone::ianaIdToWindowsId(const QByteArray &ianaId)
1632{
1633 return QTimeZonePrivate::ianaIdToWindowsId(ianaId).toByteArray();
1634}
1635
1636/*!
1637 Returns the default IANA ID for a given \a windowsId.
1638
1639 Because a Windows ID can cover several IANA IDs in several different
1640 territories, this function returns the most frequently used IANA ID with no
1641 regard for the territory and should thus be used with care. It is usually
1642 best to request the default for a specific territory.
1643
1644 This method is only available when feature \c timezone is enabled.
1645
1646 \sa ianaIdToWindowsId(), windowsIdToIanaIds()
1647*/
1648
1649QByteArray QTimeZone::windowsIdToDefaultIanaId(const QByteArray &windowsId)
1650{
1651 return QTimeZonePrivate::windowsIdToDefaultIanaId(windowsId).toByteArray();
1652}
1653
1654/*!
1655 Returns the default IANA ID for a given \a windowsId and \a territory.
1656
1657 Because a Windows ID can cover several IANA IDs within a given territory,
1658 the most frequently used IANA ID in that territory is returned.
1659
1660 As a special case, \l {QLocale::} {AnyTerritory} returns the default of
1661 those IANA IDs that have a non-territorial association, while \l {QLocale::}
1662 {World} returns the default for the given \a windowsId in territories that
1663 have no specific association with it.
1664
1665 If the return is empty, there is no IANA ID specific to the given \a
1666 territory for this \a windowsId. It is reasonable, in this case, to fall
1667 back to \c{windowsIdToDefaultIanaId(windowsId)}.
1668
1669 This method is only available when feature \c timezone is enabled.
1670
1671 \sa ianaIdToWindowsId(), windowsIdToIanaIds(), territory()
1672*/
1673
1674QByteArray QTimeZone::windowsIdToDefaultIanaId(const QByteArray &windowsId,
1675 QLocale::Territory territory)
1676{
1677 return QTimeZonePrivate::windowsIdToDefaultIanaId(windowsId, territory).toByteArray();
1678}
1679
1680/*!
1681 Returns all the IANA IDs for a given \a windowsId.
1682
1683 The returned list is sorted alphabetically.
1684
1685 This method is only available when feature \c timezone is enabled.
1686
1687 \sa ianaIdToWindowsId(), windowsIdToDefaultIanaId()
1688*/
1689
1690QList<QByteArray> QTimeZone::windowsIdToIanaIds(const QByteArray &windowsId)
1691{
1692 return QTimeZonePrivate::windowsIdToIanaIds(windowsId);
1693}
1694
1695/*!
1696 Returns all the IANA IDs for a given \a windowsId and \a territory.
1697
1698 As a special case, \l{QLocale::} {AnyTerritory} selects those IANA IDs that
1699 have a non-territorial association, while \l {QLocale::} {World} selects the
1700 default for the given \a windowsId in territories that have no specific
1701 association with it.
1702
1703 The returned list is in order of frequency of usage, i.e. larger zones
1704 within a territory are listed first.
1705
1706 This method is only available when feature \c timezone is enabled.
1707
1708 \sa ianaIdToWindowsId(), windowsIdToDefaultIanaId(), territory()
1709*/
1710
1711QList<QByteArray> QTimeZone::windowsIdToIanaIds(const QByteArray &windowsId,
1712 QLocale::Territory territory)
1713{
1714 return QTimeZonePrivate::windowsIdToIanaIds(windowsId, territory);
1715}
1716
1717/*!
1718 \fn QTimeZone QTimeZone::fromStdTimeZonePtr(const std::chrono::time_zone *timeZone)
1719 \since 6.4
1720
1721 Returns a QTimeZone object representing the same time zone as \a timeZone.
1722 The IANA ID of \a timeZone must be one of the available system IDs,
1723 otherwise an invalid time zone will be returned.
1724
1725 This method is only available when feature \c timezone is enabled.
1726*/
1727#endif // feature timezone
1728
1729template <typename Stream, typename Wrap>
1730void QTimeZone::Data::serialize(Stream &out, const Wrap &wrap) const
1731{
1732 if (isShort()) {
1733 switch (s.spec()) {
1734 case Qt::UTC:
1735 out << wrap("QTimeZone::UTC");
1736 break;
1737 case Qt::LocalTime:
1738 out << wrap("QTimeZone::LocalTime");
1739 break;
1740 case Qt::OffsetFromUTC:
1741 out << wrap("AheadOfUtcBy") << int(s.offset);
1742 break;
1743 case Qt::TimeZone:
1744 Q_UNREACHABLE();
1745 break;
1746 }
1747 return;
1748 }
1749#if QT_CONFIG(timezone)
1750 if constexpr (std::is_same<Stream, QDataStream>::value) {
1751 if (d)
1752 d->serialize(out);
1753 } else {
1754 // QDebug, traditionally gets a QString, hence quotes round the (possibly empty) ID:
1755 out << QString::fromUtf8(d ? QByteArrayView(d->id()) : QByteArrayView());
1756 }
1757#endif
1758}
1759
1760#ifndef QT_NO_DATASTREAM
1761// Invalid, as an IANA ID: too long, starts with - and has other invalid characters in it
1762static inline QString invalidId() { return QStringLiteral("-No Time Zone Specified!"); }
1763
1764QDataStream &operator<<(QDataStream &ds, const QTimeZone &tz)
1765{
1766 const auto toQString = [](const char *text) {
1767 return QString(QLatin1StringView(text));
1768 };
1769 if (tz.isValid())
1770 tz.d.serialize(ds, toQString);
1771 else
1772 ds << invalidId();
1773 return ds;
1774}
1775
1776QDataStream &operator>>(QDataStream &ds, QTimeZone &tz)
1777{
1778 QString ianaId;
1779 ds >> ianaId;
1780 // That may be various things other than actual IANA IDs:
1781 if (ianaId == invalidId()) {
1782 tz = QTimeZone();
1783 } else if (ianaId == "OffsetFromUtc"_L1) {
1784 int utcOffset;
1785 QString name;
1786 QString abbreviation;
1787 int territory;
1788 QString comment;
1789 ds >> ianaId >> utcOffset >> name >> abbreviation >> territory >> comment;
1790#if QT_CONFIG(timezone)
1791 // Try creating as a system timezone, which succeeds (producing a valid
1792 // zone) iff ianaId is valid; use this if it is a plain offset from UTC
1793 // zone, with the right offset, ignoring the other data:
1794 tz = QTimeZone(ianaId.toUtf8());
1795 if (!tz.isValid() || tz.hasDaylightTime()
1796 || tz.offsetFromUtc(QDateTime::fromMSecsSinceEpoch(0, QTimeZone::UTC)) != utcOffset) {
1797 // Construct a custom timezone using the saved values:
1798 tz = QTimeZone(ianaId.toUtf8(), utcOffset, name, abbreviation,
1799 QLocale::Territory(territory), comment);
1800 }
1801#else
1802 tz = QTimeZone::fromSecondsAheadOfUtc(utcOffset);
1803#endif
1804 } else if (ianaId == "AheadOfUtcBy"_L1) {
1805 int utcOffset;
1806 ds >> utcOffset;
1807 tz = QTimeZone::fromSecondsAheadOfUtc(utcOffset);
1808 } else if (ianaId == "QTimeZone::UTC"_L1) {
1809 tz = QTimeZone(QTimeZone::UTC);
1810 } else if (ianaId == "QTimeZone::LocalTime"_L1) {
1811 tz = QTimeZone(QTimeZone::LocalTime);
1812#if QT_CONFIG(timezone)
1813 } else {
1814 tz = QTimeZone(ianaId.toUtf8());
1815#endif
1816 }
1817 return ds;
1818}
1819#endif // QT_NO_DATASTREAM
1820
1821#ifndef QT_NO_DEBUG_STREAM
1822QDebug operator<<(QDebug dbg, const QTimeZone &tz)
1823{
1824 QDebugStateSaver saver(dbg);
1825 const auto asIs = [](const char *text) { return text; };
1826 // TODO Include backend and data version details?
1827 dbg.nospace() << "QTimeZone(";
1828 tz.d.serialize(dbg, asIs);
1829 dbg.nospace() << ')';
1830 return dbg;
1831}
1832#endif
1833
1834QT_END_NAMESPACE
QDebug operator<<(QDebug dbg, const QFileInfo &fi)
bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)
static QString invalidId()
QDataStream & operator<<(QDataStream &stream, const QImage &image)
[0]
Definition qimage.cpp:4010
QDataStream & operator>>(QDataStream &stream, QImage &image)
Definition qimage.cpp:4036