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