1/****************************************************************************
2**
3** Copyright (C) 2013 John Layt <jlayt@kde.org>
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40
41#include "qtimezone.h"
42#include "qtimezoneprivate_p.h"
43
44#include <QtCore/qdatastream.h>
45#include <QtCore/qdatetime.h>
46
47#include <qdebug.h>
48
49#include <algorithm>
50
51QT_BEGIN_NAMESPACE
52
53// Create default time zone using appropriate backend
54static QTimeZonePrivate *newBackendTimeZone()
55{
56#ifdef QT_NO_SYSTEMLOCALE
57#if QT_CONFIG(icu)
58 return new QIcuTimeZonePrivate();
59#else
60 return new QUtcTimeZonePrivate();
61#endif
62#else
63#if defined Q_OS_MAC
64 return new QMacTimeZonePrivate();
65#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
66 return new QAndroidTimeZonePrivate();
67#elif defined(Q_OS_UNIX) || defined(Q_OS_ANDROID_EMBEDDED)
68 return new QTzTimeZonePrivate();
69#elif QT_CONFIG(icu)
70 return new QIcuTimeZonePrivate();
71#elif defined Q_OS_WIN
72 return new QWinTimeZonePrivate();
73#else
74 return new QUtcTimeZonePrivate();
75#endif // System Locales
76#endif // QT_NO_SYSTEMLOCALE
77}
78
79// Create named time zone using appropriate backend
80static QTimeZonePrivate *newBackendTimeZone(const QByteArray &ianaId)
81{
82 Q_ASSERT(!ianaId.isEmpty());
83#ifdef QT_NO_SYSTEMLOCALE
84#if QT_CONFIG(icu)
85 return new QIcuTimeZonePrivate(ianaId);
86#else
87 return new QUtcTimeZonePrivate(ianaId);
88#endif
89#else
90#if defined Q_OS_MAC
91 return new QMacTimeZonePrivate(ianaId);
92#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
93 return new QAndroidTimeZonePrivate(ianaId);
94#elif defined(Q_OS_UNIX) || defined(Q_OS_ANDROID_EMBEDDED)
95 return new QTzTimeZonePrivate(ianaId);
96#elif QT_CONFIG(icu)
97 return new QIcuTimeZonePrivate(ianaId);
98#elif defined Q_OS_WIN
99 return new QWinTimeZonePrivate(ianaId);
100#else
101 return new QUtcTimeZonePrivate(ianaId);
102#endif // System Locales
103#endif // QT_NO_SYSTEMLOCALE
104}
105
106class QTimeZoneSingleton
107{
108public:
109 QTimeZoneSingleton() : backend(newBackendTimeZone()) {}
110
111 // The backend_tz is the tz to use in static methods such as availableTimeZoneIds() and
112 // isTimeZoneIdAvailable() and to create named IANA time zones. This is usually the host
113 // system, but may be different if the host resources are insufficient or if
114 // QT_NO_SYSTEMLOCALE is set. A simple UTC backend is used if no alternative is available.
115 QSharedDataPointer<QTimeZonePrivate> backend;
116};
117
118Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz);
119
120/*!
121 \class QTimeZone
122 \inmodule QtCore
123 \since 5.2
124
125 \brief The QTimeZone class converts between UTC and local time in a specific
126 time zone.
127
128 \threadsafe
129
130 This class provides a stateless calculator for time zone conversions
131 between UTC and the local time in a specific time zone. By default it uses
132 the host system time zone data to perform these conversions.
133
134 This class is primarily designed for use in QDateTime; most applications
135 will not need to access this class directly and should instead use
136 QDateTime with a Qt::TimeSpec of Qt::TimeZone.
137
138 \note For consistency with QDateTime, QTimeZone does not account for leap
139 seconds.
140
141 \section1 Remarks
142
143 \section2 IANA Time Zone IDs
144
145 QTimeZone uses the IANA time zone IDs as defined in the IANA Time Zone
146 Database (http://www.iana.org/time-zones). This is to ensure a standard ID
147 across all supported platforms. Most platforms support the IANA IDs
148 and the IANA Database natively, but for Windows a mapping is required to
149 the native IDs. See below for more details.
150
151 The IANA IDs can and do change on a regular basis, and can vary depending
152 on how recently the host system data was updated. As such you cannot rely
153 on any given ID existing on any host system. You must use
154 availableTimeZoneIds() to determine what IANA IDs are available.
155
156 The IANA IDs and database are also know as the Olson IDs and database,
157 named after their creator.
158
159 \section2 UTC Offset Time Zones
160
161 A default UTC time zone backend is provided which is always guaranteed to
162 be available. This provides a set of generic Offset From UTC time zones
163 in the range UTC-14:00 to UTC+14:00. These time zones can be created
164 using either the standard ISO format names "UTC+00:00" as listed by
165 availableTimeZoneIds(), or using the number of offset seconds.
166
167 \section2 Windows Time Zones
168
169 Windows native time zone support is severely limited compared to the
170 standard IANA TZ Database. Windows time zones cover larger geographic
171 areas and are thus less accurate in their conversions. They also do not
172 support as much historic conversion data and so may only be accurate for
173 the current year.
174
175 QTimeZone uses a conversion table derived form the Unicode CLDR data to map
176 between IANA IDs and Windows IDs. Depending on your version of Windows
177 and Qt, this table may not be able to provide a valid conversion, in which
178 "UTC" will be returned.
179
180 QTimeZone provides a public API to use this conversion table. The Windows ID
181 used is the Windows Registry Key for the time zone which is also the MS
182 Exchange EWS ID as well, but is different to the Time Zone Name (TZID) and
183 COD code used by MS Exchange in versions before 2007.
184
185 \section2 System Time Zone
186
187 QTimeZone does not support any concept of a system or default time zone.
188 If you require a QDateTime that uses the current system time zone at any
189 given moment then you should use a Qt::TimeSpec of Qt::LocalTime.
190
191 The method systemTimeZoneId() returns the current system IANA time zone
192 ID which on Unix-like systems will always be correct. On Windows this ID is
193 translated from the Windows system ID using an internal translation
194 table and the user's selected country. As a consequence there is a small
195 chance any Windows install may have IDs not known by Qt, in which case
196 "UTC" will be returned.
197
198 Creating a new QTimeZone instance using the system time zone ID will only
199 produce a fixed named copy of the time zone, it will not change if the
200 system time zone changes.
201
202 \section2 Time Zone Offsets
203
204 The difference between UTC and the local time in a time zone is expressed
205 as an offset in seconds from UTC, i.e. the number of seconds to add to UTC
206 to obtain the local time. The total offset is comprised of two component
207 parts, the standard time offset and the daylight-saving time offset. The
208 standard time offset is the number of seconds to add to UTC to obtain
209 standard time in the time zone. The daylight-saving time offset is the
210 number of seconds to add to the standard time offset to obtain
211 daylight-saving time (abbreviated DST and sometimes called "daylight time"
212 or "summer time") in the time zone.
213
214 Note that the standard and DST offsets for a time zone may change over time
215 as countries have changed DST laws or even their standard time offset.
216
217 \section2 License
218
219 This class includes data obtained from the CLDR data files under the terms
220 of the Unicode Data Files and Software License. See
221 \l{unicode-cldr}{Unicode Common Locale Data Repository (CLDR)} for details.
222
223 \sa QDateTime
224*/
225
226/*!
227 \enum QTimeZone::anonymous
228
229 Sane UTC offsets range from -14 to +14 hours.
230 No known zone > 12 hrs West of Greenwich (Baker Island, USA).
231 No known zone > 14 hrs East of Greenwich (Kiritimati, Christmas Island, Kiribati).
232
233 \value MinUtcOffsetSecs
234 -14 * 3600,
235
236 \value MaxUtcOffsetSecs
237 +14 * 3600
238*/
239
240/*!
241 \enum QTimeZone::TimeType
242
243 The type of time zone time, for example when requesting the name. In time
244 zones that do not apply DST, all three values may return the same result.
245
246 \value StandardTime
247 The standard time in a time zone, i.e. when Daylight-Saving is not
248 in effect.
249 For example when formatting a display name this will show something
250 like "Pacific Standard Time".
251 \value DaylightTime
252 A time when Daylight-Saving is in effect.
253 For example when formatting a display name this will show something
254 like "Pacific daylight-saving time".
255 \value GenericTime
256 A time which is not specifically Standard or Daylight-Saving time,
257 either an unknown time or a neutral form.
258 For example when formatting a display name this will show something
259 like "Pacific Time".
260*/
261
262/*!
263 \enum QTimeZone::NameType
264
265 The type of time zone name.
266
267 \value DefaultName
268 The default form of the time zone name, e.g. LongName, ShortName or OffsetName
269 \value LongName
270 The long form of the time zone name, e.g. "Central European Time"
271 \value ShortName
272 The short form of the time zone name, usually an abbreviation, e.g. "CET"
273 \value OffsetName
274 The standard ISO offset form of the time zone name, e.g. "UTC+01:00"
275*/
276
277/*!
278 \class QTimeZone::OffsetData
279 \inmodule QtCore
280
281 The time zone offset data for a given moment in time, i.e. the time zone
282 offsets and abbreviation to use at that moment in time.
283
284 \list
285 \li OffsetData::atUtc The datetime of the offset data in UTC time.
286 \li OffsetData::offsetFromUtc The total offset from UTC in effect at the datetime.
287 \li OffsetData::standardTimeOffset The standard time offset component of the total offset.
288 \li OffsetData::daylightTimeOffset The DST offset component of the total offset.
289 \li OffsetData::abbreviation The abbreviation in effect at the datetime.
290 \endlist
291
292 For example, for time zone "Europe/Berlin" the OffsetDate in standard and DST might be:
293
294 \list
295 \li atUtc = QDateTime(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::UTC)
296 \li offsetFromUtc = 3600
297 \li standardTimeOffset = 3600
298 \li daylightTimeOffset = 0
299 \li abbreviation = "CET"
300 \endlist
301
302 \list
303 \li atUtc = QDateTime(QDate(2013, 6, 1), QTime(0, 0, 0), Qt::UTC)
304 \li offsetFromUtc = 7200
305 \li standardTimeOffset = 3600
306 \li daylightTimeOffset = 3600
307 \li abbreviation = "CEST"
308 \endlist
309*/
310
311/*!
312 \typedef QTimeZone::OffsetDataList
313
314 Synonym for QVector<OffsetData>.
315*/
316
317/*!
318 Create a null/invalid time zone instance.
319*/
320
321QTimeZone::QTimeZone() noexcept
322 : d(nullptr)
323{
324}
325
326/*!
327 Creates an instance of the requested time zone \a ianaId.
328
329 The ID must be one of the available system IDs or a valid UTC-with-offset
330 ID, otherwise an invalid time zone will be returned.
331
332 \sa availableTimeZoneIds()
333*/
334
335QTimeZone::QTimeZone(const QByteArray &ianaId)
336{
337 // Try and see if it's a CLDR UTC offset ID - just as quick by creating as
338 // by looking up.
339 d = new QUtcTimeZonePrivate(ianaId);
340 // If not a CLDR UTC offset ID then try creating it with the system backend.
341 // Relies on backend not creating valid TZ with invalid name.
342 if (!d->isValid())
343 d = ianaId.isEmpty() ? newBackendTimeZone() : newBackendTimeZone(ianaId);
344 // Can also handle UTC with arbitrary (valid) offset, but only do so as
345 // fall-back, since either of the above may handle it more informatively.
346 if (!d->isValid()) {
347 qint64 offset = QUtcTimeZonePrivate::offsetFromUtcString(id: ianaId);
348 if (offset != QTimeZonePrivate::invalidSeconds()) {
349 // Should have abs(offset) < 24 * 60 * 60 = 86400.
350 qint32 seconds = qint32(offset);
351 Q_ASSERT(qint64(seconds) == offset);
352 // NB: this canonicalises the name, so it might not match ianaId
353 d = new QUtcTimeZonePrivate(seconds);
354 }
355 }
356}
357
358/*!
359 Creates an instance of a time zone with the requested Offset from UTC of
360 \a offsetSeconds.
361
362 The \a offsetSeconds from UTC must be in the range -14 hours to +14 hours
363 otherwise an invalid time zone will be returned.
364*/
365
366QTimeZone::QTimeZone(int offsetSeconds)
367 : d((offsetSeconds >= MinUtcOffsetSecs && offsetSeconds <= MaxUtcOffsetSecs)
368 ? new QUtcTimeZonePrivate(offsetSeconds) : nullptr)
369{
370}
371
372/*!
373 Creates a custom time zone with an ID of \a ianaId and an offset from UTC
374 of \a offsetSeconds. The \a name will be the name used by displayName()
375 for the LongName, the \a abbreviation will be used by displayName() for the
376 ShortName and by abbreviation(), and the optional \a country will be used
377 by country(). The \a comment is an optional note that may be displayed in
378 a GUI to assist users in selecting a time zone.
379
380 The \a ianaId must not be one of the available system IDs returned by
381 availableTimeZoneIds(). The \a offsetSeconds from UTC must be in the range
382 -14 hours to +14 hours.
383
384 If the custom time zone does not have a specific country then set it to the
385 default value of QLocale::AnyCountry.
386*/
387
388QTimeZone::QTimeZone(const QByteArray &ianaId, int offsetSeconds, const QString &name,
389 const QString &abbreviation, QLocale::Country country, const QString &comment)
390 : d()
391{
392 if (!isTimeZoneIdAvailable(ianaId))
393 d = new QUtcTimeZonePrivate(ianaId, offsetSeconds, name, abbreviation, country, comment);
394}
395
396/*!
397 \internal
398
399 Private. Create time zone with given private backend
400*/
401
402QTimeZone::QTimeZone(QTimeZonePrivate &dd)
403 : d(&dd)
404{
405}
406
407/*!
408 Copy constructor, copy \a other to this.
409*/
410
411QTimeZone::QTimeZone(const QTimeZone &other)
412 : d(other.d)
413{
414}
415
416/*!
417 Destroys the time zone.
418*/
419
420QTimeZone::~QTimeZone()
421{
422}
423
424/*!
425 \fn QTimeZone::swap(QTimeZone &other)
426
427 Swaps this time zone instance with \a other. This function is very
428 fast and never fails.
429*/
430
431/*!
432 Assignment operator, assign \a other to this.
433*/
434
435QTimeZone &QTimeZone::operator=(const QTimeZone &other)
436{
437 d = other.d;
438 return *this;
439}
440
441/*
442 \fn void QTimeZone::swap(QTimeZone &other)
443
444 Swaps this timezone with \a other. This function is very fast and
445 never fails.
446*/
447
448/*!
449 \fn QTimeZone &QTimeZone::operator=(QTimeZone &&other)
450
451 Move-assigns \a other to this QTimeZone instance, transferring the
452 ownership of the managed pointer to this instance.
453*/
454
455/*!
456 Returns \c true if this time zone is equal to the \a other time zone.
457*/
458
459bool QTimeZone::operator==(const QTimeZone &other) const
460{
461 if (d && other.d)
462 return (*d == *other.d);
463 else
464 return (d == other.d);
465}
466
467/*!
468 Returns \c true if this time zone is not equal to the \a other time zone.
469*/
470
471bool QTimeZone::operator!=(const QTimeZone &other) const
472{
473 if (d && other.d)
474 return (*d != *other.d);
475 else
476 return (d != other.d);
477}
478
479/*!
480 Returns \c true if this time zone is valid.
481*/
482
483bool QTimeZone::isValid() const
484{
485 if (d)
486 return d->isValid();
487 else
488 return false;
489}
490
491/*!
492 Returns the IANA ID for the time zone.
493
494 IANA IDs are used on all platforms. On Windows these are translated
495 from the Windows ID into the closest IANA ID for the time zone and country.
496*/
497
498QByteArray QTimeZone::id() const
499{
500 if (d)
501 return d->id();
502 else
503 return QByteArray();
504}
505
506/*!
507 Returns the country for the time zone.
508*/
509
510QLocale::Country QTimeZone::country() const
511{
512 if (isValid())
513 return d->country();
514 else
515 return QLocale::AnyCountry;
516}
517
518/*!
519 Returns any comment for the time zone.
520
521 A comment may be provided by the host platform to assist users in
522 choosing the correct time zone. Depending on the platform this may not
523 be localized.
524*/
525
526QString QTimeZone::comment() const
527{
528 if (isValid())
529 return d->comment();
530 else
531 return QString();
532}
533
534/*!
535 Returns the localized time zone display name at the given \a atDateTime
536 for the given \a nameType in the given \a locale. The \a nameType and
537 \a locale requested may not be supported on all platforms, in which case
538 the best available option will be returned.
539
540 If the \a locale is not provided then the application default locale will
541 be used.
542
543 The display name may change depending on DST or historical events.
544
545 \sa abbreviation()
546*/
547
548QString QTimeZone::displayName(const QDateTime &atDateTime, NameType nameType,
549 const QLocale &locale) const
550{
551 if (isValid())
552 return d->displayName(atMSecsSinceEpoch: atDateTime.toMSecsSinceEpoch(), nameType, locale);
553 else
554 return QString();
555}
556
557/*!
558 Returns the localized time zone display name for the given \a timeType
559 and \a nameType in the given \a locale. The \a nameType and \a locale
560 requested may not be supported on all platforms, in which case the best
561 available option will be returned.
562
563 If the \a locale is not provided then the application default locale will
564 be used.
565
566 Where the time zone display names have changed over time then the most
567 recent names will be used.
568
569 \sa abbreviation()
570*/
571
572QString QTimeZone::displayName(TimeType timeType, NameType nameType,
573 const QLocale &locale) const
574{
575 if (isValid())
576 return d->displayName(timeType, nameType, locale);
577 else
578 return QString();
579}
580
581/*!
582 Returns the time zone abbreviation at the given \a atDateTime. The
583 abbreviation may change depending on DST or even historical events.
584
585 Note that the abbreviation is not guaranteed to be unique to this time zone
586 and should not be used in place of the ID or display name.
587
588 \sa displayName()
589*/
590
591QString QTimeZone::abbreviation(const QDateTime &atDateTime) const
592{
593 if (isValid())
594 return d->abbreviation(atMSecsSinceEpoch: atDateTime.toMSecsSinceEpoch());
595 else
596 return QString();
597}
598
599/*!
600 Returns the total effective offset at the given \a atDateTime, i.e. the
601 number of seconds to add to UTC to obtain the local time. This includes
602 any DST offset that may be in effect, i.e. it is the sum of
603 standardTimeOffset() and daylightTimeOffset() for the given datetime.
604
605 For example, for the time zone "Europe/Berlin" the standard time offset is
606 +3600 seconds and the DST offset is +3600 seconds. During standard time
607 offsetFromUtc() will return +3600 (UTC+01:00), and during DST it will
608 return +7200 (UTC+02:00).
609
610 \sa standardTimeOffset(), daylightTimeOffset()
611*/
612
613int QTimeZone::offsetFromUtc(const QDateTime &atDateTime) const
614{
615 if (isValid())
616 return d->offsetFromUtc(atMSecsSinceEpoch: atDateTime.toMSecsSinceEpoch());
617 else
618 return 0;
619}
620
621/*!
622 Returns the standard time offset at the given \a atDateTime, i.e. the
623 number of seconds to add to UTC to obtain the local Standard Time. This
624 excludes any DST offset that may be in effect.
625
626 For example, for the time zone "Europe/Berlin" the standard time offset is
627 +3600 seconds. During both standard and DST offsetFromUtc() will return
628 +3600 (UTC+01:00).
629
630 \sa offsetFromUtc(), daylightTimeOffset()
631*/
632
633int QTimeZone::standardTimeOffset(const QDateTime &atDateTime) const
634{
635 if (isValid())
636 return d->standardTimeOffset(atMSecsSinceEpoch: atDateTime.toMSecsSinceEpoch());
637 else
638 return 0;
639}
640
641/*!
642 Returns the daylight-saving time offset at the given \a atDateTime,
643 i.e. the number of seconds to add to the standard time offset to obtain the
644 local daylight-saving time.
645
646 For example, for the time zone "Europe/Berlin" the DST offset is +3600
647 seconds. During standard time daylightTimeOffset() will return 0, and when
648 daylight-saving is in effect it will return +3600.
649
650 \sa offsetFromUtc(), standardTimeOffset()
651*/
652
653int QTimeZone::daylightTimeOffset(const QDateTime &atDateTime) const
654{
655 if (hasDaylightTime())
656 return d->daylightTimeOffset(atMSecsSinceEpoch: atDateTime.toMSecsSinceEpoch());
657 else
658 return 0;
659}
660
661/*!
662 Returns \c true if the time zone has practiced daylight-saving at any time.
663
664 \sa isDaylightTime(), daylightTimeOffset()
665*/
666
667bool QTimeZone::hasDaylightTime() const
668{
669 if (isValid())
670 return d->hasDaylightTime();
671 else
672 return false;
673}
674
675/*!
676 Returns \c true if daylight-saving was in effect at the given \a atDateTime.
677
678 \sa hasDaylightTime(), daylightTimeOffset()
679*/
680
681bool QTimeZone::isDaylightTime(const QDateTime &atDateTime) const
682{
683 if (hasDaylightTime())
684 return d->isDaylightTime(atMSecsSinceEpoch: atDateTime.toMSecsSinceEpoch());
685 else
686 return false;
687}
688
689/*!
690 Returns the effective offset details at the given \a forDateTime. This is
691 the equivalent of calling offsetFromUtc(), abbreviation(), etc individually but is
692 more efficient.
693
694 \sa offsetFromUtc(), standardTimeOffset(), daylightTimeOffset(), abbreviation()
695*/
696
697QTimeZone::OffsetData QTimeZone::offsetData(const QDateTime &forDateTime) const
698{
699 if (hasTransitions())
700 return QTimeZonePrivate::toOffsetData(data: d->data(forMSecsSinceEpoch: forDateTime.toMSecsSinceEpoch()));
701 else
702 return QTimeZonePrivate::invalidOffsetData();
703}
704
705/*!
706 Returns \c true if the system backend supports obtaining transitions.
707
708 Transitions are changes in the time-zone: these happen when DST turns on or
709 off and when authorities alter the offsets for the time-zone.
710
711 \sa nextTransition(), previousTransition(), transitions()
712*/
713
714bool QTimeZone::hasTransitions() const
715{
716 if (isValid())
717 return d->hasTransitions();
718 else
719 return false;
720}
721
722/*!
723 Returns the first time zone Transition after the given \a afterDateTime.
724 This is most useful when you have a Transition time and wish to find the
725 Transition after it.
726
727 If there is no transition after the given \a afterDateTime then an invalid
728 OffsetData will be returned with an invalid QDateTime.
729
730 The given \a afterDateTime is exclusive.
731
732 \sa hasTransitions(), previousTransition(), transitions()
733*/
734
735QTimeZone::OffsetData QTimeZone::nextTransition(const QDateTime &afterDateTime) const
736{
737 if (hasTransitions())
738 return QTimeZonePrivate::toOffsetData(data: d->nextTransition(afterMSecsSinceEpoch: afterDateTime.toMSecsSinceEpoch()));
739 else
740 return QTimeZonePrivate::invalidOffsetData();
741}
742
743/*!
744 Returns the first time zone Transition before the given \a beforeDateTime.
745 This is most useful when you have a Transition time and wish to find the
746 Transition before it.
747
748 If there is no transition before the given \a beforeDateTime then an invalid
749 OffsetData will be returned with an invalid QDateTime.
750
751 The given \a beforeDateTime is exclusive.
752
753 \sa hasTransitions(), nextTransition(), transitions()
754*/
755
756QTimeZone::OffsetData QTimeZone::previousTransition(const QDateTime &beforeDateTime) const
757{
758 if (hasTransitions())
759 return QTimeZonePrivate::toOffsetData(data: d->previousTransition(beforeMSecsSinceEpoch: beforeDateTime.toMSecsSinceEpoch()));
760 else
761 return QTimeZonePrivate::invalidOffsetData();
762}
763
764/*!
765 Returns a list of all time zone transitions between the given datetimes.
766
767 The given \a fromDateTime and \a toDateTime are inclusive.
768
769 \sa hasTransitions(), nextTransition(), previousTransition()
770*/
771
772QTimeZone::OffsetDataList QTimeZone::transitions(const QDateTime &fromDateTime,
773 const QDateTime &toDateTime) const
774{
775 OffsetDataList list;
776 if (hasTransitions()) {
777 const QTimeZonePrivate::DataList plist = d->transitions(fromMSecsSinceEpoch: fromDateTime.toMSecsSinceEpoch(),
778 toMSecsSinceEpoch: toDateTime.toMSecsSinceEpoch());
779 list.reserve(asize: plist.count());
780 for (const QTimeZonePrivate::Data &pdata : plist)
781 list.append(t: QTimeZonePrivate::toOffsetData(data: pdata));
782 }
783 return list;
784}
785
786// Static methods
787
788/*!
789 Returns the current system time zone IANA ID.
790
791 On Windows this ID is translated from the Windows ID using an internal
792 translation table and the user's selected country. As a consequence there
793 is a small chance any Windows install may have IDs not known by Qt, in
794 which case "UTC" will be returned.
795*/
796
797QByteArray QTimeZone::systemTimeZoneId()
798{
799 const QByteArray sys = global_tz->backend->systemTimeZoneId();
800 if (!sys.isEmpty())
801 return sys;
802 // The system zone, despite the empty ID, may know its real ID anyway:
803 auto zone = systemTimeZone();
804 if (zone.isValid() && !zone.id().isEmpty())
805 return zone.id();
806 // If all else fails, guess UTC.
807 return QTimeZonePrivate::utcQByteArray();
808}
809
810/*!
811 \since 5.5
812 Returns a QTimeZone object that refers to the local system time, as
813 specified by systemTimeZoneId().
814
815 \sa utc()
816*/
817QTimeZone QTimeZone::systemTimeZone()
818{
819 return QTimeZone(global_tz->backend->systemTimeZoneId());
820}
821
822/*!
823 \since 5.5
824 Returns a QTimeZone object that refers to UTC (Universal Time Coordinated).
825
826 \sa systemTimeZone()
827*/
828QTimeZone QTimeZone::utc()
829{
830 return QTimeZone(QTimeZonePrivate::utcQByteArray());
831}
832
833/*!
834 Returns \c true if a given time zone \a ianaId is available on this system.
835
836 \sa availableTimeZoneIds()
837*/
838
839bool QTimeZone::isTimeZoneIdAvailable(const QByteArray &ianaId)
840{
841 // isValidId is not strictly required, but faster to weed out invalid
842 // IDs as availableTimeZoneIds() may be slow
843 if (!QTimeZonePrivate::isValidId(ianaId))
844 return false;
845 return QUtcTimeZonePrivate().isTimeZoneIdAvailable(ianaId) ||
846 global_tz->backend->isTimeZoneIdAvailable(ianaId);
847}
848
849static QList<QByteArray> set_union(const QList<QByteArray> &l1, const QList<QByteArray> &l2)
850{
851 QList<QByteArray> result;
852 result.reserve(alloc: l1.size() + l2.size());
853 std::set_union(first1: l1.begin(), last1: l1.end(),
854 first2: l2.begin(), last2: l2.end(),
855 result: std::back_inserter(x&: result));
856 return result;
857}
858
859/*!
860 Returns a list of all available IANA time zone IDs on this system.
861
862 \sa isTimeZoneIdAvailable()
863*/
864
865QList<QByteArray> QTimeZone::availableTimeZoneIds()
866{
867 return set_union(l1: QUtcTimeZonePrivate().availableTimeZoneIds(),
868 l2: global_tz->backend->availableTimeZoneIds());
869}
870
871/*!
872 Returns a list of all available IANA time zone IDs for a given \a country.
873
874 As a special case, a \a country of Qt::AnyCountry returns those time zones
875 that do not have any country related to them, such as UTC. If you require
876 a list of all time zone IDs for all countries then use the standard
877 availableTimeZoneIds() method.
878
879 \sa isTimeZoneIdAvailable()
880*/
881
882QList<QByteArray> QTimeZone::availableTimeZoneIds(QLocale::Country country)
883{
884 return set_union(l1: QUtcTimeZonePrivate().availableTimeZoneIds(country),
885 l2: global_tz->backend->availableTimeZoneIds(country));
886}
887
888/*!
889 Returns a list of all available IANA time zone IDs with a given standard
890 time offset of \a offsetSeconds.
891
892 \sa isTimeZoneIdAvailable()
893*/
894
895QList<QByteArray> QTimeZone::availableTimeZoneIds(int offsetSeconds)
896{
897 return set_union(l1: QUtcTimeZonePrivate().availableTimeZoneIds(utcOffset: offsetSeconds),
898 l2: global_tz->backend->availableTimeZoneIds(utcOffset: offsetSeconds));
899}
900
901/*!
902 Returns the Windows ID equivalent to the given \a ianaId.
903
904 \sa windowsIdToDefaultIanaId(), windowsIdToIanaIds()
905*/
906
907QByteArray QTimeZone::ianaIdToWindowsId(const QByteArray &ianaId)
908{
909 return QTimeZonePrivate::ianaIdToWindowsId(ianaId);
910}
911
912/*!
913 Returns the default IANA ID for a given \a windowsId.
914
915 Because a Windows ID can cover several IANA IDs in several different
916 countries, this function returns the most frequently used IANA ID with no
917 regard for the country and should thus be used with care. It is usually
918 best to request the default for a specific country.
919
920 \sa ianaIdToWindowsId(), windowsIdToIanaIds()
921*/
922
923QByteArray QTimeZone::windowsIdToDefaultIanaId(const QByteArray &windowsId)
924{
925 return QTimeZonePrivate::windowsIdToDefaultIanaId(windowsId);
926}
927
928/*!
929 Returns the default IANA ID for a given \a windowsId and \a country.
930
931 Because a Windows ID can cover several IANA IDs within a given country,
932 the most frequently used IANA ID in that country is returned.
933
934 As a special case, QLocale::AnyCountry returns the default of those IANA IDs
935 that do not have any specific country.
936
937 \sa ianaIdToWindowsId(), windowsIdToIanaIds()
938*/
939
940QByteArray QTimeZone::windowsIdToDefaultIanaId(const QByteArray &windowsId,
941 QLocale::Country country)
942{
943 return QTimeZonePrivate::windowsIdToDefaultIanaId(windowsId, country);
944}
945
946/*!
947 Returns all the IANA IDs for a given \a windowsId.
948
949 The returned list is sorted alphabetically.
950
951 \sa ianaIdToWindowsId(), windowsIdToDefaultIanaId()
952*/
953
954QList<QByteArray> QTimeZone::windowsIdToIanaIds(const QByteArray &windowsId)
955{
956 return QTimeZonePrivate::windowsIdToIanaIds(windowsId);
957}
958
959/*!
960 Returns all the IANA IDs for a given \a windowsId and \a country.
961
962 As a special case QLocale::AnyCountry returns those IANA IDs that do
963 not have any specific country.
964
965 The returned list is in order of frequency of usage, i.e. larger zones
966 within a country are listed first.
967
968 \sa ianaIdToWindowsId(), windowsIdToDefaultIanaId()
969*/
970
971QList<QByteArray> QTimeZone::windowsIdToIanaIds(const QByteArray &windowsId,
972 QLocale::Country country)
973{
974 return QTimeZonePrivate::windowsIdToIanaIds(windowsId, country);
975}
976
977#ifndef QT_NO_DATASTREAM
978QDataStream &operator<<(QDataStream &ds, const QTimeZone &tz)
979{
980 tz.d->serialize(ds);
981 return ds;
982}
983
984QDataStream &operator>>(QDataStream &ds, QTimeZone &tz)
985{
986 QString ianaId;
987 ds >> ianaId;
988 if (ianaId == QLatin1String("OffsetFromUtc")) {
989 int utcOffset;
990 QString name;
991 QString abbreviation;
992 int country;
993 QString comment;
994 ds >> ianaId >> utcOffset >> name >> abbreviation >> country >> comment;
995 // Try creating as a system timezone, which succeeds (producing a valid
996 // zone) iff ianaId is valid; we can then ignore the other data.
997 tz = QTimeZone(ianaId.toUtf8());
998 // If not, then construct a custom timezone using all the saved values:
999 if (!tz.isValid())
1000 tz = QTimeZone(ianaId.toUtf8(), utcOffset, name, abbreviation,
1001 QLocale::Country(country), comment);
1002 } else {
1003 tz = QTimeZone(ianaId.toUtf8());
1004 }
1005 return ds;
1006}
1007#endif // QT_NO_DATASTREAM
1008
1009#ifndef QT_NO_DEBUG_STREAM
1010QDebug operator<<(QDebug dbg, const QTimeZone &tz)
1011{
1012 QDebugStateSaver saver(dbg);
1013 //TODO Include backend and data version details?
1014 dbg.nospace() << "QTimeZone(" << QString::fromUtf8(str: tz.id()) << ')';
1015 return dbg;
1016}
1017#endif
1018
1019QT_END_NAMESPACE
1020

source code of qtbase/src/corelib/time/qtimezone.cpp