summaryrefslogtreecommitdiffstats
path: root/src/corelib/time
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/time')
-rw-r--r--src/corelib/time/qdatetime.cpp2
-rw-r--r--src/corelib/time/qdatetimeparser.cpp4
-rw-r--r--src/corelib/time/qdatetimeparser_p.h2
-rw-r--r--src/corelib/time/qtimezone.cpp23
-rw-r--r--src/corelib/time/qtimezoneprivate.cpp48
-rw-r--r--src/corelib/time/qtimezoneprivate_p.h3
6 files changed, 69 insertions, 13 deletions
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp
index 9b0bc688c9..c833c18809 100644
--- a/src/corelib/time/qdatetime.cpp
+++ b/src/corelib/time/qdatetime.cpp
@@ -3266,7 +3266,7 @@ inline QDateTime::Data::Data(Qt::TimeSpec spec)
// the structure is too small, we need to detach
d = new QDateTimePrivate;
d->ref.ref();
- d->m_status = mergeSpec(nullptr, spec);
+ d->m_status = mergeSpec({}, spec);
}
}
diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp
index 74db2bdfd5..2501bbaab7 100644
--- a/src/corelib/time/qdatetimeparser.cpp
+++ b/src/corelib/time/qdatetimeparser.cpp
@@ -405,7 +405,7 @@ bool QDateTimeParser::parseFormat(const QString &newFormat)
QDTPDEBUGN("parseFormat: %s", newFormat.toLatin1().constData());
QVector<SectionNode> newSectionNodes;
- Sections newDisplay = 0;
+ Sections newDisplay;
QStringList newSeparators;
int i, index = 0;
int add = 0;
@@ -1797,7 +1797,7 @@ int QDateTimeParser::SectionNode::maxChange() const
QDateTimeParser::FieldInfo QDateTimeParser::fieldInfo(int index) const
{
- FieldInfo ret = 0;
+ FieldInfo ret;
const SectionNode &sn = sectionNode(index);
switch (sn.type) {
case MSecSection:
diff --git a/src/corelib/time/qdatetimeparser_p.h b/src/corelib/time/qdatetimeparser_p.h
index e9f1455380..ec4e4e4df2 100644
--- a/src/corelib/time/qdatetimeparser_p.h
+++ b/src/corelib/time/qdatetimeparser_p.h
@@ -84,7 +84,7 @@ public:
DateTimeEdit
};
QDateTimeParser(QVariant::Type t, Context ctx, const QCalendar &cal = QCalendar())
- : currentSectionIndex(-1), display(nullptr), cachedDay(-1), parserType(t),
+ : currentSectionIndex(-1), cachedDay(-1), parserType(t),
fixday(false), spec(Qt::LocalTime), context(ctx), calendar(cal)
{
defaultLocale = QLocale::system();
diff --git a/src/corelib/time/qtimezone.cpp b/src/corelib/time/qtimezone.cpp
index ef323de14a..410a16e3c5 100644
--- a/src/corelib/time/qtimezone.cpp
+++ b/src/corelib/time/qtimezone.cpp
@@ -325,20 +325,33 @@ QTimeZone::QTimeZone() noexcept
/*!
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.
+ The ID must be one of the available system IDs or a valid UTC-with-offset
+ ID, otherwise an invalid time zone will be returned.
\sa availableTimeZoneIds()
*/
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
+ // Try and see if it's a CLDR UTC offset ID - just as quick by creating as
+ // by looking up.
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 not a CLDR UTC offset ID then try creating it with the system backend.
+ // Relies on backend not creating valid TZ with invalid name.
if (!d->isValid())
d = newBackendTimeZone(ianaId);
+ // Can also handle UTC with arbitrary (valid) offset, but only do so as
+ // fall-back, since either of the above may handle it more informatively.
+ if (!d->isValid()) {
+ qint64 offset = QUtcTimeZonePrivate::offsetFromUtcString(ianaId);
+ if (offset != QTimeZonePrivate::invalidSeconds()) {
+ // Should have abs(offset) < 24 * 60 * 60 = 86400.
+ qint32 seconds = qint32(offset);
+ Q_ASSERT(qint64(seconds) == offset);
+ // NB: this canonicalises the name, so it might not match ianaId
+ d = new QUtcTimeZonePrivate(seconds);
+ }
+ }
}
/*!
diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp
index 00dc8b4ced..7d6ef0a404 100644
--- a/src/corelib/time/qtimezoneprivate.cpp
+++ b/src/corelib/time/qtimezoneprivate.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2013 John Layt <jlayt@kde.org>
** Contact: https://www.qt.io/licensing/
**
@@ -767,6 +768,39 @@ QUtcTimeZonePrivate::QUtcTimeZonePrivate(const QByteArray &id)
}
}
+qint64 QUtcTimeZonePrivate::offsetFromUtcString(const QByteArray &id)
+{
+ // Convert reasonable UTC[+-]\d+(:\d+){,2} to offset in seconds.
+ // Assumption: id has already been tried as a CLDR UTC offset ID (notably
+ // including plain "UTC" itself) and a system offset ID; it's neither.
+ if (!id.startsWith("UTC") || id.size() < 5)
+ return invalidSeconds(); // Doesn't match
+ const char signChar = id.at(3);
+ if (signChar != '-' && signChar != '+')
+ return invalidSeconds(); // No sign
+ const int sign = signChar == '-' ? -1 : 1;
+
+ const auto offsets = id.mid(4).split(':');
+ if (offsets.isEmpty() || offsets.size() > 3)
+ return invalidSeconds(); // No numbers, or too many.
+
+ qint32 seconds = 0;
+ int prior = 0; // Number of fields parsed thus far
+ for (const auto &offset : offsets) {
+ bool ok = false;
+ unsigned short field = offset.toUShort(&ok);
+ // Bound hour above at 24, minutes and seconds at 60:
+ if (!ok || field >= (prior ? 60 : 24))
+ return invalidSeconds();
+ seconds = seconds * 60 + field;
+ ++prior;
+ }
+ while (prior++ < 3)
+ seconds *= 60;
+
+ return seconds * sign;
+}
+
// Create offset from UTC
QUtcTimeZonePrivate::QUtcTimeZonePrivate(qint32 offsetSeconds)
{
@@ -880,22 +914,25 @@ QByteArray QUtcTimeZonePrivate::systemTimeZoneId() const
bool QUtcTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const
{
+ // Only the zone IDs supplied by CLDR and recognized by constructor.
for (int i = 0; i < utcDataTableSize; ++i) {
const QUtcData *data = utcData(i);
- if (utcId(data) == ianaId) {
+ if (utcId(data) == ianaId)
return true;
- }
}
+ // But see offsetFromUtcString(), which lets us accept some "unavailable" IDs.
return false;
}
QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds() const
{
+ // Only the zone IDs supplied by CLDR and recognized by constructor.
QList<QByteArray> result;
result.reserve(utcDataTableSize);
for (int i = 0; i < utcDataTableSize; ++i)
result << utcId(utcData(i));
- std::sort(result.begin(), result.end()); // ### or already sorted??
+ // Not guaranteed to be sorted, so sort:
+ std::sort(result.begin(), result.end());
// ### assuming no duplicates
return result;
}
@@ -910,13 +947,16 @@ QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds(QLocale::Country cou
QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds(qint32 offsetSeconds) const
{
+ // Only if it's present in CLDR. (May get more than one ID: UTC, UTC+00:00
+ // and UTC-00:00 all have the same offset.)
QList<QByteArray> result;
for (int i = 0; i < utcDataTableSize; ++i) {
const QUtcData *data = utcData(i);
if (data->offsetFromUtc == offsetSeconds)
result << utcId(data);
}
- std::sort(result.begin(), result.end()); // ### or already sorted??
+ // Not guaranteed to be sorted, so sort:
+ std::sort(result.begin(), result.end());
// ### assuming no duplicates
return result;
}
diff --git a/src/corelib/time/qtimezoneprivate_p.h b/src/corelib/time/qtimezoneprivate_p.h
index 5f6491ef81..a57f61f381 100644
--- a/src/corelib/time/qtimezoneprivate_p.h
+++ b/src/corelib/time/qtimezoneprivate_p.h
@@ -188,6 +188,9 @@ public:
QUtcTimeZonePrivate(const QUtcTimeZonePrivate &other);
virtual ~QUtcTimeZonePrivate();
+ // Fall-back for UTC[+-]\d+(:\d+){,2} IDs.
+ static qint64 offsetFromUtcString(const QByteArray &id);
+
QUtcTimeZonePrivate *clone() const override;
Data data(qint64 forMSecsSinceEpoch) const override;