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/*!
530 Creates a custom time zone instance at fixed offset from UTC.
531
532 The returned time zone has an ID of \a zoneId and an offset from UTC of \a
533 offsetSeconds. The \a name will be the name used by displayName() for the
534 LongName, the \a abbreviation will be used by displayName() for the
535 ShortName and by abbreviation(), and the optional \a territory will be used
536 by territory(). The \a comment is an optional note that may be displayed in
537 a GUI to assist users in selecting a time zone.
538
539 The \a offsetSeconds from UTC must be in the range -16 hours to +16 hours.
540 The \a zoneId \e{must not} be an ID for which isTimeZoneIdAvailable() is
541 true, unless it is a UTC-offset name that doesn't appear in
542 availableTimeZoneIds().
543
544 If the custom time zone does not have a specific territory then set it to the
545 default value of QLocale::AnyTerritory.
546
547 This constructor is only available when feature \c timezone is enabled.
548
549 \sa id(), offsetFromUtc(), displayName(), abbreviation(), territory(), comment(),
550 MinUtcOffsetSecs, MaxUtcOffsetSecs
551*/
552
553QTimeZone::QTimeZone(const QByteArray &zoneId, int offsetSeconds, const QString &name,
554 const QString &abbreviation, QLocale::Territory territory, const QString &comment)
555 : d(QUtcTimeZonePrivate().isTimeZoneIdAvailable(zoneId)
556 || global_tz->backend->isTimeZoneIdAvailable(zoneId)
557 ? nullptr // Don't let client code hijack a real zone name.
558 : new QUtcTimeZonePrivate(zoneId, offsetSeconds, name, abbreviation, territory, comment))
559{
560}
561
562/*!
563 \internal
564
565 Private. Create time zone with given private backend
566
567 This constructor is only available when feature \c timezone is enabled.
568*/
569
570QTimeZone::QTimeZone(QTimeZonePrivate &dd)
571 : d(&dd)
572{
573}
574
575/*!
576 \since 6.5
577 Converts this QTimeZone to one whose timeSpec() is Qt::TimeZone.
578
579 In all cases, the result's \l timeSpec() is Qt::TimeZone. When this
580 QTimeZone's timeSpec() is Qt::TimeZone, this QTimeZone itself is returned.
581 If timeSpec() is Qt::LocalTime then systemTimeZone() is returned.
582
583 If timeSpec() is Qt::UTC, QTimeZone::utc() is returned. If it is
584 Qt::OffsetFromUTC then QTimeZone(int) is passed its offset and the result is
585 returned.
586
587 When using a lightweight time representation - local time, UTC time or time
588 at a fixed offset from UTC - using methods only supported when feature \c
589 timezone is enabled may be more expensive than using a corresponding time
590 zone. This method maps a lightweight time representation to a corresponding
591 time zone - that is, an instance based on system-supplied or standard data.
592
593 This method is only available when feature \c timezone is enabled.
594
595 \sa QTimeZone(QTimeZone::Initialization), fromSecondsAheadOfUtc()
596*/
597
598QTimeZone QTimeZone::asBackendZone() const
599{
600 switch (timeSpec()) {
601 case Qt::TimeZone:
602 return *this;
603 case Qt::LocalTime:
604 return systemTimeZone();
605 case Qt::UTC:
606 return utc();
607 case Qt::OffsetFromUTC:
608 return QTimeZone(*new QUtcTimeZonePrivate(int(d.s.offset)));
609 }
610 return QTimeZone();
611}
612#endif // timezone backends
613
614/*!
615 \since 6.5
616 \enum QTimeZone::Initialization
617
618 The type of the simplest lightweight time representations.
619
620 This enumeration identifies a type of lightweight time representation to
621 pass to a QTimeZone constructor, where no further data are required. They
622 correspond to the like-named members of Qt::TimeSpec.
623
624 \value LocalTime This time representation corresponds to the one implicitly
625 used by system functions using \c time_t and \c {struct tm}
626 value to map between local time and UTC time.
627
628 \value UTC This time representation, Coordinated Universal Time, is the base
629 representation to which civil time is referred in all supported
630 time representations. It is defined by the International
631 Telecommunication Union.
632*/
633
634/*!
635 \since 6.5
636 \fn QTimeZone::QTimeZone(Initialization spec) noexcept
637
638 Creates a lightweight instance describing UTC or local time.
639
640 \sa fromSecondsAheadOfUtc(), asBackendZone(), utc(), systemTimeZone()
641*/
642
643/*!
644 \since 6.5
645 \fn QTimeZone::fromSecondsAheadOfUtc(int offset)
646 \fn QTimeZone::fromDurationAheadOfUtc(std::chrono::seconds offset)
647
648 Returns a time representation at a fixed \a offset, in seconds, ahead of
649 UTC.
650
651 The \a offset from UTC must be in the range -16 hours to +16 hours otherwise
652 an invalid time zone will be returned. The returned QTimeZone is a
653 lightweight time representation, not a time zone (backed by system-supplied
654 or standard data).
655
656 If the offset is 0, the \l timeSpec() of the returned instance will be
657 Qt::UTC. Otherwise, if \a offset is valid, timeSpec() is
658 Qt::OffsetFromUTC. An invalid time zone, when returned, has Qt::TimeZone as
659 its timeSpec().
660
661 \sa QTimeZone(int), asBackendZone(), fixedSecondsAheadOfUtc(),
662 MinUtcOffsetSecs, MaxUtcOffsetSecs
663*/
664
665/*!
666 \since 6.5
667 \fn Qt::TimeSpec QTimeZone::timeSpec() const noexcept
668
669 Returns a Qt::TimeSpec identifying the type of time representation.
670
671 If the result is Qt::TimeZone, this time description is a time zone (backed
672 by system-supplied or standard data); otherwise, it is a lightweight time
673 representation. If the result is Qt::LocalTime it describes local time: see
674 Qt::TimeSpec for details.
675
676 \sa fixedSecondsAheadOfUtc(), asBackendZone()
677*/
678
679/*!
680 \since 6.5
681 \fn int QTimeZone::fixedSecondsAheadOfUtc() const noexcept
682
683 For a lightweight time representation whose \l timeSpec() is Qt::OffsetFromUTC,
684 this returns the fixed offset from UTC that it describes. For any other time
685 representation it returns 0, even if that time representation does have a
686 constant offset from UTC.
687*/
688
689/*!
690 \since 6.5
691 \fn QTimeZone::isUtcOrFixedOffset(Qt::TimeSpec spec) noexcept
692
693 Returns \c true if \a spec is Qt::UTC or Qt::OffsetFromUTC.
694*/
695
696/*!
697 \since 6.5
698 \fn QTimeZone::isUtcOrFixedOffset() const noexcept
699
700 Returns \c true if \l timeSpec() is Qt::UTC or Qt::OffsetFromUTC.
701
702 When it is true, the time description does not change over time, such as
703 having seasonal daylight-saving changes, as may happen for local time or a
704 time zone. Knowing this may save the calling code to need for various other
705 checks.
706*/
707
708/*!
709 Copy constructor: copy \a other to this.
710*/
711
712QTimeZone::QTimeZone(const QTimeZone &other) noexcept
713 : d(other.d)
714{
715}
716
717/*!
718 \fn QTimeZone::QTimeZone(QTimeZone &&other) noexcept
719
720 Move constructor of this from \a other.
721*/
722
723/*!
724 Destroys the time zone.
725*/
726
727QTimeZone::~QTimeZone()
728{
729}
730
731/*!
732 \fn QTimeZone::swap(QTimeZone &other) noexcept
733 \memberswap{time zone instance}
734*/
735
736/*!
737 Assignment operator, assign \a other to this.
738*/
739
740QTimeZone &QTimeZone::operator=(const QTimeZone &other)
741{
742 d = other.d;
743 return *this;
744}
745
746/*!
747 \fn QTimeZone &QTimeZone::operator=(QTimeZone &&other)
748
749 Move-assigns \a other to this QTimeZone instance, transferring the ownership
750 of its data to this instance.
751*/
752
753/*!
754 \fn bool QTimeZone::operator==(const QTimeZone &lhs, const QTimeZone &rhs)
755
756 Returns \c true if \a lhs time zone is equal to the \a rhs time zone.
757
758 Two representations are different if they are internally described
759 differently, even if they agree in their representation of all moments of
760 time. In particular, a lightweight time representation may coincide with a
761 time zone but the two will not be equal.
762*/
763
764/*!
765 \fn bool QTimeZone::operator!=(const QTimeZone &lhs, const QTimeZone &rhs)
766
767 Returns \c true if \a lhs time zone is not equal to the \a rhs time zone.
768
769 Two representations are different if they are internally described
770 differently, even if they agree in their representation of all moments of
771 time. In particular, a lightweight time representation may coincide with a
772 time zone but the two will not be equal.
773*/
774
775bool comparesEqual(const QTimeZone &lhs, const QTimeZone &rhs) noexcept
776{
777 if (lhs.d.isShort())
778 return rhs.d.isShort() && lhs.d.s == rhs.d.s;
779
780 if (!rhs.d.isShort()) {
781 if (lhs.d.d == rhs.d.d)
782 return true;
783#if QT_CONFIG(timezone)
784 return lhs.d.d && rhs.d.d && *lhs.d.d == *rhs.d.d;
785#endif
786 }
787
788 return false;
789}
790
791/*!
792 Returns \c true if this time zone is valid.
793*/
794
795bool QTimeZone::isValid() const
796{
797#if QT_CONFIG(timezone)
798 if (!d.isShort())
799 return d.d && d->isValid();
800#endif
801 return d.isShort();
802}
803
804#if QT_CONFIG(timezone)
805/*!
806 Returns the IANA ID for the time zone.
807
808 IANA IDs are used on all platforms. On Windows these are translated from
809 the Windows ID into the best match IANA ID for the time zone and territory.
810
811 If this timezone instance was not constructed from an IANA ID, its ID is
812 determined by how it was constructed. In most cases, the ID passed when
813 constructing the instance is used. (The constructor for a custom zone uses
814 the ID it is passed, which must not be an IANA ID.) There are two
815 exceptions.
816 \list
817 \li Instances constructed by passing only a UTC offset in seconds have no ID
818 passed when constructing.
819 \li The constructor taking only an IANA ID will also accept some UTC-offset
820 IDs that are not in fact IANA IDs: its handling of these is equivalent
821 to passing the corresponding offset in seconds, as for the first
822 exception.
823 \endlist
824
825 In the two exceptional cases, if there is an IANA UTC-offset zone with the
826 specified offset, the instance constructed uses that IANA zone's ID, even
827 though this may differ from the (non-IANA) UTC-offset ID passed to the
828 constructor. Otherwise, the instance uses an ID synthesized from its offset,
829 with the form UTC±hh:mm:ss, omitting any trailing :00 for zero seconds or
830 minutes. Again, this may differ from the UTC-offset ID passed to the
831 constructor.
832
833 This method is only available when feature \c timezone is enabled.
834*/
835
836QByteArray QTimeZone::id() const
837{
838 if (d.isShort()) {
839 switch (d.s.spec()) {
840 case Qt::UTC:
841 return QTimeZonePrivate::utcQByteArray();
842 case Qt::LocalTime:
843 return systemTimeZoneId();
844 case Qt::OffsetFromUTC:
845 return QUtcTimeZonePrivate(d.s.offset).id();
846 case Qt::TimeZone:
847 Q_UNREACHABLE();
848 break;
849 }
850 } else if (d.d) {
851 return d->id();
852 }
853 return QByteArray();
854}
855
856/*!
857 \since 6.8
858 Returns \c true if \a alias is an alternative name for this timezone.
859
860 The IANA (formerly Olson) database has renamed some zones during its
861 history. There are also some zones that only differed prior to 1970 but are
862 now treated as synonymous. Some backends may have data reaching to before
863 1970 and produce distinct zones in the latter case. Others may produce zones
864 indistinguishable except by id(). This method determines whether an ID
865 refers (at least since 1970) to the same zone that this timezone object
866 describes.
867
868 This method is only available when feature \c timezone is enabled.
869
870 \sa isTimeZoneIdAvailable()
871*/
872bool QTimeZone::hasAlternativeName(QByteArrayView alias) const
873{
874 const QByteArray me = id();
875 if (alias == me)
876 return true;
877 QByteArrayView mine = QTimeZonePrivate::aliasToIana(me);
878 // Empty if id() aliases to itself, which we've already checked:
879 if (mine.isEmpty())
880 mine = me; // To simplify the final conditional
881 else if (alias == mine)
882 return true;
883 QByteArrayView its = QTimeZonePrivate::aliasToIana(alias);
884 // Empty if alias aliases to itself, which we've already compared to id()
885 // and, where relevant, mine.
886 return !its.isEmpty() && its == mine;
887}
888
889/*!
890 \since 6.2
891
892 Returns the territory for the time zone.
893
894 A return of \l {QLocale::}{AnyTerritory} means the zone has no known
895 territorial association. In some cases this may be because the zone has no
896 associated territory - for example, UTC - or because the zone is used in
897 several territories - for example, CET. In other cases, the QTimeZone
898 backend may not know which territory the zone is associated with - for
899 example, because it is not the primary zone of the territory in which it is
900 used.
901
902 This method is only available when feature \c timezone is enabled.
903*/
904QLocale::Territory QTimeZone::territory() const
905{
906 if (d.isShort()) {
907 if (d.s.spec() == Qt::LocalTime)
908 return systemTimeZone().territory();
909 } else if (isValid()) {
910 return d->territory();
911 }
912 return QLocale::AnyTerritory;
913}
914
915#if QT_DEPRECATED_SINCE(6, 6)
916/*!
917 \deprecated [6.6] Use territory() instead.
918
919 Returns the territory for the time zone.
920
921 This method is only available when feature \c timezone is enabled.
922*/
923
924QLocale::Country QTimeZone::country() const
925{
926 return territory();
927}
928#endif
929
930/*!
931 Returns any comment for the time zone.
932
933 A comment may be provided by the host platform to assist users in
934 choosing the correct time zone. Depending on the platform this may not
935 be localized.
936
937 This method is only available when feature \c timezone is enabled.
938*/
939
940QString QTimeZone::comment() const
941{
942 if (d.isShort()) {
943 // TODO: anything ? Or just stick with empty string ?
944 } else if (isValid()) {
945 return d->comment();
946 }
947 return QString();
948}
949
950/*!
951 Returns the localized time zone display name.
952
953 The name returned is the one for the given \a locale, applicable at the
954 given \a atDateTime, and of the form indicated by \a nameType. The display
955 name may change depending on DST or historical events.
956//! [display-name-caveats]
957 If no suitably localized name of the given type is available, another name
958 type may be used, or an empty string may be returned.
959
960 If the \a locale is not provided, then the application default locale will
961 be used. For custom timezones created by client code, the data supplied to
962 the constructor are used, as no localization data will be available for it.
963 If this timezone is invalid, an empty string is returned. This may also
964 arise for the representation of local time if determining the system time
965 zone fails.
966
967 This method is only available when feature \c timezone is enabled.
968//! [display-name-caveats]
969
970 \sa abbreviation()
971*/
972
973QString QTimeZone::displayName(const QDateTime &atDateTime, NameType nameType,
974 const QLocale &locale) const
975{
976 if (d.isShort()) {
977 switch (d.s.spec()) {
978 case Qt::LocalTime:
979 return systemTimeZone().displayName(atDateTime, nameType, locale);
980 case Qt::UTC:
981 case Qt::OffsetFromUTC:
982 return QUtcTimeZonePrivate(d.s.offset).displayName(
983 atDateTime.toMSecsSinceEpoch(), nameType, locale);
984 case Qt::TimeZone:
985 Q_UNREACHABLE();
986 break;
987 }
988 } else if (isValid()) {
989 return d->displayName(atDateTime.toMSecsSinceEpoch(), nameType, locale);
990 }
991
992 return QString();
993}
994
995/*!
996 Returns the localized time zone display name.
997
998 The name returned is the one for the given \a locale, applicable when the
999 given \a timeType is in effect and of the form indicated by \a nameType.
1000 Where the time zone display names have changed over time, the current names
1001 will be used.
1002 \include qtimezone.cpp display-name-caveats
1003
1004 \sa abbreviation()
1005*/
1006
1007QString QTimeZone::displayName(TimeType timeType, NameType nameType,
1008 const QLocale &locale) const
1009{
1010 if (d.isShort()) {
1011 switch (d.s.spec()) {
1012 case Qt::LocalTime:
1013 return systemTimeZone().displayName(timeType, nameType, locale);
1014 case Qt::UTC:
1015 case Qt::OffsetFromUTC:
1016 return QUtcTimeZonePrivate(d.s.offset).displayName(timeType, nameType, locale);
1017 case Qt::TimeZone:
1018 Q_UNREACHABLE();
1019 break;
1020 }
1021 } else if (isValid()) {
1022 return d->displayName(timeType, nameType, locale);
1023 }
1024
1025 return QString();
1026}
1027
1028/*!
1029 Returns the time zone abbreviation at the given \a atDateTime.
1030
1031 The abbreviation may change depending on DST or even historical events.
1032
1033 \note The abbreviation is not guaranteed to be unique to this time zone and
1034 should not be used in place of the ID or display name. The abbreviation may
1035 be localized, depending on the underlying operating system. To get consistent
1036 localization, use \c {displayName(atDateTime, QTimeZone::ShortName, locale)}.
1037
1038 This method is only available when feature \c timezone is enabled.
1039
1040 \sa displayName()
1041*/
1042
1043QString QTimeZone::abbreviation(const QDateTime &atDateTime) const
1044{
1045 if (d.isShort()) {
1046 switch (d.s.spec()) {
1047 case Qt::LocalTime:
1048 return systemTimeZone().abbreviation(atDateTime);
1049 case Qt::UTC:
1050 case Qt::OffsetFromUTC:
1051 return QUtcTimeZonePrivate(d.s.offset).abbreviation(atDateTime.toMSecsSinceEpoch());
1052 case Qt::TimeZone:
1053 Q_UNREACHABLE();
1054 break;
1055 }
1056 } else if (isValid()) {
1057 return d->abbreviation(atDateTime.toMSecsSinceEpoch());
1058 }
1059
1060 return QString();
1061}
1062
1063/*!
1064 Returns the total effective offset at the given \a atDateTime, i.e. the
1065 number of seconds to add to UTC to obtain the local time. This includes
1066 any DST offset that may be in effect, i.e. it is the sum of
1067 standardTimeOffset() and daylightTimeOffset() for the given datetime.
1068
1069 For example, for the time zone "Europe/Berlin" the standard time offset is
1070 +3600 seconds and the DST offset is +3600 seconds. During standard time
1071 offsetFromUtc() will return +3600 (UTC+01:00), and during DST it will
1072 return +7200 (UTC+02:00).
1073
1074 This method is only available when feature \c timezone is enabled.
1075
1076 \sa standardTimeOffset(), daylightTimeOffset()
1077*/
1078
1079int QTimeZone::offsetFromUtc(const QDateTime &atDateTime) const
1080{
1081 if (d.isShort()) {
1082 switch (d.s.spec()) {
1083 case Qt::LocalTime:
1084 return systemTimeZone().offsetFromUtc(atDateTime);
1085 case Qt::UTC:
1086 case Qt::OffsetFromUTC:
1087 return d.s.offset;
1088 case Qt::TimeZone:
1089 Q_UNREACHABLE();
1090 break;
1091 }
1092 } else if (isValid()) {
1093 const int offset = d->offsetFromUtc(atDateTime.toMSecsSinceEpoch());
1094 if (offset != QTimeZonePrivate::invalidSeconds())
1095 return offset;
1096 }
1097 return 0;
1098}
1099
1100/*!
1101 Returns the standard time offset at the given \a atDateTime, i.e. the
1102 number of seconds to add to UTC to obtain the local Standard Time. This
1103 excludes any DST offset that may be in effect.
1104
1105 For example, for the time zone "Europe/Berlin" the standard time offset is
1106 +3600 seconds. During both standard and DST offsetFromUtc() will return
1107 +3600 (UTC+01:00).
1108
1109 This method is only available when feature \c timezone is enabled.
1110
1111 \sa offsetFromUtc(), daylightTimeOffset()
1112*/
1113
1114int QTimeZone::standardTimeOffset(const QDateTime &atDateTime) const
1115{
1116 if (d.isShort()) {
1117 switch (d.s.spec()) {
1118 case Qt::LocalTime:
1119 return systemTimeZone().standardTimeOffset(atDateTime);
1120 case Qt::UTC:
1121 case Qt::OffsetFromUTC:
1122 return d.s.offset;
1123 case Qt::TimeZone:
1124 Q_UNREACHABLE();
1125 break;
1126 }
1127 } else if (isValid()) {
1128 const int offset = d->standardTimeOffset(atDateTime.toMSecsSinceEpoch());
1129 if (offset != QTimeZonePrivate::invalidSeconds())
1130 return offset;
1131 }
1132 return 0;
1133}
1134
1135/*!
1136 Returns the daylight-saving time offset at the given \a atDateTime,
1137 i.e. the number of seconds to add to the standard time offset to obtain the
1138 local daylight-saving time.
1139
1140 For example, for the time zone "Europe/Berlin" the DST offset is +3600
1141 seconds. During standard time daylightTimeOffset() will return 0, and when
1142 daylight-saving is in effect it will return +3600.
1143
1144 This method is only available when feature \c timezone is enabled.
1145
1146 \sa offsetFromUtc(), standardTimeOffset()
1147*/
1148
1149int QTimeZone::daylightTimeOffset(const QDateTime &atDateTime) const
1150{
1151 if (d.isShort()) {
1152 switch (d.s.spec()) {
1153 case Qt::LocalTime:
1154 return systemTimeZone().daylightTimeOffset(atDateTime);
1155 case Qt::UTC:
1156 case Qt::OffsetFromUTC:
1157 return 0;
1158 case Qt::TimeZone:
1159 Q_UNREACHABLE();
1160 break;
1161 }
1162 } else if (hasDaylightTime()) {
1163 const int offset = d->daylightTimeOffset(atDateTime.toMSecsSinceEpoch());
1164 if (offset != QTimeZonePrivate::invalidSeconds())
1165 return offset;
1166 }
1167 return 0;
1168}
1169
1170/*!
1171 Returns \c true if the time zone has practiced daylight-saving at any time.
1172
1173 This method is only available when feature \c timezone is enabled.
1174
1175 \sa isDaylightTime(), daylightTimeOffset()
1176*/
1177
1178bool QTimeZone::hasDaylightTime() const
1179{
1180 if (d.isShort()) {
1181 switch (d.s.spec()) {
1182 case Qt::LocalTime:
1183 return systemTimeZone().hasDaylightTime();
1184 case Qt::UTC:
1185 case Qt::OffsetFromUTC:
1186 return false;
1187 case Qt::TimeZone:
1188 Q_UNREACHABLE();
1189 break;
1190 }
1191 } else if (isValid()) {
1192 return d->hasDaylightTime();
1193 }
1194 return false;
1195}
1196
1197/*!
1198 Returns \c true if daylight-saving was in effect at the given \a atDateTime.
1199
1200 This method is only available when feature \c timezone is enabled.
1201
1202 \sa hasDaylightTime(), daylightTimeOffset()
1203*/
1204
1205bool QTimeZone::isDaylightTime(const QDateTime &atDateTime) const
1206{
1207 if (d.isShort()) {
1208 switch (d.s.spec()) {
1209 case Qt::LocalTime:
1210 return systemTimeZone().isDaylightTime(atDateTime);
1211 case Qt::UTC:
1212 case Qt::OffsetFromUTC:
1213 return false;
1214 case Qt::TimeZone:
1215 Q_UNREACHABLE();
1216 break;
1217 }
1218 } else if (hasDaylightTime()) {
1219 return d->isDaylightTime(atDateTime.toMSecsSinceEpoch());
1220 }
1221 return false;
1222}
1223
1224/*!
1225 Returns the effective offset details at the given \a forDateTime.
1226
1227 This is the equivalent of calling abbreviation() and all three offset
1228 functions individually but may be more efficient and may get a different
1229 localization for the abbreviation. If this data is not available for the
1230 given datetime, an invalid OffsetData will be returned with an invalid
1231 QDateTime as its \c atUtc.
1232
1233 This method is only available when feature \c timezone is enabled.
1234
1235 \sa offsetFromUtc(), standardTimeOffset(), daylightTimeOffset(), abbreviation()
1236*/
1237
1238QTimeZone::OffsetData QTimeZone::offsetData(const QDateTime &forDateTime) const
1239{
1240 if (d.isShort()) {
1241 switch (d.s.spec()) {
1242 case Qt::LocalTime:
1243 return systemTimeZone().offsetData(forDateTime);
1244 case Qt::UTC:
1245 case Qt::OffsetFromUTC:
1246 return { abbreviation(forDateTime), forDateTime, int(d.s.offset), int(d.s.offset), 0 };
1247 case Qt::TimeZone:
1248 Q_UNREACHABLE();
1249 break;
1250 }
1251 }
1252 if (isValid())
1253 return QTimeZonePrivate::toOffsetData(d->data(forDateTime.toMSecsSinceEpoch()));
1254
1255 return QTimeZonePrivate::invalidOffsetData();
1256}
1257
1258/*!
1259 Returns \c true if the system backend supports obtaining transitions.
1260
1261 Transitions are changes in the time-zone: these happen when DST turns on or
1262 off and when authorities alter the offsets for the time-zone.
1263
1264 This method is only available when feature \c timezone is enabled.
1265
1266 \note this is not a property of the timezone described by this object but of
1267 the backend that provides data about the zone, typically from system
1268 libraries. It tells you whether the other transition-related functions have
1269 anything to offer.
1270
1271 \sa nextTransition(), previousTransition(), transitions()
1272*/
1273
1274bool QTimeZone::hasTransitions() const
1275{
1276 if (d.isShort()) {
1277 switch (d.s.spec()) {
1278 case Qt::LocalTime:
1279 return systemTimeZone().hasTransitions();
1280 case Qt::UTC:
1281 case Qt::OffsetFromUTC:
1282 return false;
1283 case Qt::TimeZone:
1284 Q_UNREACHABLE();
1285 break;
1286 }
1287 } else if (isValid()) {
1288 return d->hasTransitions();
1289 }
1290 return false;
1291}
1292
1293/*!
1294 Returns the first time zone Transition after the given \a afterDateTime.
1295 This is most useful when you have a Transition time and wish to find the
1296 Transition after it.
1297
1298 If there is no transition after the given \a afterDateTime then an invalid
1299 OffsetData will be returned with an invalid QDateTime as its \c atUtc.
1300
1301 The given \a afterDateTime is exclusive.
1302
1303 This method is only available when feature \c timezone is enabled.
1304
1305 \sa hasTransitions(), previousTransition(), transitions()
1306*/
1307
1308QTimeZone::OffsetData QTimeZone::nextTransition(const QDateTime &afterDateTime) const
1309{
1310 if (d.isShort()) {
1311 switch (d.s.spec()) {
1312 case Qt::LocalTime:
1313 return systemTimeZone().nextTransition(afterDateTime);
1314 case Qt::UTC:
1315 case Qt::OffsetFromUTC:
1316 break;
1317 case Qt::TimeZone:
1318 Q_UNREACHABLE();
1319 break;
1320 }
1321 } else if (isValid() && hasTransitions()) {
1322 return QTimeZonePrivate::toOffsetData(d->nextTransition(afterDateTime.toMSecsSinceEpoch()));
1323 }
1324
1325 return QTimeZonePrivate::invalidOffsetData();
1326}
1327
1328/*!
1329 Returns the first time zone Transition before the given \a beforeDateTime.
1330 This is most useful when you have a Transition time and wish to find the
1331 Transition before it.
1332
1333 If there is no transition before the given \a beforeDateTime then an invalid
1334 OffsetData will be returned with an invalid QDateTime as its \c atUtc.
1335
1336 The given \a beforeDateTime is exclusive.
1337
1338 This method is only available when feature \c timezone is enabled.
1339
1340 \sa hasTransitions(), nextTransition(), transitions()
1341*/
1342
1343QTimeZone::OffsetData QTimeZone::previousTransition(const QDateTime &beforeDateTime) const
1344{
1345 if (d.isShort()) {
1346 switch (d.s.spec()) {
1347 case Qt::LocalTime:
1348 return systemTimeZone().previousTransition(beforeDateTime);
1349 case Qt::UTC:
1350 case Qt::OffsetFromUTC:
1351 break;
1352 case Qt::TimeZone:
1353 Q_UNREACHABLE();
1354 break;
1355 }
1356 } else if (isValid() && hasTransitions()) {
1357 return QTimeZonePrivate::toOffsetData(
1358 d->previousTransition(beforeDateTime.toMSecsSinceEpoch()));
1359 }
1360
1361 return QTimeZonePrivate::invalidOffsetData();
1362}
1363
1364/*!
1365 Returns a list of all time zone transitions between the given datetimes.
1366
1367 The given \a fromDateTime and \a toDateTime are inclusive. The \c atUtc
1368 member of each entry describes the moment of the transition, at which the
1369 offsets and abbreviation given by other members take effect.
1370
1371 This method is only available when feature \c timezone is enabled.
1372
1373 \sa hasTransitions(), nextTransition(), previousTransition()
1374*/
1375
1376QTimeZone::OffsetDataList QTimeZone::transitions(const QDateTime &fromDateTime,
1377 const QDateTime &toDateTime) const
1378{
1379 OffsetDataList list;
1380 if (d.isShort()) {
1381 switch (d.s.spec()) {
1382 case Qt::LocalTime:
1383 return systemTimeZone().transitions(fromDateTime, toDateTime);
1384 case Qt::UTC:
1385 case Qt::OffsetFromUTC:
1386 break;
1387 case Qt::TimeZone:
1388 Q_UNREACHABLE();
1389 break;
1390 }
1391 } else if (isValid() && hasTransitions()) {
1392 const QTimeZonePrivate::DataList plist = d->transitions(fromDateTime.toMSecsSinceEpoch(),
1393 toDateTime.toMSecsSinceEpoch());
1394 list.reserve(plist.size());
1395 for (const QTimeZonePrivate::Data &pdata : plist)
1396 list.append(QTimeZonePrivate::toOffsetData(pdata));
1397 }
1398 return list;
1399}
1400
1401// Static methods
1402
1403/*!
1404 Returns the current system time zone IANA ID.
1405
1406 Equivalent to calling systemTimeZone().id(), but may bypass some computation
1407 to obtain it. Constructing a QTimeZone from the returned byte array will
1408 produce the same result as systemTimeZone().
1409
1410 If the backend is unable to determine the correct system zone, the result is
1411 empty. In this case, systemTimeZone().isValid() is false and a warning is
1412 output if either this method of systemTimeZone() is called.
1413
1414 If the backend is able to determine the correct system zone but not its
1415 name, an empty byte array is returned. For example, on Windows, the system
1416 native ID is converted to an IANA ID - if the system ID isn't known to the
1417 internal translation code, the result shall be empty. In this case,
1418 systemTimeZone().isValid() shall be true.
1419
1420 This method is only available when feature \c timezone is enabled.
1421
1422 \note Prior to Qt 6.7, when the result could not be determined, the
1423 misleading result "UTC" was returned.
1424
1425 \sa systemTimeZone()
1426*/
1427
1428QByteArray QTimeZone::systemTimeZoneId()
1429{
1430 QByteArray sys = global_tz->backend->systemTimeZoneId();
1431 if (!sys.isEmpty())
1432 return sys;
1433 // The system zone, despite the empty ID, may know its real ID anyway:
1434 return global_tz->backend->id();
1435}
1436
1437/*!
1438 \since 5.5
1439
1440 Returns a QTimeZone object that describes local system time.
1441
1442 This method is only available when feature \c timezone is enabled. The
1443 returned instance is usually equivalent to the lightweight time
1444 representation \c {QTimeZone(QTimeZone::LocalTime)}, albeit implemented as a
1445 time zone.
1446
1447 The returned object will not change to reflect any subsequent change to the
1448 system time zone. It represents the local time that was in effect when
1449 asBackendZone() was called. On misconfigured systems, such as those that
1450 lack the timezone data relied on by the backend for which Qt was compiled,
1451 it may be invalid. In such a case, a warning is output.
1452
1453 \sa utc(), Initialization, asBackendZone(), systemTimeZoneId()
1454*/
1455QTimeZone QTimeZone::systemTimeZone()
1456{
1457 // Short-cut constructor's handling of empty ID:
1458 const QByteArray sysId = global_tz->backend->systemTimeZoneId();
1459 const auto sys = sysId.isEmpty() ? QTimeZone(global_tz->backend) : QTimeZone(sysId);
1460 if (!sys.isValid()) {
1461 static bool neverWarned = true;
1462 if (neverWarned) {
1463 // Racey but, at worst, merely repeats the warning.
1464 neverWarned = false;
1465 qWarning("Unable to determine system time zone: "
1466 "please check your system configuration.");
1467 }
1468 }
1469 return sys;
1470}
1471
1472/*!
1473 \fn QTimeZone QTimeZone::utc()
1474 \since 5.5
1475 Returns a QTimeZone object that describes UTC as a time zone.
1476
1477 This method is only available when feature \c timezone is enabled. It is
1478 equivalent to passing 0 to QTimeZone(int offsetSeconds) and to the
1479 lightweight time representation QTimeZone(QTimeZone::UTC), albeit
1480 implemented as a time zone, unlike the latter.
1481
1482 \sa systemTimeZone(), Initialization, asBackendZone()
1483*/
1484QTimeZone QTimeZonePrivate::utcQTimeZone()
1485{
1486 return QTimeZone(*new QUtcTimeZonePrivate());
1487}
1488
1489Q_GLOBAL_STATIC(QTimeZone, utcTimeZone, QTimeZonePrivate::utcQTimeZone());
1490
1491QTimeZone QTimeZone::utc()
1492{
1493 if (Q_UNLIKELY(utcTimeZone.isDestroyed()))
1494 return QTimeZonePrivate::utcQTimeZone(); // create a new, unshared one
1495 return *utcTimeZone; // take a shallow copy
1496}
1497
1498/*!
1499 Returns \c true if a given time zone \a ianaId is available on this system.
1500
1501 This may be true for some texts that are not in fact IANA IDs, notably
1502 UTC-offset IDs, and known aliases for supported IANA IDs that are not listed
1503 in \l availableTimeZoneIds().
1504
1505 This method is only available when feature \c timezone is enabled.
1506
1507 \sa availableTimeZoneIds(), hasAlternativeName()
1508*/
1509
1510bool QTimeZone::isTimeZoneIdAvailable(QByteArrayView ianaId)
1511{
1512#if defined(Q_OS_UNIX) && !(QT_CONFIG(timezone_tzdb) || defined(Q_OS_DARWIN)
1513 || defined(Q_OS_ANDROID) || defined(Q_OS_VXWORKS))
1514 // Keep #if-ery consistent with selection of QTzTimeZonePrivate in
1515 // newBackendTimeZone(). Skip the pre-check, as the TZ backend accepts POSIX
1516 // zone IDs, which need not be valid IANA IDs. See also QTBUG-112006.
1517#else
1518 // isValidId is not strictly required, but faster to weed out invalid
1519 // IDs as availableTimeZoneIds() may be slow
1520 if (!QTimeZonePrivate::isValidId(ianaId))
1521 return false;
1522#endif
1523 if (QUtcTimeZonePrivate().isTimeZoneIdAvailable(ianaId)
1524 || QUtcTimeZonePrivate::offsetFromUtcString(ianaId) != QTimeZonePrivate::invalidSeconds()
1525 || global_tz->backend->isTimeZoneIdAvailable(ianaId)) {
1526 return true;
1527 }
1528 if (const auto name = QTimeZonePrivate::aliasToIana(ianaId); !name.isEmpty()) {
1529 return QUtcTimeZonePrivate().isTimeZoneIdAvailable(name)
1530 || global_tz->backend->isTimeZoneIdAvailable(name);
1531 }
1532
1533 QByteArrayView known = global_tz->backend->availableAlias(ianaId);
1534 return !known.isEmpty();
1535}
1536
1537[[maybe_unused]] static bool isUniqueSorted(const QList<QByteArray> &seq)
1538{
1539 // Verify every [..., b, a, ...] has b < a, i.e. none has b >= a.
1540 return std::adjacent_find(seq.cbegin(), seq.cend(),
1541 std::greater_equal<QByteArray>()) == seq.cend();
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