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