summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2013-11-26 10:51:33 +0100
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2013-11-26 10:51:34 +0100
commit3061dc4abdfbd1a536918935d380872de6655521 (patch)
treeff440ed0c7d5816cc7e2874f73fdabfb0bce493f /src/corelib
parent25b2b682d616dd52c3515f443e3d25fc0224f3a2 (diff)
parent9b8570c4e9359eb8b45b39c28aa9d8c140f3fc44 (diff)
Merge remote-tracking branch 'origin/release' into stable
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/global/qcompilerdetection.h14
-rw-r--r--src/corelib/global/qglobal.cpp26
-rw-r--r--src/corelib/global/qglobal.h10
-rw-r--r--src/corelib/global/qsysinfo.h13
-rw-r--r--src/corelib/io/qfileselector.cpp2
-rw-r--r--src/corelib/kernel/kernel.pri3
-rw-r--r--src/corelib/kernel/qcore_mac_objc.mm30
-rw-r--r--src/corelib/kernel/qcore_mac_p.h4
-rw-r--r--src/corelib/kernel/qobject.cpp43
-rw-r--r--src/corelib/kernel/qobject_impl.h2
-rw-r--r--src/corelib/kernel/qobject_p.h1
-rw-r--r--src/corelib/tools/qtimezone.cpp117
-rw-r--r--src/corelib/tools/qtimezone.h14
-rw-r--r--src/corelib/tools/qtimezoneprivate.cpp26
-rw-r--r--src/corelib/tools/qtimezoneprivate_p.h11
-rw-r--r--src/corelib/tools/qtimezoneprivate_tz.cpp259
-rw-r--r--src/corelib/tools/qtimezoneprivate_win.cpp19
17 files changed, 392 insertions, 202 deletions
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index f23478d75c..44077132d4 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -735,6 +735,20 @@
# define Q_COMPILER_CLASS_ENUM
# define Q_COMPILER_ATOMICS
# endif /* VC 11 */
+# if _MSC_VER >= 1800
+ /* C++11 features in VC12 = VC2013 */
+# define Q_COMPILER_DEFAULT_MEMBERS
+# define Q_COMPILER_DELETE_MEMBERS
+# define Q_COMPILER_DELEGATING_CONSTRUCTORS
+# define Q_COMPILER_EXPLICIT_CONVERSIONS
+# define Q_COMPILER_NONSTATIC_MEMBER_INIT
+# define Q_COMPILER_INITIALIZER_LISTS
+// implemented in principle, but has a bug that makes it unusable: http://connect.microsoft.com/VisualStudio/feedback/details/802058/c-11-unified-initialization-fails-with-c-style-arrays
+// #define Q_COMPILER_UNIFORM_INIT
+# define Q_COMPILER_RAW_STRINGS
+# define Q_COMPILER_TEMPLATE_ALIAS
+# define Q_COMPILER_VARIADIC_TEMPLATES
+# endif /* VC 12 */
#endif /* Q_CC_MSVC */
#ifdef __cplusplus
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index b27d0bf53f..0c72bd7022 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -985,8 +985,7 @@ bool qSharedBuild() Q_DECL_NOTHROW
/*!
\fn QSysInfo::MacVersion QSysInfo::macVersion()
- Returns the version of Mac OS X on which the application is run (Mac OS X
- Only).
+ Returns the version of Darwin (OS X or iOS) on which the application is run.
*/
/*!
@@ -1056,7 +1055,7 @@ bool qSharedBuild() Q_DECL_NOTHROW
\enum QSysInfo::MacVersion
This enum provides symbolic names for the various versions of the
- OS X operating system. On OS X, the
+ Darwin operating system, covering both OS X and iOS. The
QSysInfo::MacintoshVersion variable gives the version of the
system on which the application is run.
@@ -1084,6 +1083,15 @@ bool qSharedBuild() Q_DECL_NOTHROW
\value MV_MOUNTAINLION Apple codename for MV_10_8
\value MV_MAVERICKS Apple codename for MV_10_9
+ \value MV_IOS iOS (any)
+ \value MV_IOS_4_3 iOS 4.3
+ \value MV_IOS_5_0 iOS 5.0
+ \value MV_IOS_5_1 iOS 5.1
+ \value MV_IOS_6_0 iOS 6.0
+ \value MV_IOS_6_1 iOS 6.1
+ \value MV_IOS_7_0 iOS 7.0
+ \value MV_IOS_7_1 iOS 7.1
+
\sa WinVersion
*/
@@ -1706,13 +1714,15 @@ static const unsigned int qt_one = 1;
const int QSysInfo::ByteOrder = ((*((unsigned char *) &qt_one) == 0) ? BigEndian : LittleEndian);
#endif
-#if defined(Q_OS_MACX)
+#if defined(Q_OS_MAC)
QT_BEGIN_INCLUDE_NAMESPACE
#include "private/qcore_mac_p.h"
#include "qnamespace.h"
QT_END_INCLUDE_NAMESPACE
+#if defined(Q_OS_OSX)
+
Q_CORE_EXPORT OSErr qt_mac_create_fsref(const QString &file, FSRef *fsref)
{
return FSPathMakeRef(reinterpret_cast<const UInt8 *>(file.toUtf8().constData()), fsref, 0);
@@ -1728,17 +1738,17 @@ Q_CORE_EXPORT void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding e
Q_CORE_EXPORT QString qt_mac_from_pascal_string(const Str255 pstr) {
return QCFString(CFStringCreateWithPascalString(0, pstr, CFStringGetSystemEncoding()));
}
-#endif // defined(Q_OS_MACX)
-
-#if defined(Q_OS_MAC)
+#endif // defined(Q_OS_OSX)
QSysInfo::MacVersion QSysInfo::macVersion()
{
-#ifdef Q_OS_MACX
+#if defined(Q_OS_OSX)
SInt32 gestalt_version;
if (Gestalt(gestaltSystemVersion, &gestalt_version) == noErr) {
return QSysInfo::MacVersion(((gestalt_version & 0x00F0) >> 4) + 2);
}
+#elif defined(Q_OS_IOS)
+ return qt_ios_version(); // qtcore_mac_objc.mm
#endif
return QSysInfo::MV_Unknown;
}
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index c2bb7173ba..3c3d35e373 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -520,6 +520,16 @@ Q_DECL_CONSTEXPR inline const T &qBound(const T &min, const T &val, const T &max
# define QT_MAC_DEPLOYMENT_TARGET_BELOW(osx, ios) \
(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && osx != __MAC_NA && __MAC_OS_X_VERSION_MIN_REQUIRED < osx) || \
(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && ios != __IPHONE_NA && __IPHONE_OS_VERSION_MIN_REQUIRED < ios)
+
+# define QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(ios) \
+ QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, ios)
+# define QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(osx) \
+ QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(osx, __IPHONE_NA)
+
+# define QT_IOS_DEPLOYMENT_TARGET_BELOW(ios) \
+ QT_MAC_DEPLOYMENT_TARGET_BELOW(__MAC_NA, ios)
+# define QT_OSX_DEPLOYMENT_TARGET_BELOW(osx) \
+ QT_MAC_DEPLOYMENT_TARGET_BELOW(osx, __IPHONE_NA)
#endif
/*
diff --git a/src/corelib/global/qsysinfo.h b/src/corelib/global/qsysinfo.h
index bd76f908e7..38735c12de 100644
--- a/src/corelib/global/qsysinfo.h
+++ b/src/corelib/global/qsysinfo.h
@@ -120,6 +120,7 @@ public:
#endif
#ifdef Q_OS_MAC
+# define Q_MV_IOS(major, minor) (QSysInfo::MV_IOS | major << 4 | minor)
enum MacVersion {
MV_Unknown = 0x0000,
@@ -146,7 +147,17 @@ public:
MV_SNOWLEOPARD = MV_10_6,
MV_LION = MV_10_7,
MV_MOUNTAINLION = MV_10_8,
- MV_MAVERICKS = MV_10_9
+ MV_MAVERICKS = MV_10_9,
+
+ /* iOS */
+ MV_IOS = 1 << 8,
+ MV_IOS_4_3 = Q_MV_IOS(4, 3),
+ MV_IOS_5_0 = Q_MV_IOS(5, 0),
+ MV_IOS_5_1 = Q_MV_IOS(5, 1),
+ MV_IOS_6_0 = Q_MV_IOS(6, 0),
+ MV_IOS_6_1 = Q_MV_IOS(6, 1),
+ MV_IOS_7_0 = Q_MV_IOS(7, 0),
+ MV_IOS_7_1 = Q_MV_IOS(7, 1)
};
static const MacVersion MacintoshVersion;
static MacVersion macVersion();
diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp
index eed9e8870a..72e4198fb0 100644
--- a/src/corelib/io/qfileselector.cpp
+++ b/src/corelib/io/qfileselector.cpp
@@ -359,6 +359,8 @@ QStringList QFileSelectorPrivate::platformSelectors()
ret << QStringLiteral("android");
# elif defined(Q_OS_BLACKBERRY)
ret << QStringLiteral("blackberry");
+# elif defined(Q_OS_QNX)
+ ret << QStringLiteral("qnx");
# elif defined(Q_OS_IOS)
ret << QStringLiteral("ios");
# elif defined(Q_OS_LINUX)
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index 26ad9f488c..7625a74381 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -98,6 +98,9 @@ mac:!nacl {
kernel/qcore_mac.cpp
OBJECTIVE_SOURCES += \
kernel/qcore_mac_objc.mm
+
+ # We need UIKit for UIDevice
+ ios: LIBS_PRIVATE += -framework UIKit
}
nacl {
diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm
index 7b9eb67969..73f8296021 100644
--- a/src/corelib/kernel/qcore_mac_objc.mm
+++ b/src/corelib/kernel/qcore_mac_objc.mm
@@ -41,6 +41,10 @@
#include <private/qcore_mac_p.h>
+#ifdef Q_OS_IOS
+#import <UIKit/UIKit.h>
+#endif
+
QT_BEGIN_NAMESPACE
NSString *QCFString::toNSString(const QString &string)
@@ -54,5 +58,31 @@ QString QCFString::toQString(const NSString *nsstr)
return toQString(reinterpret_cast<CFStringRef>(nsstr));
}
+#ifdef Q_OS_IOS
+QSysInfo::MacVersion qt_ios_version()
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ int major = 0, minor = 0;
+ NSArray *components = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:@"."];
+ switch ([components count]) {
+ case 3:
+ // We don't care about the patch version
+ case 2:
+ minor = [[components objectAtIndex:1] intValue];
+ // fall through
+ case 1:
+ major = [[components objectAtIndex:0] intValue];
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+
+ [pool release];
+
+ return QSysInfo::MacVersion(Q_MV_IOS(major, minor));
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index fa911fb967..f491be9768 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -143,6 +143,10 @@ private:
QString string;
};
+#ifdef Q_OS_IOS
+QSysInfo::MacVersion qt_ios_version();
+#endif
+
QT_END_NAMESPACE
#endif // QCORE_MAC_P_H
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 6fb22054cc..e02026ca4c 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -177,6 +178,7 @@ private:
void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject *) = 0;
+void (*QAbstractDeclarativeData::destroyed_qml1)(QAbstractDeclarativeData *, QObject *) = 0;
void (*QAbstractDeclarativeData::parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *) = 0;
void (*QAbstractDeclarativeData::signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **) = 0;
int (*QAbstractDeclarativeData::receivers)(QAbstractDeclarativeData *, const QObject *, int) = 0;
@@ -805,8 +807,12 @@ QObject::~QObject()
}
}
- if (d->declarativeData)
- QAbstractDeclarativeData::destroyed(d->declarativeData, this);
+ if (d->declarativeData) {
+ if (QAbstractDeclarativeData::destroyed)
+ QAbstractDeclarativeData::destroyed(d->declarativeData, this);
+ if (QAbstractDeclarativeData::destroyed_qml1)
+ QAbstractDeclarativeData::destroyed_qml1(d->declarativeData, this);
+ }
// set ref to zero to indicate that this object has been deleted
if (d->currentSender != 0)
@@ -847,9 +853,9 @@ QObject::~QObject()
// The destroy operation must happen outside the lock
if (c->isSlotObject) {
+ c->isSlotObject = false;
locker.unlock();
c->slotObj->destroyIfLastRef();
- c->isSlotObject = false;
locker.relock();
}
c->deref();
@@ -864,15 +870,29 @@ QObject::~QObject()
d->connectionLists = 0;
}
- // disconnect all senders
+ /* Disconnect all senders:
+ * This loop basically just does
+ * for (node = d->senders; node; node = node->next) { ... }
+ *
+ * We need to temporarily unlock the receiver mutex to destroy the functors or to lock the
+ * sender's mutex. And when the mutex is released, node->next might be destroyed by another
+ * thread. That's why we set node->prev to &node, that way, if node is destroyed, node will
+ * be updated.
+ */
QObjectPrivate::Connection *node = d->senders;
while (node) {
QObject *sender = node->sender;
+ // Send disconnectNotify before removing the connection from sender's connection list.
+ // This ensures any eventual destructor of sender will block on getting receiver's lock
+ // and not finish until we release it.
+ sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
QMutex *m = signalSlotLock(sender);
node->prev = &node;
bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
//the node has maybe been removed while the mutex was unlocked in relock?
if (!node || node->sender != sender) {
+ // We hold the wrong mutex
+ Q_ASSERT(needToUnlock);
m->unlock();
continue;
}
@@ -881,8 +901,6 @@ QObject::~QObject()
if (senderLists)
senderLists->dirty = true;
- int signal_index = node->signal_index;
-
QtPrivate::QSlotObjectBase *slotObj = Q_NULLPTR;
if (node->isSlotObject) {
slotObj = node->slotObj;
@@ -894,12 +912,12 @@ QObject::~QObject()
m->unlock();
if (slotObj) {
+ if (node)
+ node->prev = &node;
locker.unlock();
slotObj->destroyIfLastRef();
locker.relock();
}
-
- sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), signal_index));
}
}
@@ -1858,7 +1876,7 @@ void QObjectPrivate::setParent_helper(QObject *o)
}
}
}
- if (!isDeletingChildren && declarativeData)
+ if (!isDeletingChildren && declarativeData && QAbstractDeclarativeData::parentChanged)
QAbstractDeclarativeData::parentChanged(declarativeData, q, o);
}
@@ -3163,7 +3181,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c,
&& (slot == 0 || (c->isSlotObject && c->slotObj->compare(slot)))))) {
bool needToUnlock = false;
QMutex *receiverMutex = 0;
- if (!receiver) {
+ if (c->receiver) {
receiverMutex = signalSlotLock(c->receiver);
// need to relock this receiver and sender in the correct order
needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex);
@@ -3180,9 +3198,9 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c,
c->receiver = 0;
if (c->isSlotObject) {
+ c->isSlotObject = false;
senderMutex->unlock();
c->slotObj->destroyIfLastRef();
- c->isSlotObject = false;
senderMutex->lock();
}
@@ -3211,8 +3229,7 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender,
QObject *s = const_cast<QObject *>(sender);
QMutex *senderMutex = signalSlotLock(sender);
- QMutex *receiverMutex = receiver ? signalSlotLock(receiver) : 0;
- QOrderedMutexLocker locker(senderMutex, receiverMutex);
+ QMutexLocker locker(senderMutex);
QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
if (!connectionLists)
diff --git a/src/corelib/kernel/qobject_impl.h b/src/corelib/kernel/qobject_impl.h
index 1bbd548be6..d2996e6e4d 100644
--- a/src/corelib/kernel/qobject_impl.h
+++ b/src/corelib/kernel/qobject_impl.h
@@ -99,6 +99,8 @@ namespace QtPrivate {
template <typename ArgList, bool Declared = TypesAreDeclaredMetaType<ArgList>::Value > struct ConnectionTypes
{ static const int *types() { return 0; } };
+ template <> struct ConnectionTypes<List<>, true>
+ { static const int *types() { return 0; } };
template <typename... Args> struct ConnectionTypes<List<Args...>, true>
{ static const int *types() { static const int t[sizeof...(Args) + 1] = { (QtPrivate::QMetaTypeIdHelper<Args>::qt_metatype_id())..., 0 }; return t; } };
#endif
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index f5745515c9..cd2d592cec 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -90,6 +90,7 @@ class Q_CORE_EXPORT QAbstractDeclarativeData
{
public:
static void (*destroyed)(QAbstractDeclarativeData *, QObject *);
+ static void (*destroyed_qml1)(QAbstractDeclarativeData *, QObject *);
static void (*parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *);
static void (*signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **);
static int (*receivers)(QAbstractDeclarativeData *, const QObject *, int);
diff --git a/src/corelib/tools/qtimezone.cpp b/src/corelib/tools/qtimezone.cpp
index 9288dc7756..5fec06b30a 100644
--- a/src/corelib/tools/qtimezone.cpp
+++ b/src/corelib/tools/qtimezone.cpp
@@ -105,7 +105,7 @@ public:
QTimeZoneSingleton() : backend(newBackendTimeZone()) {}
// The backend_tz is the tz to use in static methods such as availableTimeZoneIds() and
- // isTimeZoneIdAvailable() and to create named Olsen time zones. This is usually the host
+ // isTimeZoneIdAvailable() and to create named IANA time zones. This is usually the host
// system, but may be different if the host resources are insufficient or if
// QT_NO_SYSTEMLOCALE is set. A simple UTC backend is used if no alternative is available.
QSharedDataPointer<QTimeZonePrivate> backend;
@@ -135,18 +135,21 @@ Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz);
\section1
- \section2 Olsen Time Zone IDs
+ \section2 IANA Time Zone IDs
- QTimeZone uses the Olsen time zone IDs as defined in the IANA Time Zone
+ QTimeZone uses the IANA time zone IDs as defined in the IANA Time Zone
Database (http://www.iana.org/time-zones). This is to ensure a standard ID
- across all supported platforms. Most platforms support the Olsen IDs
+ across all supported platforms. Most platforms support the IANA IDs
and the IANA Database natively, but for Windows a mapping is required to
the native IDs. See below for more details.
- The Olsen IDs can and do change on a regular basis, and can vary depending
+ The IANA IDs can and do change on a regular basis, and can vary depending
on how recently the host system data was updated. As such you cannot rely
on any given ID existing on any host system. You must use
- availableTimeZoneIds() to determine what Olsen IDs are available.
+ availableTimeZoneIds() to determine what IANA IDs are available.
+
+ The IANA IDs and database are also know as the Olson IDs and database,
+ named after their creator.
\section2 UTC Offset Time Zones
@@ -165,7 +168,7 @@ Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz);
the current year.
QTimeZone uses a conversion table derived form the Unicode CLDR data to map
- between Olsen IDs and Windows IDs. Depending on your version of Windows
+ between IANA IDs and Windows IDs. Depending on your version of Windows
and Qt, this table may not be able to provide a valid conversion, in which
"UTC" will be returned.
@@ -180,7 +183,7 @@ Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz);
If you require a QDateTime that uses the current system time zone at any
given moment then you should use a Qt::TimeSpec of Qt::LocalTime.
- The method systemTimeZoneId() returns the current system Olsen time zone
+ The method systemTimeZoneId() returns the current system IANA time zone
ID which on OSX and Linux will always be correct. On Windows this ID is
translated from the the Windows system ID using an internal translation
table and the user's selected country. As a consequence there is a small
@@ -323,7 +326,7 @@ QTimeZone::QTimeZone()
}
/*!
- Creates an instance of the requested time zone \a olsenId.
+ Creates an instance of the requested time zone \a ianaId.
The ID must be one of the available system IDs otherwise an invalid
time zone will be returned.
@@ -331,14 +334,14 @@ QTimeZone::QTimeZone()
\sa availableTimeZoneIds()
*/
-QTimeZone::QTimeZone(const QByteArray &olsenId)
+QTimeZone::QTimeZone(const QByteArray &ianaId)
{
// Try and see if it's a valid UTC offset ID, just as quick to try create as look-up
- d = new QUtcTimeZonePrivate(olsenId);
+ d = new QUtcTimeZonePrivate(ianaId);
// If not a valid UTC offset ID then try create it with the system backend
// Relies on backend not creating valid tz with invalid name
if (!d->isValid())
- d = newBackendTimeZone(olsenId);
+ d = newBackendTimeZone(ianaId);
}
/*!
@@ -359,14 +362,14 @@ QTimeZone::QTimeZone(int offsetSeconds)
}
/*!
- Creates a custom time zone with an ID of \a olsenId and an offset from UTC
+ Creates a custom time zone with an ID of \a ianaId and an offset from UTC
of \a offsetSeconds. The \a name will be the name used by displayName()
for the LongName, the \a abbreviation will be used by displayName() for the
ShortName and by abbreviation(), and the optional \a country will be used
by country(). The \a comment is an optional note that may be displayed in
a GUI to assist users in selecting a time zone.
- The \a olsenId must not be one of the available system IDs returned by
+ The \a ianaId must not be one of the available system IDs returned by
availableTimeZoneIds(). The \a offsetSeconds from UTC must be in the range
-14 hours to +14 hours.
@@ -374,12 +377,12 @@ QTimeZone::QTimeZone(int offsetSeconds)
default value of QLocale::AnyCountry.
*/
-QTimeZone::QTimeZone(const QByteArray &olsenId, int offsetSeconds, const QString &name,
+QTimeZone::QTimeZone(const QByteArray &ianaId, int offsetSeconds, const QString &name,
const QString &abbreviation, QLocale::Country country, const QString &comment)
{
- // olsenId must be a valid ID and must not clash with the standard system names
- if (QTimeZonePrivate::isValidId(olsenId) && !availableTimeZoneIds().contains(olsenId))
- d = new QUtcTimeZonePrivate(olsenId, offsetSeconds, name, abbreviation, country, comment);
+ // ianaId must be a valid ID and must not clash with the standard system names
+ if (QTimeZonePrivate::isValidId(ianaId) && !availableTimeZoneIds().contains(ianaId))
+ d = new QUtcTimeZonePrivate(ianaId, offsetSeconds, name, abbreviation, country, comment);
else
d = 0;
}
@@ -473,10 +476,10 @@ bool QTimeZone::isValid() const
}
/*!
- Returns the Olsen ID for the time zone.
+ Returns the IANA ID for the time zone.
- Olsen IDs are used on all platforms. On Windows these are translated
- from the Windows ID into the closest Olsen ID for the time zone and country.
+ IANA IDs are used on all platforms. On Windows these are translated
+ from the Windows ID into the closest IANA ID for the time zone and country.
*/
QByteArray QTimeZone::id() const
@@ -705,6 +708,9 @@ bool QTimeZone::hasTransitions() const
This is most useful when you have a Transition time and wish to find the
Transition after it.
+ If there is no transition after the given \a afterDateTime then an invalid
+ OffsetData will be returned with an invalid QDateTime.
+
The given \a afterDateTime is exclusive.
\sa hasTransitions(), previousTransition(), transitions()
@@ -723,6 +729,9 @@ QTimeZone::OffsetData QTimeZone::nextTransition(const QDateTime &afterDateTime)
This is most useful when you have a Transition time and wish to find the
Transition before it.
+ If there is no transition before the given \a beforeDateTime then an invalid
+ OffsetData will be returned with an invalid QDateTime.
+
The given \a beforeDateTime is exclusive.
\sa hasTransitions(), nextTransition(), transitions()
@@ -760,7 +769,7 @@ QTimeZone::OffsetDataList QTimeZone::transitions(const QDateTime &fromDateTime,
// Static methods
/*!
- Returns the current system time zone Olsen ID.
+ Returns the current system time zone IANA ID.
On Windows this ID is translated from the the Windows ID using an internal
translation table and the user's selected country. As a consequence there
@@ -774,20 +783,20 @@ QByteArray QTimeZone::systemTimeZoneId()
}
/*!
- Returns \c true if a given time zone \a olsenId is available on this system.
+ Returns \c true if a given time zone \a ianaId is available on this system.
\sa availableTimeZoneIds()
*/
-bool QTimeZone::isTimeZoneIdAvailable(const QByteArray &olsenId)
+bool QTimeZone::isTimeZoneIdAvailable(const QByteArray &ianaId)
{
// isValidId is not strictly required, but faster to weed out invalid
// IDs as availableTimeZoneIds() may be slow
- return (QTimeZonePrivate::isValidId(olsenId) && (availableTimeZoneIds().contains(olsenId)));
+ return (QTimeZonePrivate::isValidId(ianaId) && (availableTimeZoneIds().contains(ianaId)));
}
/*!
- Returns a list of all available Olsen time zone IDs on this system.
+ Returns a list of all available IANA time zone IDs on this system.
\sa isTimeZoneIdAvailable()
*/
@@ -802,7 +811,7 @@ QList<QByteArray> QTimeZone::availableTimeZoneIds()
}
/*!
- Returns a list of all available Olsen time zone IDs for a given \a country.
+ Returns a list of all available IANA time zone IDs for a given \a country.
As a special case, a \a country of Qt::AnyCountry returns those time zones
that do not have any country related to them, such as UTC. If you require
@@ -822,7 +831,7 @@ QList<QByteArray> QTimeZone::availableTimeZoneIds(QLocale::Country country)
}
/*!
- Returns a list of all available Olsen time zone IDs with a given standard
+ Returns a list of all available IANA time zone IDs with a given standard
time offset of \a offsetSeconds.
\sa isTimeZoneIdAvailable()
@@ -838,79 +847,79 @@ QList<QByteArray> QTimeZone::availableTimeZoneIds(int offsetSeconds)
}
/*!
- Returns the Windows ID equivalent to the given \a olsenId.
+ Returns the Windows ID equivalent to the given \a ianaId.
- \sa windowsIdToDefaultOlsenId(), windowsIdToOlsenIds()
+ \sa windowsIdToDefaultIanaId(), windowsIdToIanaIds()
*/
-QByteArray QTimeZone::olsenIdToWindowsId(const QByteArray &olsenId)
+QByteArray QTimeZone::ianaIdToWindowsId(const QByteArray &ianaId)
{
- return QTimeZonePrivate::olsenIdToWindowsId(olsenId);
+ return QTimeZonePrivate::ianaIdToWindowsId(ianaId);
}
/*!
- Returns the default Olsen ID for a given \a windowsId.
+ Returns the default IANA ID for a given \a windowsId.
- Because a Windows ID can cover several Olsen IDs in several different
- countries, this function returns the most frequently used Olsen ID with no
+ Because a Windows ID can cover several IANA IDs in several different
+ countries, this function returns the most frequently used IANA ID with no
regard for the country and should thus be used with care. It is usually
best to request the default for a specific country.
- \sa olsenIdToWindowsId(), windowsIdToOlsenIds()
+ \sa ianaIdToWindowsId(), windowsIdToIanaIds()
*/
-QByteArray QTimeZone::windowsIdToDefaultOlsenId(const QByteArray &windowsId)
+QByteArray QTimeZone::windowsIdToDefaultIanaId(const QByteArray &windowsId)
{
- return QTimeZonePrivate::windowsIdToDefaultOlsenId(windowsId);
+ return QTimeZonePrivate::windowsIdToDefaultIanaId(windowsId);
}
/*!
- Returns the default Olsen ID for a given \a windowsId and \a country.
+ Returns the default IANA ID for a given \a windowsId and \a country.
- Because a Windows ID can cover several Olsen IDs within a given country,
- the most frequently used Olsen ID in that country is returned.
+ Because a Windows ID can cover several IANA IDs within a given country,
+ the most frequently used IANA ID in that country is returned.
- As a special case, QLocale::AnyCountry returns the default of those Olsen IDs
+ As a special case, QLocale::AnyCountry returns the default of those IANA IDs
that do not have any specific country.
- \sa olsenIdToWindowsId(), windowsIdToOlsenIds()
+ \sa ianaIdToWindowsId(), windowsIdToIanaIds()
*/
-QByteArray QTimeZone::windowsIdToDefaultOlsenId(const QByteArray &windowsId,
+QByteArray QTimeZone::windowsIdToDefaultIanaId(const QByteArray &windowsId,
QLocale::Country country)
{
- return QTimeZonePrivate::windowsIdToDefaultOlsenId(windowsId, country);
+ return QTimeZonePrivate::windowsIdToDefaultIanaId(windowsId, country);
}
/*!
- Returns all the Olsen IDs for a given \a windowsId.
+ Returns all the IANA IDs for a given \a windowsId.
The returned list is sorted alphabetically.
- \sa olsenIdToWindowsId(), windowsIdToDefaultOlsenId()
+ \sa ianaIdToWindowsId(), windowsIdToDefaultIanaId()
*/
-QList<QByteArray> QTimeZone::windowsIdToOlsenIds(const QByteArray &windowsId)
+QList<QByteArray> QTimeZone::windowsIdToIanaIds(const QByteArray &windowsId)
{
- return QTimeZonePrivate::windowsIdToOlsenIds(windowsId);
+ return QTimeZonePrivate::windowsIdToIanaIds(windowsId);
}
/*!
- Returns all the Olsen IDs for a given \a windowsId and \a country.
+ Returns all the IANA IDs for a given \a windowsId and \a country.
- As a special case QLocale::AnyCountry returns those Olsen IDs that do
+ As a special case QLocale::AnyCountry returns those IANA IDs that do
not have any specific country.
The returned list is in order of frequency of usage, i.e. larger zones
within a country are listed first.
- \sa olsenIdToWindowsId(), windowsIdToDefaultOlsenId()
+ \sa ianaIdToWindowsId(), windowsIdToDefaultIanaId()
*/
-QList<QByteArray> QTimeZone::windowsIdToOlsenIds(const QByteArray &windowsId,
+QList<QByteArray> QTimeZone::windowsIdToIanaIds(const QByteArray &windowsId,
QLocale::Country country)
{
- return QTimeZonePrivate::windowsIdToOlsenIds(windowsId, country);
+ return QTimeZonePrivate::windowsIdToIanaIds(windowsId, country);
}
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/tools/qtimezone.h b/src/corelib/tools/qtimezone.h
index cbc4f3e4ad..b038d66a65 100644
--- a/src/corelib/tools/qtimezone.h
+++ b/src/corelib/tools/qtimezone.h
@@ -77,7 +77,7 @@ public:
typedef QVector<OffsetData> OffsetDataList;
QTimeZone();
- explicit QTimeZone(const QByteArray &olsenId);
+ explicit QTimeZone(const QByteArray &ianaId);
explicit QTimeZone(int offsetSeconds);
/*implicit*/ QTimeZone(const QByteArray &zoneId, int offsetSeconds, const QString &name,
const QString &abbreviation, QLocale::Country country = QLocale::AnyCountry,
@@ -126,18 +126,18 @@ public:
static QByteArray systemTimeZoneId();
- static bool isTimeZoneIdAvailable(const QByteArray &olsenId);
+ static bool isTimeZoneIdAvailable(const QByteArray &ianaId);
static QList<QByteArray> availableTimeZoneIds();
static QList<QByteArray> availableTimeZoneIds(QLocale::Country country);
static QList<QByteArray> availableTimeZoneIds(int offsetSeconds);
- static QByteArray olsenIdToWindowsId(const QByteArray &olsenId);
- static QByteArray windowsIdToDefaultOlsenId(const QByteArray &windowsId);
- static QByteArray windowsIdToDefaultOlsenId(const QByteArray &windowsId,
+ static QByteArray ianaIdToWindowsId(const QByteArray &ianaId);
+ static QByteArray windowsIdToDefaultIanaId(const QByteArray &windowsId);
+ static QByteArray windowsIdToDefaultIanaId(const QByteArray &windowsId,
QLocale::Country country);
- static QList<QByteArray> windowsIdToOlsenIds(const QByteArray &windowsId);
- static QList<QByteArray> windowsIdToOlsenIds(const QByteArray &windowsId,
+ static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId);
+ static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId,
QLocale::Country country);
private:
diff --git a/src/corelib/tools/qtimezoneprivate.cpp b/src/corelib/tools/qtimezoneprivate.cpp
index 8d5d60bf37..08a5ce0861 100644
--- a/src/corelib/tools/qtimezoneprivate.cpp
+++ b/src/corelib/tools/qtimezoneprivate.cpp
@@ -264,7 +264,8 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs)
// If the local msecs is less than the real local time of the transition
// then get the previous transition to use instead
if (forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
- while (forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
+ while (tran.atMSecsSinceEpoch != invalidMSecs()
+ && forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
nextTran = tran;
tran = previousTransition(tran.atMSecsSinceEpoch);
}
@@ -272,7 +273,8 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs)
// The zone msecs is after the transition, so check it is before the next tran
// If not try use the next transition instead
nextTran = nextTransition(tran.atMSecsSinceEpoch);
- while (forLocalMSecs >= nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)) {
+ while (nextTran.atMSecsSinceEpoch != invalidMSecs()
+ && forLocalMSecs >= nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)) {
tran = nextTran;
nextTran = nextTransition(tran.atMSecsSinceEpoch);
}
@@ -292,7 +294,8 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs)
// then use the prev tran as we default to the FirstOccurrence
// TODO Check if faster to just always get prev tran, or if faster using 6 hour check.
Data dstTran = previousTransition(tran.atMSecsSinceEpoch);
- if (dstTran.daylightTimeOffset > 0 && diffPrevTran < (dstTran.daylightTimeOffset * 1000))
+ if (dstTran.atMSecsSinceEpoch != invalidMSecs()
+ && dstTran.daylightTimeOffset > 0 && diffPrevTran < (dstTran.daylightTimeOffset * 1000))
tran = dstTran;
} else if (diffNextTran >= 0 && diffNextTran <= (nextTran.daylightTimeOffset * 1000)) {
// If time falls within last hour of standard time then is actually the missing hour
@@ -328,10 +331,11 @@ QTimeZonePrivate::DataList QTimeZonePrivate::transitions(qint64 fromMSecsSinceEp
qint64 toMSecsSinceEpoch) const
{
DataList list;
- if (toMSecsSinceEpoch > fromMSecsSinceEpoch) {
+ if (toMSecsSinceEpoch >= fromMSecsSinceEpoch) {
// fromMSecsSinceEpoch is inclusive but nextTransitionTime() is exclusive so go back 1 msec
Data next = nextTransition(fromMSecsSinceEpoch - 1);
- while (next.atMSecsSinceEpoch <= toMSecsSinceEpoch) {
+ while (next.atMSecsSinceEpoch != invalidMSecs()
+ && next.atMSecsSinceEpoch <= toMSecsSinceEpoch) {
list.append(next);
next = nextTransition(next.atMSecsSinceEpoch);
}
@@ -477,7 +481,7 @@ QString QTimeZonePrivate::isoOffsetFormat(int offsetFromUtc)
.arg(qAbs(mins) % 60, 2, 10, QLatin1Char('0'));
}
-QByteArray QTimeZonePrivate::olsenIdToWindowsId(const QByteArray &id)
+QByteArray QTimeZonePrivate::ianaIdToWindowsId(const QByteArray &id)
{
for (int i = 0; i < zoneDataTableSize; ++i) {
const QZoneData *data = zoneData(i);
@@ -487,7 +491,7 @@ QByteArray QTimeZonePrivate::olsenIdToWindowsId(const QByteArray &id)
return QByteArray();
}
-QByteArray QTimeZonePrivate::windowsIdToDefaultOlsenId(const QByteArray &windowsId)
+QByteArray QTimeZonePrivate::windowsIdToDefaultIanaId(const QByteArray &windowsId)
{
const quint16 windowsIdKey = toWindowsIdKey(windowsId);
for (int i = 0; i < windowsDataTableSize; ++i) {
@@ -498,17 +502,17 @@ QByteArray QTimeZonePrivate::windowsIdToDefaultOlsenId(const QByteArray &windows
return QByteArray();
}
-QByteArray QTimeZonePrivate::windowsIdToDefaultOlsenId(const QByteArray &windowsId,
+QByteArray QTimeZonePrivate::windowsIdToDefaultIanaId(const QByteArray &windowsId,
QLocale::Country country)
{
- const QList<QByteArray> list = windowsIdToOlsenIds(windowsId, country);
+ const QList<QByteArray> list = windowsIdToIanaIds(windowsId, country);
if (list.count() > 0)
return list.first();
else
return QByteArray();
}
-QList<QByteArray> QTimeZonePrivate::windowsIdToOlsenIds(const QByteArray &windowsId)
+QList<QByteArray> QTimeZonePrivate::windowsIdToIanaIds(const QByteArray &windowsId)
{
const quint16 windowsIdKey = toWindowsIdKey(windowsId);
QList<QByteArray> list;
@@ -524,7 +528,7 @@ QList<QByteArray> QTimeZonePrivate::windowsIdToOlsenIds(const QByteArray &window
return list;
}
-QList<QByteArray> QTimeZonePrivate::windowsIdToOlsenIds(const QByteArray &windowsId,
+QList<QByteArray> QTimeZonePrivate::windowsIdToIanaIds(const QByteArray &windowsId,
QLocale::Country country)
{
const quint16 windowsIdKey = toWindowsIdKey(windowsId);
diff --git a/src/corelib/tools/qtimezoneprivate_p.h b/src/corelib/tools/qtimezoneprivate_p.h
index 9f99f49fcf..108aec2654 100644
--- a/src/corelib/tools/qtimezoneprivate_p.h
+++ b/src/corelib/tools/qtimezoneprivate_p.h
@@ -146,12 +146,12 @@ public:
static bool isValidId(const QByteArray &olsenId);
static QString isoOffsetFormat(int offsetFromUtc);
- static QByteArray olsenIdToWindowsId(const QByteArray &olsenId);
- static QByteArray windowsIdToDefaultOlsenId(const QByteArray &windowsId);
- static QByteArray windowsIdToDefaultOlsenId(const QByteArray &windowsId,
+ static QByteArray ianaIdToWindowsId(const QByteArray &ianaId);
+ static QByteArray windowsIdToDefaultIanaId(const QByteArray &windowsId);
+ static QByteArray windowsIdToDefaultIanaId(const QByteArray &windowsId,
QLocale::Country country);
- static QList<QByteArray> windowsIdToOlsenIds(const QByteArray &windowsId);
- static QList<QByteArray> windowsIdToOlsenIds(const QByteArray &windowsId,
+ static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId);
+ static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId,
QLocale::Country country);
protected:
@@ -309,6 +309,7 @@ private:
bool operator==(const QTzTransitionRule &other) { return (stdOffset == other.stdOffset
&& dstOffset == other.dstOffset && abbreviationIndex == other.abbreviationIndex); }
};
+ Data dataForTzTransition(QTzTransitionTime tran) const;
QList<QTzTransitionTime> m_tranTimes;
QList<QTzTransitionRule> m_tranRules;
QList<QByteArray> m_abbreviations;
diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp
index 4bf19178fa..1fb6bb1b5a 100644
--- a/src/corelib/tools/qtimezoneprivate_tz.cpp
+++ b/src/corelib/tools/qtimezoneprivate_tz.cpp
@@ -149,11 +149,13 @@ static QTzHeader parseTzHeader(QDataStream &ds, bool *ok)
if (memcmp(hdr.tzh_magic, TZ_MAGIC, 4) != 0 || ds.status() != QDataStream::Ok)
return hdr;
- // Parse Version, 1 byte, before 2005 was '\0', since 2005 a '2'
+ // Parse Version, 1 byte, before 2005 was '\0', since 2005 a '2', since 2013 a '3'
ds >> ch;
hdr.tzh_version = ch;
- if (ds.status() != QDataStream::Ok || (hdr.tzh_version != '2' && hdr.tzh_version != '\0'))
+ if (ds.status() != QDataStream::Ok
+ || (hdr.tzh_version != '2' && hdr.tzh_version != '\0' && hdr.tzh_version != '3')) {
return hdr;
+ }
// Parse reserved space, 15 bytes
ds.readRawData(hdr.tzh_reserved, 15);
@@ -238,30 +240,31 @@ static QList<QTzType> parseTzTypes(QDataStream &ds, int tzh_typecnt)
return typeList;
}
-static QMap<int, QByteArray> parseTzAbbreviations(QDataStream &ds, int tzh_charcnt)
+static QMap<int, QByteArray> parseTzAbbreviations(QDataStream &ds, int tzh_charcnt, QList<QTzType> typeList)
{
// Parse the abbreviation list which is tzh_charcnt long with '\0' separated strings. The
- // tz_abbrind index points to the first char of the abbreviation in the array, not the
- // occurrence in the list. By parsing char at a time we can track the char index and convert
- // to an occurrence index. By using a map with tz_abbrind as ordered key we get both index
+ // QTzType.tz_abbrind index points to the first char of the abbreviation in the array, not the
+ // occurrence in the list. It can also point to a partial string so we need to use the actual typeList
+ // index values when parsing. By using a map with tz_abbrind as ordered key we get both index
// methods in one data structure and can convert the types afterwards.
QMap<int, QByteArray> map;
quint8 ch;
- QByteArray abbrev;
- // Track the start position of each abbreviation
- int tz_abbrind = 0;
+ QByteArray input;
+ // First parse the full abbrev string
for (int i = 0; i < tzh_charcnt && ds.status() == QDataStream::Ok; ++i) {
ds >> ch;
- if (ds.status() == QDataStream::Ok) {
- if (ch == '\0') {
- // Have reached end of an abbreviation, so add to map
- map[tz_abbrind] = abbrev;
- tz_abbrind = i + 1;
- abbrev.clear();
- } else {
- abbrev.append((char)ch);
- }
- }
+ if (ds.status() == QDataStream::Ok)
+ input.append(char(ch));
+ else
+ return map;
+ }
+ // Then extract all the substrings pointed to by typeList
+ foreach (const QTzType type, typeList) {
+ QByteArray abbrev;
+ for (int i = type.tz_abbrind; input.at(i) != '\0'; ++i)
+ abbrev.append(input.at(i));
+ // Have reached end of an abbreviation, so add to map
+ map[type.tz_abbrind] = abbrev;
}
return map;
}
@@ -371,7 +374,7 @@ static QDate calculatePosixDate(const QByteArray dateRule, int year)
}
}
-static QTime parsePosixTime(const QByteArray timeRule)
+static QTime parsePosixTime(const QByteArray &timeRule)
{
// Format "HH:mm:ss", put check parts count just in case
QList<QByteArray> parts = timeRule.split(':');
@@ -385,7 +388,7 @@ static QTime parsePosixTime(const QByteArray timeRule)
return QTime(2, 0, 0);
}
-static int parsePosixOffset(const QByteArray timeRule)
+static int parsePosixOffset(const QByteArray &timeRule)
{
// Format "[+|-]hh[:mm[:ss]]"
QList<QByteArray> parts = timeRule.split(':');
@@ -399,7 +402,9 @@ static int parsePosixOffset(const QByteArray timeRule)
return 0;
}
-static QList<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray &posixRule, int startYear, int endYear)
+static QList<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray &posixRule,
+ int startYear, int endYear,
+ int lastTranMSecs)
{
QList<QTimeZonePrivate::Data> list;
@@ -443,11 +448,13 @@ static QList<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray
// If only the name part then no transitions
if (parts.count() == 1) {
QTimeZonePrivate::Data data;
- data.atMSecsSinceEpoch = 0;
+ data.atMSecsSinceEpoch = lastTranMSecs;
data.offsetFromUtc = utcOffset;
data.standardTimeOffset = utcOffset;
data.daylightTimeOffset = 0;
data.abbreviation = stdName;
+ list << data;
+ return list;
}
// If not populated the total dst offset is 1 hour
@@ -572,7 +579,7 @@ void QTzTimeZonePrivate::init(const QByteArray &olsenId)
QList<QTzType> typeList = parseTzTypes(ds, hdr.tzh_typecnt);
if (ds.status() != QDataStream::Ok)
return;
- QMap<int, QByteArray> abbrevMap = parseTzAbbreviations(ds, hdr.tzh_charcnt);
+ QMap<int, QByteArray> abbrevMap = parseTzAbbreviations(ds, hdr.tzh_charcnt, typeList);
if (ds.status() != QDataStream::Ok)
return;
parseTzLeapSeconds(ds, hdr.tzh_leapcnt, false);
@@ -583,7 +590,7 @@ void QTzTimeZonePrivate::init(const QByteArray &olsenId)
return;
// If version 2 then parse the second block of data
- if (hdr.tzh_version == '2') {
+ if (hdr.tzh_version == '2' || hdr.tzh_version == '3') {
ok = false;
QTzHeader hdr2 = parseTzHeader(ds, &ok);
if (!ok || ds.status() != QDataStream::Ok)
@@ -594,7 +601,7 @@ void QTzTimeZonePrivate::init(const QByteArray &olsenId)
typeList = parseTzTypes(ds, hdr2.tzh_typecnt);
if (ds.status() != QDataStream::Ok)
return;
- abbrevMap = parseTzAbbreviations(ds, hdr2.tzh_charcnt);
+ abbrevMap = parseTzAbbreviations(ds, hdr2.tzh_charcnt, typeList);
if (ds.status() != QDataStream::Ok)
return;
parseTzLeapSeconds(ds, hdr2.tzh_leapcnt, true);
@@ -682,12 +689,14 @@ QString QTzTimeZonePrivate::displayName(qint64 atMSecsSinceEpoch,
if (!m_icu)
m_icu = new QIcuTimeZonePrivate(m_id);
// TODO small risk may not match if tran times differ due to outdated files
- return m_icu->displayName(atMSecsSinceEpoch, nameType, locale);
+ // TODO Some valid TZ names are not valid ICU names, use translation table?
+ if (m_icu->isValid())
+ return m_icu->displayName(atMSecsSinceEpoch, nameType, locale);
#else
Q_UNUSED(nameType)
Q_UNUSED(locale)
- return abbreviation(atMSecsSinceEpoch);
#endif // QT_USE_ICU
+ return abbreviation(atMSecsSinceEpoch);
}
QString QTzTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
@@ -698,19 +707,59 @@ QString QTzTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
if (!m_icu)
m_icu = new QIcuTimeZonePrivate(m_id);
// TODO small risk may not match if tran times differ due to outdated files
- return m_icu->displayName(timeType, nameType, locale);
+ // TODO Some valid TZ names are not valid ICU names, use translation table?
+ if (m_icu->isValid())
+ return m_icu->displayName(timeType, nameType, locale);
#else
Q_UNUSED(timeType)
Q_UNUSED(nameType)
Q_UNUSED(locale)
- const int atMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch();
- QTimeZonePrivate::Data tran = data(atMSecsSinceEpoch);
- while ((timeType == QTimeZone::StandardTime && tran.daylightTimeOffset != 0)
- || (timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset == 0)) {
- tran = nextTransition(tran.atMSecsSinceEpoch);
- }
- return tran.abbreviation;
#endif // QT_USE_ICU
+ // If no ICU available then have to use abbreviations instead
+ // Abbreviations don't have GenericTime
+ if (timeType == QTimeZone::GenericTime)
+ timeType = QTimeZone::StandardTime;
+
+ // Get current tran, if valid and is what we want, then use it
+ const qint64 currentMSecs = QDateTime::currentMSecsSinceEpoch();
+ QTimeZonePrivate::Data tran = data(currentMSecs);
+ if (tran.atMSecsSinceEpoch != invalidMSecs()
+ && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0)
+ || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) {
+ return tran.abbreviation;
+ }
+
+ // Otherwise get next tran and if valid and is what we want, then use it
+ tran = nextTransition(currentMSecs);
+ if (tran.atMSecsSinceEpoch != invalidMSecs()
+ && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0)
+ || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) {
+ return tran.abbreviation;
+ }
+
+ // Otherwise get prev tran and if valid and is what we want, then use it
+ tran = previousTransition(currentMSecs);
+ if (tran.atMSecsSinceEpoch != invalidMSecs())
+ tran = previousTransition(tran.atMSecsSinceEpoch);
+ if (tran.atMSecsSinceEpoch != invalidMSecs()
+ && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0)
+ || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) {
+ return tran.abbreviation;
+ }
+
+ // Otherwise is strange sequence, so work backwards through trans looking for first match, if any
+ for (int i = m_tranTimes.size() - 1; i >= 0; --i) {
+ if (m_tranTimes.at(i).atMSecsSinceEpoch <= currentMSecs) {
+ tran = dataForTzTransition(m_tranTimes.at(i));
+ if ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0)
+ || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0)) {
+ return tran.abbreviation;
+ }
+ }
+ }
+
+ // Otherwise if no match use current data
+ return data(currentMSecs).abbreviation;
}
QString QTzTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch) const
@@ -749,35 +798,55 @@ bool QTzTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch) const
return (daylightTimeOffset(atMSecsSinceEpoch) != 0);
}
+QTimeZonePrivate::Data QTzTimeZonePrivate::dataForTzTransition(QTzTransitionTime tran) const
+{
+ QTimeZonePrivate::Data data;
+ data.atMSecsSinceEpoch = tran.atMSecsSinceEpoch;
+ QTzTransitionRule rule = m_tranRules.at(tran.ruleIndex);
+ data.standardTimeOffset = rule.stdOffset;
+ data.daylightTimeOffset = rule.dstOffset;
+ data.offsetFromUtc = rule.stdOffset + rule.dstOffset;
+ data.abbreviation = QString::fromUtf8(m_abbreviations.at(rule.abbreviationIndex));
+ return data;
+}
+
QTimeZonePrivate::Data QTzTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
{
- QTimeZonePrivate::Data data = invalidData();
- int lastTran = m_tranTimes.size() - 1;
- int tran;
- for (tran = lastTran; tran > 0; --tran) {
- if (m_tranTimes.at(tran).atMSecsSinceEpoch <= forMSecsSinceEpoch)
- break;
- }
- // If after the last transition time then we need to use the posix rule if available
- if (tran >= lastTran && !m_posixRule.isEmpty()) {
- QDateTime dt = QDateTime::fromMSecsSinceEpoch(forMSecsSinceEpoch);
- int year = dt.date().year();
- QList<QTimeZonePrivate::Data> posixTrans = calculatePosixTransitions(m_posixRule, year - 1, year + 1);
- for (int i = posixTrans.size() - 1; i > 0; --i) {
+ // If the required time is after the last transition and we have a POSIX rule then use it
+ if (m_tranTimes.size() > 0 && m_tranTimes.last().atMSecsSinceEpoch < forMSecsSinceEpoch
+ &&!m_posixRule.isEmpty() && forMSecsSinceEpoch >= 0) {
+ const int year = QDateTime::fromMSecsSinceEpoch(forMSecsSinceEpoch, Qt::UTC).date().year();
+ const int lastMSecs = (m_tranTimes.size() > 0) ? m_tranTimes.last().atMSecsSinceEpoch : 0;
+ QList<QTimeZonePrivate::Data> posixTrans = calculatePosixTransitions(m_posixRule, year - 1,
+ year + 1, lastMSecs);
+ for (int i = posixTrans.size() - 1; i >= 0; --i) {
if (posixTrans.at(i).atMSecsSinceEpoch <= forMSecsSinceEpoch) {
+ QTimeZonePrivate::Data data;
data = posixTrans.at(i);
data.atMSecsSinceEpoch = forMSecsSinceEpoch;
return data;
}
}
}
- data.atMSecsSinceEpoch = forMSecsSinceEpoch;
- QTzTransitionRule rule = m_tranRules.at(m_tranTimes.at(tran).ruleIndex);
- data.standardTimeOffset = rule.stdOffset;
- data.daylightTimeOffset = rule.dstOffset;
- data.offsetFromUtc = rule.stdOffset + rule.dstOffset;
- data.abbreviation = QString::fromUtf8(m_abbreviations.at(rule.abbreviationIndex));
- return data;
+
+ // Otherwise if we can find a valid tran then use its rule
+ for (int i = m_tranTimes.size() - 1; i >= 0; --i) {
+ if (m_tranTimes.at(i).atMSecsSinceEpoch <= forMSecsSinceEpoch) {
+ Data data = dataForTzTransition(m_tranTimes.at(i));
+ data.atMSecsSinceEpoch = forMSecsSinceEpoch;
+ return data;
+ }
+ }
+
+ // Otherwise use the earliest transition we have
+ if (m_tranTimes.size() > 0) {
+ Data data = dataForTzTransition(m_tranTimes.at(0));
+ data.atMSecsSinceEpoch = forMSecsSinceEpoch;
+ return data;
+ }
+
+ // Otherwise we have no rules, so probably an invalid tz, so return invalid data
+ return invalidData();
}
bool QTzTimeZonePrivate::hasTransitions() const
@@ -787,60 +856,54 @@ bool QTzTimeZonePrivate::hasTransitions() const
QTimeZonePrivate::Data QTzTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch) const
{
- int lastTran = m_tranTimes.size() - 1;
- int tran;
- for (tran = 0; tran < lastTran; ++tran) {
- if (m_tranTimes.at(tran).atMSecsSinceEpoch > afterMSecsSinceEpoch)
- break;
- }
- // If after the last transition time then we need to use the posix rule if available
- if (tran >= lastTran && !m_posixRule.isEmpty()) {
- QDateTime dt = QDateTime::fromMSecsSinceEpoch(afterMSecsSinceEpoch);
- int year = dt.date().year();
- QList<QTimeZonePrivate::Data> posixTrans = calculatePosixTransitions(m_posixRule, year - 1, year + 1);
- for (int i = 0; i < posixTrans.size() - 1; ++i) {
+ // If the required time is after the last transition and we have a POSIX rule then use it
+ if (m_tranTimes.size() > 0 && m_tranTimes.last().atMSecsSinceEpoch < afterMSecsSinceEpoch
+ &&!m_posixRule.isEmpty() && afterMSecsSinceEpoch >= 0) {
+ const int year = QDateTime::fromMSecsSinceEpoch(afterMSecsSinceEpoch, Qt::UTC).date().year();
+ const int lastMSecs = (m_tranTimes.size() > 0) ? m_tranTimes.last().atMSecsSinceEpoch : 0;
+ QList<QTimeZonePrivate::Data> posixTrans = calculatePosixTransitions(m_posixRule, year - 1,
+ year + 1, lastMSecs);
+ for (int i = 0; i < posixTrans.size(); ++i) {
if (posixTrans.at(i).atMSecsSinceEpoch > afterMSecsSinceEpoch)
return posixTrans.at(i);
}
}
- // Otherwise use the transition we found
- QTimeZonePrivate::Data data;
- data.atMSecsSinceEpoch = m_tranTimes.at(tran).atMSecsSinceEpoch;
- QTzTransitionRule rule = m_tranRules.at(m_tranTimes.at(tran).ruleIndex);
- data.standardTimeOffset = rule.stdOffset;
- data.daylightTimeOffset = rule.dstOffset;
- data.offsetFromUtc = rule.stdOffset + rule.dstOffset;
- data.abbreviation = QString::fromUtf8(m_abbreviations.at(rule.abbreviationIndex));
- return data;
+
+ // Otherwise if we can find a valid tran then use its rule
+ for (int i = 0; i < m_tranTimes.size(); ++i) {
+ if (m_tranTimes.at(i).atMSecsSinceEpoch > afterMSecsSinceEpoch) {
+ return dataForTzTransition(m_tranTimes.at(i));
+ }
+ }
+
+ // Otherwise we have no rule, or there is no next transition, so return invalid data
+ return invalidData();
}
QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const
{
- int lastTran = m_tranTimes.size() - 1;
- int tran;
- for (tran = lastTran; tran > 0; --tran) {
- if (m_tranTimes.at(tran).atMSecsSinceEpoch < beforeMSecsSinceEpoch)
- break;
- }
- // If after the last transition time then we need to use the posix rule if available
- if (tran >= lastTran && !m_posixRule.isEmpty()) {
- QDateTime dt = QDateTime::fromMSecsSinceEpoch(beforeMSecsSinceEpoch);
- int year = dt.date().year();
- QList<QTimeZonePrivate::Data> posixTrans = calculatePosixTransitions(m_posixRule, year - 1, year + 1);
- for (int i = posixTrans.size() - 1; i > 0; --i) {
+ // If the required time is after the last transition and we have a POSIX rule then use it
+ if (m_tranTimes.size() > 0 && m_tranTimes.last().atMSecsSinceEpoch < beforeMSecsSinceEpoch
+ &&!m_posixRule.isEmpty() && beforeMSecsSinceEpoch > 0) {
+ const int year = QDateTime::fromMSecsSinceEpoch(beforeMSecsSinceEpoch, Qt::UTC).date().year();
+ const int lastMSecs = (m_tranTimes.size() > 0) ? m_tranTimes.last().atMSecsSinceEpoch : 0;
+ QList<QTimeZonePrivate::Data> posixTrans = calculatePosixTransitions(m_posixRule, year - 1,
+ year + 1, lastMSecs);
+ for (int i = posixTrans.size() - 1; i >= 0; --i) {
if (posixTrans.at(i).atMSecsSinceEpoch < beforeMSecsSinceEpoch)
return posixTrans.at(i);
}
}
- // Otherwise use the transition we found
- QTimeZonePrivate::Data data;
- data.atMSecsSinceEpoch = m_tranTimes.at(tran).atMSecsSinceEpoch;
- QTzTransitionRule rule = m_tranRules.at(m_tranTimes.at(tran).ruleIndex);
- data.standardTimeOffset = rule.stdOffset;
- data.daylightTimeOffset = rule.dstOffset;
- data.offsetFromUtc = rule.stdOffset + rule.dstOffset;
- data.abbreviation = QString::fromUtf8(m_abbreviations.at(rule.abbreviationIndex));
- return data;
+
+ // Otherwise if we can find a valid tran then use its rule
+ for (int i = m_tranTimes.size() - 1; i >= 0; --i) {
+ if (m_tranTimes.at(i).atMSecsSinceEpoch < beforeMSecsSinceEpoch) {
+ return dataForTzTransition(m_tranTimes.at(i));
+ }
+ }
+
+ // Otherwise we have no rule, so return invalid data
+ return invalidData();
}
// TODO Could cache the value and monitor the required files for any changes
diff --git a/src/corelib/tools/qtimezoneprivate_win.cpp b/src/corelib/tools/qtimezoneprivate_win.cpp
index f411d35b3d..04588b2ba8 100644
--- a/src/corelib/tools/qtimezoneprivate_win.cpp
+++ b/src/corelib/tools/qtimezoneprivate_win.cpp
@@ -305,7 +305,7 @@ static void calculateTransitionsForYear(const QWinTimeZonePrivate::QWinTransitio
QDate daylightDate = calculateTransitionLocalDate(rule.daylightTimeRule, year);
QTime daylightTime = QTime(rule.daylightTimeRule.wHour, rule.daylightTimeRule.wMinute,
rule.daylightTimeRule.wSecond);
- if (standardDate.isValid() && standardTime.isValid())
+ if (daylightDate.isValid() && daylightTime.isValid())
*dstMSecs = timeToMSecs(daylightDate, daylightTime) + (rule.standardTimeBias * 60000);
else
*dstMSecs = QTimeZonePrivate::invalidMSecs();
@@ -362,7 +362,7 @@ void QWinTimeZonePrivate::init(const QByteArray &olsenId)
m_windowsId = windowsSystemZoneId();
m_id = systemTimeZoneId();
} else {
- m_windowsId = olsenIdToWindowsId(olsenId);
+ m_windowsId = ianaIdToWindowsId(olsenId);
m_id = olsenId;
}
@@ -488,6 +488,9 @@ QTimeZonePrivate::Data QWinTimeZonePrivate::data(qint64 forMSecsSinceEpoch) cons
do {
// Convert the transition rules into msecs for the year we want to try
rule = ruleForYear(year);
+ // If no transition rules to calculate then no DST, so just use rule for std
+ if (rule.standardTimeRule.wMonth == 0 && rule.daylightTimeRule.wMonth == 0)
+ break;
calculateTransitionsForYear(rule, year, &stdMSecs, &dstMSecs);
if (stdMSecs < dstMSecs) {
first = stdMSecs;
@@ -543,6 +546,9 @@ QTimeZonePrivate::Data QWinTimeZonePrivate::nextTransition(qint64 afterMSecsSinc
do {
// Convert the transition rules into msecs for the year we want to try
rule = ruleForYear(year);
+ // If no transition rules to calculate then no next transition
+ if (rule.standardTimeRule.wMonth == 0 && rule.daylightTimeRule.wMonth == 0)
+ return invalidData();
calculateTransitionsForYear(rule, year, &stdMSecs, &dstMSecs);
// Find the first and second transition for the year
if (stdMSecs < dstMSecs) {
@@ -591,6 +597,9 @@ QTimeZonePrivate::Data QWinTimeZonePrivate::previousTransition(qint64 beforeMSec
do {
// Convert the transition rules into msecs for the year we want to try
rule = ruleForYear(year);
+ // If no transition rules to calculate then no previous transition
+ if (rule.standardTimeRule.wMonth == 0 && rule.daylightTimeRule.wMonth == 0)
+ return invalidData();
calculateTransitionsForYear(rule, year, &stdMSecs, &dstMSecs);
if (stdMSecs < dstMSecs) {
first = stdMSecs;
@@ -620,10 +629,10 @@ QByteArray QWinTimeZonePrivate::systemTimeZoneId() const
QByteArray olsenId;
// If we have a real country, then try get a specific match for that country
if (country != QLocale::AnyCountry)
- olsenId = windowsIdToDefaultOlsenId(windowsId, country);
+ olsenId = windowsIdToDefaultIanaId(windowsId, country);
// If we don't have a real country, or there wasn't a specific match, try the global default
if (olsenId.isEmpty()) {
- olsenId = windowsIdToDefaultOlsenId(windowsId);
+ olsenId = windowsIdToDefaultIanaId(windowsId);
// If no global default then probably an unknown Windows ID so return UTC
if (olsenId.isEmpty())
return QByteArrayLiteral("UTC");
@@ -635,7 +644,7 @@ QSet<QByteArray> QWinTimeZonePrivate::availableTimeZoneIds() const
{
QSet<QByteArray> set;
foreach (const QByteArray &winId, availableWindowsIds()) {
- foreach (const QByteArray &olsenId, windowsIdToOlsenIds(winId))
+ foreach (const QByteArray &olsenId, windowsIdToIanaIds(winId))
set << olsenId;
}
return set;