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