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