diff options
Diffstat (limited to 'src/corelib/time')
-rw-r--r-- | src/corelib/time/qdatetime.cpp | 6 | ||||
-rw-r--r-- | src/corelib/time/qdatetimeparser.cpp | 6 | ||||
-rw-r--r-- | src/corelib/time/qdatetimeparser_p.h | 2 | ||||
-rw-r--r-- | src/corelib/time/qtimezone.cpp | 25 | ||||
-rw-r--r-- | src/corelib/time/qtimezoneprivate.cpp | 48 | ||||
-rw-r--r-- | src/corelib/time/qtimezoneprivate_icu.cpp | 12 | ||||
-rw-r--r-- | src/corelib/time/qtimezoneprivate_p.h | 3 | ||||
-rw-r--r-- | src/corelib/time/qtimezoneprivate_tz.cpp | 2 |
8 files changed, 80 insertions, 24 deletions
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index a8d643d483..67d37f19d8 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1794,7 +1794,7 @@ QDate QDate::fromString(const QString &string, const QString &format, QCalendar QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString, cal); // dt.setDefaultLocale(QLocale::c()); ### Qt 6 if (dt.parseFormat(format)) - dt.fromString(string, &date, 0); + dt.fromString(string, &date, nullptr); #else Q_UNUSED(string); Q_UNUSED(format); @@ -2540,7 +2540,7 @@ QTime QTime::fromString(const QString &string, const QString &format) QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString, QCalendar()); // dt.setDefaultLocale(QLocale::c()); ### Qt 6 if (dt.parseFormat(format)) - dt.fromString(string, 0, &time); + dt.fromString(string, nullptr, &time); #else Q_UNUSED(string); Q_UNUSED(format); @@ -3307,7 +3307,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 2636928e69..31d8e6cc20 100644 --- a/src/corelib/time/qdatetimeparser.cpp +++ b/src/corelib/time/qdatetimeparser.cpp @@ -404,7 +404,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; @@ -1151,7 +1151,7 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, } pos += separator.size(); sectionNodes[index].pos = pos; - int *current = 0; + int *current = nullptr; const SectionNode sn = sectionNodes.at(index); ParsedSection sect; @@ -1796,7 +1796,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..3d2078087b 100644 --- a/src/corelib/time/qtimezone.cpp +++ b/src/corelib/time/qtimezone.cpp @@ -318,27 +318,40 @@ Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz); */ QTimeZone::QTimeZone() noexcept - : d(0) + : d(nullptr) { } /*! 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 cb019fa1a5..facdf6661d 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/ ** @@ -764,6 +765,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) { @@ -877,22 +911,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; } @@ -907,13 +944,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_icu.cpp b/src/corelib/time/qtimezoneprivate_icu.cpp index 5570ce7571..8a92bbb387 100644 --- a/src/corelib/time/qtimezoneprivate_icu.cpp +++ b/src/corelib/time/qtimezoneprivate_icu.cpp @@ -273,7 +273,7 @@ static int ucalDaylightOffset(const QByteArray &id) // Create the system default time zone QIcuTimeZonePrivate::QIcuTimeZonePrivate() - : m_ucal(0) + : m_ucal(nullptr) { // TODO No ICU C API to obtain sysem tz, assume default hasn't been changed init(ucalDefaultTimeZoneId()); @@ -281,7 +281,7 @@ QIcuTimeZonePrivate::QIcuTimeZonePrivate() // Create a named time zone QIcuTimeZonePrivate::QIcuTimeZonePrivate(const QByteArray &ianaId) - : m_ucal(0) + : m_ucal(nullptr) { // Need to check validity here as ICu will create a GMT tz if name is invalid if (availableTimeZoneIds().contains(ianaId)) @@ -289,14 +289,14 @@ QIcuTimeZonePrivate::QIcuTimeZonePrivate(const QByteArray &ianaId) } QIcuTimeZonePrivate::QIcuTimeZonePrivate(const QIcuTimeZonePrivate &other) - : QTimeZonePrivate(other), m_ucal(0) + : QTimeZonePrivate(other), m_ucal(nullptr) { // Clone the ucal so we don't close the shared object UErrorCode status = U_ZERO_ERROR; m_ucal = ucal_clone(other.m_ucal, &status); if (!U_SUCCESS(status)) { m_id.clear(); - m_ucal = 0; + m_ucal = nullptr; } } @@ -322,7 +322,7 @@ void QIcuTimeZonePrivate::init(const QByteArray &ianaId) if (!U_SUCCESS(status)) { m_id.clear(); - m_ucal = 0; + m_ucal = nullptr; } } @@ -493,7 +493,7 @@ QList<QByteArray> QIcuTimeZonePrivate::availableTimeZoneIds(int offsetFromUtc) c // TODO Available directly in C++ api but not C api, from 4.8 onwards new filter method works #if U_ICU_VERSION_MAJOR_NUM >= 49 || (U_ICU_VERSION_MAJOR_NUM == 4 && U_ICU_VERSION_MINOR_NUM == 8) UErrorCode status = U_ZERO_ERROR; - UEnumeration *uenum = ucal_openTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, 0, + UEnumeration *uenum = ucal_openTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, nullptr, &offsetFromUtc, &status); QList<QByteArray> result; if (U_SUCCESS(status)) 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; diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp index 3c2695a789..5e55c6897d 100644 --- a/src/corelib/time/qtimezoneprivate_tz.cpp +++ b/src/corelib/time/qtimezoneprivate_tz.cpp @@ -512,7 +512,7 @@ PosixZone PosixZone::parse(const char *&pos, const char *end) if (zoneEnd < end && (zoneEnd[0] == '+' || zoneEnd[0] == '-')) ++zoneEnd; while (zoneEnd < end) { - if (strchr(offsetChars, char(*zoneEnd)) == NULL) + if (strchr(offsetChars, char(*zoneEnd)) == nullptr) break; ++zoneEnd; } |