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

source code of qtbase/src/corelib/time/qtimezone.cpp