diff options
Diffstat (limited to 'src/corelib/time')
-rw-r--r-- | src/corelib/time/qcalendar.cpp | 11 | ||||
-rw-r--r-- | src/corelib/time/qdatetime.cpp | 263 | ||||
-rw-r--r-- | src/corelib/time/qdatetime.h | 16 | ||||
-rw-r--r-- | src/corelib/time/qdatetimeparser.cpp | 30 | ||||
-rw-r--r-- | src/corelib/time/qdatetimeparser_p.h | 6 | ||||
-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 |
10 files changed, 252 insertions, 164 deletions
diff --git a/src/corelib/time/qcalendar.cpp b/src/corelib/time/qcalendar.cpp index 9d485f181e..32f0a511a3 100644 --- a/src/corelib/time/qcalendar.cpp +++ b/src/corelib/time/qcalendar.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -750,6 +750,8 @@ int QCalendar::daysInMonth(int month, int year) const /*! Returns the number of days in the given \a year. + + Handling of \c Unspecified as \a year is undefined. */ int QCalendar::daysInYear(int year) const { @@ -758,10 +760,15 @@ int QCalendar::daysInYear(int year) const /*! Returns the number of months in the given \a year. + + If \a year is \c Unspecified, returns the maximum number of months in a + year. + + \sa maximumMonthsInYear() */ int QCalendar::monthsInYear(int year) const { - return d ? d->monthsInYear(year) : 0; + return d ? year == Unspecified ? d->maximumMonthsInYear() : d->monthsInYear(year) : 0; } /*! diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index a5761055ed..773280ad68 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -1114,11 +1114,6 @@ static QString toStringTextDate(QDate date, QCalendar cal) return QString(); } -static QString toStringTextDate(QDate date) -{ - return toStringTextDate(date, QCalendar()); -} - static QString toStringIsoDate(QDate date) { const auto parts = QCalendar().partsFromDate(date); @@ -1129,11 +1124,13 @@ static QString toStringIsoDate(QDate date) /*! \fn QString QDate::toString(Qt::DateFormat format) const + \fn QString QDate::toString(Qt::DateFormat format, QCalendar cal) const \overload - Returns the date as a string. The \a format parameter determines - the format of the string. + Returns the date as a string. The \a format parameter determines the format + of the string. If \a cal is supplied, it determines the calendar used to + represent the date; it defaults to Gregorian. If the \a format is Qt::TextDate, the string is formatted in the default way. The day and month names will be localized names using the system @@ -1146,18 +1143,16 @@ static QString toStringIsoDate(QDate date) year, MM is the month of the year (between 01 and 12), and dd is the day of the month between 01 and 31. - If the \a format is Qt::SystemLocaleShortDate or - Qt::SystemLocaleLongDate, the string format depends on the locale - settings of the system. Identical to calling - QLocale::system().toString(date, QLocale::ShortFormat) or - QLocale::system().toString(date, QLocale::LongFormat). - - If the \a format is Qt::DefaultLocaleShortDate or - Qt::DefaultLocaleLongDate, the string format depends on the - default application locale. This is the locale set with - QLocale::setDefault(), or the system locale if no default locale - has been set. Identical to calling - \l {QLocale::toString()}{QLocale().toString(date, QLocale::ShortFormat) } or + The \a format options Qt::SystemLocaleDate, Qt::SystemLocaleShortDate and + Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with + \l {QLocale::toString()}{QLocale::system().toString(date, QLocale::ShortFormat)} or + \l {QLocale::toString()}{QLocale::system().toString(date, QLocale::LongFormat)}. + + The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and + Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with + \l {QLocale::toString()}{QLocale().toString(date, QLocale::ShortFormat)} or \l {QLocale::toString()}{QLocale().toString(date, QLocale::LongFormat)}. If the \a format is Qt::RFC2822Date, the string is formatted in @@ -1167,44 +1162,54 @@ static QString toStringIsoDate(QDate date) If the date is invalid, an empty string will be returned. \warning The Qt::ISODate format is only valid for years in the - range 0 to 9999. This restriction may apply to locale-aware - formats as well, depending on the locale settings. + range 0 to 9999. \sa fromString(), QLocale::toString() */ QString QDate::toString(Qt::DateFormat format) const { + return toString(format, QCalendar()); +} + +QString QDate::toString(Qt::DateFormat format, QCalendar cal) const +{ if (!isValid()) return QString(); switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: - return QLocale::system().toString(*this, QLocale::ShortFormat); + return QLocale::system().toString(*this, QLocale::ShortFormat, cal); case Qt::SystemLocaleLongDate: - return QLocale::system().toString(*this, QLocale::LongFormat); + return QLocale::system().toString(*this, QLocale::LongFormat, cal); case Qt::LocaleDate: case Qt::DefaultLocaleShortDate: - return QLocale().toString(*this, QLocale::ShortFormat); + return QLocale().toString(*this, QLocale::ShortFormat, cal); case Qt::DefaultLocaleLongDate: - return QLocale().toString(*this, QLocale::LongFormat); + return QLocale().toString(*this, QLocale::LongFormat, cal); +#endif // 5.15 case Qt::RFC2822Date: - return QLocale::c().toString(*this, u"dd MMM yyyy"); + return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy"), cal); default: case Qt::TextDate: - return toStringTextDate(*this); + return toStringTextDate(*this, cal); case Qt::ISODate: case Qt::ISODateWithMs: + // No calendar dependence return toStringIsoDate(*this); } } /*! \fn QString QDate::toString(const QString &format) const + \fn QString QDate::toString(const QString &format, QCalendar cal) const \fn QString QDate::toString(QStringView format) const + \fn QString QDate::toString(QStringView format, QCalendar cal) const - Returns the date as a string. The \a format parameter determines - the format of the result string. + Returns the date as a string. The \a format parameter determines the format + of the result string. If \cal is supplied, it determines the calendar used + to represent the date; it defaults to Gregorian. These expressions may be used: @@ -1259,41 +1264,7 @@ QString QDate::toString(Qt::DateFormat format) const */ QString QDate::toString(QStringView format) const { - return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6 -} - -#if QT_STRINGVIEW_LEVEL < 2 -QString QDate::toString(const QString &format) const -{ - return toString(qToStringViewIgnoringNull(format)); -} -#endif - -QString QDate::toString(Qt::DateFormat format, QCalendar cal) const -{ - if (!isValid()) - return QString(); - - switch (format) { - case Qt::SystemLocaleDate: - case Qt::SystemLocaleShortDate: - return QLocale::system().toString(*this, QLocale::ShortFormat, cal); - case Qt::SystemLocaleLongDate: - return QLocale::system().toString(*this, QLocale::LongFormat, cal); - case Qt::LocaleDate: - case Qt::DefaultLocaleShortDate: - return QLocale().toString(*this, QLocale::ShortFormat, cal); - case Qt::DefaultLocaleLongDate: - return QLocale().toString(*this, QLocale::LongFormat, cal); - case Qt::RFC2822Date: - return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy"), cal); - default: - case Qt::TextDate: - return toStringTextDate(*this, cal); - case Qt::ISODate: - case Qt::ISODateWithMs: - return toStringIsoDate(*this); - } + return toString(format, QCalendar()); } QString QDate::toString(QStringView format, QCalendar cal) const @@ -1302,6 +1273,11 @@ QString QDate::toString(QStringView format, QCalendar cal) const } #if QT_STRINGVIEW_LEVEL < 2 +QString QDate::toString(const QString &format) const +{ + return toString(qToStringViewIgnoringNull(format), QCalendar()); +} + QString QDate::toString(const QString &format, QCalendar cal) const { return toString(qToStringViewIgnoringNull(format), cal); @@ -1648,9 +1624,14 @@ ParsedInt readInt(QStringView text) \a format given, or an invalid date if the string cannot be parsed. - Note for Qt::TextDate: It is recommended that you use the - English short month names (e.g. "Jan"). Although localized month - names can also be used, they depend on the user's locale settings. + Note for Qt::TextDate: It is recommended that you use the English short + month names (e.g. "Jan"). Although localized month names can also be used in + Qt 5, they depend on the user's locale settings. + + \note Support for localized dates, including the format options + Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate, + Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate, + shall be removed in Qt 6. Use QLocale::toDate() instead. \sa toString(), QLocale::toDate() */ @@ -1661,6 +1642,7 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format) return QDate(); switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toDate(string, QLocale::ShortFormat); @@ -1671,6 +1653,7 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format) return QLocale().toDate(string, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toDate(string, QLocale::LongFormat); +#endif // 5.15 case Qt::RFC2822Date: return rfcDateImpl(string).date; default: @@ -1783,10 +1766,10 @@ QDate QDate::fromString(const QString &string, const QString &format, QCalendar { QDate date; #if QT_CONFIG(datetimeparser) - QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString, cal); + QDateTimeParser dt(QMetaType::QDate, 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); @@ -2022,18 +2005,15 @@ int QTime::msec() const date, use the \a format Qt::ISODateWithMs, which corresponds to HH:mm:ss.zzz. - If the \a format is Qt::SystemLocaleShortDate or - Qt::SystemLocaleLongDate, the string format depends on the locale - settings of the system. Identical to calling - QLocale::system().toString(time, QLocale::ShortFormat) or - QLocale::system().toString(time, QLocale::LongFormat). - - If the \a format is Qt::DefaultLocaleShortDate or - Qt::DefaultLocaleLongDate, the string format depends on the - default application locale. This is the locale set with - QLocale::setDefault(), or the system locale if no default locale - has been set. Identical to calling + The \a format options Qt::SystemLocaleDate:, Qt::SystemLocaleShortDate and + Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with: + \l {QLocale::toString()}{QLocale::system().toString(time, QLocale::ShortFormat)} or + \l {QLocale::toString()}{QLocale::system().toString(time, QLocale::LongFormat)}. + The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and + Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with: \l {QLocale::toString()}{QLocale().toString(time, QLocale::ShortFormat)} or \l {QLocale::toString()}{QLocale().toString(time, QLocale::LongFormat)}. @@ -2052,6 +2032,7 @@ QString QTime::toString(Qt::DateFormat format) const return QString(); switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toString(*this, QLocale::ShortFormat); @@ -2062,6 +2043,7 @@ QString QTime::toString(Qt::DateFormat format) const return QLocale().toString(*this, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toString(*this, QLocale::LongFormat); +#endif // 5.15 case Qt::ISODateWithMs: return QString::asprintf("%02d:%02d:%02d.%03d", hour(), minute(), second(), msec()); case Qt::RFC2822Date: @@ -2437,6 +2419,12 @@ static QTime fromIsoTimeString(QStringView string, Qt::DateFormat format, bool * fails for the default locale). This should be considered an implementation detail. + + \note Support for localized dates, including the format options + Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate, + Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate, + shall be removed in Qt 6. Use QLocale::toTime() instead. + \sa toString(), QLocale::toTime() */ QTime QTime::fromString(const QString &string, Qt::DateFormat format) @@ -2445,6 +2433,7 @@ QTime QTime::fromString(const QString &string, Qt::DateFormat format) return QTime(); switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toTime(string, QLocale::ShortFormat); @@ -2455,6 +2444,7 @@ QTime QTime::fromString(const QString &string, Qt::DateFormat format) return QLocale().toTime(string, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toTime(string, QLocale::LongFormat); +#endif // 5.15 case Qt::RFC2822Date: return rfcDateImpl(string).time; case Qt::ISODate: @@ -2529,10 +2519,10 @@ QTime QTime::fromString(const QString &string, const QString &format) { QTime time; #if QT_CONFIG(datetimeparser) - QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString, QCalendar()); + QDateTimeParser dt(QMetaType::QTime, 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); @@ -3299,7 +3289,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); } } @@ -3623,15 +3613,18 @@ QDateTime::QDateTime() noexcept(Data::CanBeSmall) } +#if QT_DEPRECATED_SINCE(5, 17) // ### Qt 6: remove /*! - Constructs a datetime with the given \a date, a valid - time(00:00:00.000), and sets the timeSpec() to Qt::LocalTime. -*/ + Constructs a datetime with the given \a date, using Qt::LocalTime as the + timeSpec() and the time at the start of that date. + \sa QDate::startOfDay() +*/ QDateTime::QDateTime(const QDate &date) - : d(QDateTimePrivate::create(date, QTime(0, 0), Qt::LocalTime, 0)) + : QDateTime(date.startOfDay(Qt::LocalTime, 0)) { } +#endif /*! Constructs a datetime with the given \a date and \a time, using @@ -4287,10 +4280,13 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) #if QT_CONFIG(datestring) // depends on, so implies, textdate /*! \fn QString QDateTime::toString(Qt::DateFormat format) const + \fn QString QDateTime::toString(Qt::DateFormat format, QCalendar cal) const \overload - Returns the datetime as a string in the \a format given. + Returns the datetime as a string in the \a format given. If \cal is + supplied, it determines the calendar used to represent the date; it defaults + to Gregorian. If the \a format is Qt::TextDate, the string is formatted in the default way. The day and month names will be localized names using the system @@ -4307,19 +4303,17 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) date, use the \a format Qt::ISODateWithMs, which corresponds to yyyy-MM-ddTHH:mm:ss.zzz[Z|[+|-]HH:mm]. - If the \a format is Qt::SystemLocaleShortDate or - Qt::SystemLocaleLongDate, the string format depends on the locale - settings of the system. Identical to calling - QLocale::system().toString(datetime, QLocale::ShortFormat) or - QLocale::system().toString(datetime, QLocale::LongFormat). + The \a format options Qt::SystemLocaleDate, Qt::SystemLocaleShortDate and + Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with + \l {QLocale::toString()}{QLocale::system().toString(datetime, QLocale::ShortFormat)} or + \l {QLocale::toString()}{QLocale::system().toString(datetime, QLocale::LongFormat)}. - If the \a format is Qt::DefaultLocaleShortDate or - Qt::DefaultLocaleLongDate, the string format depends on the - default application locale. This is the locale set with - QLocale::setDefault(), or the system locale if no default locale - has been set. Identical to calling QLocale().toString(datetime, - QLocale::ShortFormat) or QLocale().toString(datetime, - QLocale::LongFormat). + The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and + Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be + replaced with + \l {QLocale::toString()}{QLocale().toString(datetime, QLocale::ShortFormat)} or + \l {QLocale::toString()}{QLocale().toString(datetime, QLocale::LongFormat)}. If the \a format is Qt::RFC2822Date, the string is formatted following \l{RFC 2822}. @@ -4327,8 +4321,7 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) If the datetime is invalid, an empty string will be returned. \warning The Qt::ISODate format is only valid for years in the - range 0 to 9999. This restriction may apply to locale-aware - formats as well, depending on the locale settings. + range 0 to 9999. \sa fromString(), QDate::toString(), QTime::toString(), QLocale::toString() @@ -4336,30 +4329,37 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) QString QDateTime::toString(Qt::DateFormat format) const { + return toString(format, QCalendar()); +} + +QString QDateTime::toString(Qt::DateFormat format, QCalendar cal) const +{ QString buf; if (!isValid()) return buf; switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: - return QLocale::system().toString(*this, QLocale::ShortFormat); + return QLocale::system().toString(*this, QLocale::ShortFormat, cal); case Qt::SystemLocaleLongDate: - return QLocale::system().toString(*this, QLocale::LongFormat); + return QLocale::system().toString(*this, QLocale::LongFormat, cal); case Qt::LocaleDate: case Qt::DefaultLocaleShortDate: - return QLocale().toString(*this, QLocale::ShortFormat); + return QLocale().toString(*this, QLocale::ShortFormat, cal); case Qt::DefaultLocaleLongDate: - return QLocale().toString(*this, QLocale::LongFormat); + return QLocale().toString(*this, QLocale::LongFormat, cal); +#endif // 5.15 case Qt::RFC2822Date: { - buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss "); + buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss ", cal); buf += toOffsetString(Qt::TextDate, offsetFromUtc()); return buf; } default: case Qt::TextDate: { const QPair<QDate, QTime> p = getDateTime(d); - buf = p.first.toString(Qt::TextDate); + buf = toStringTextDate(p.first, cal); // Insert time between date's day and year: buf.insert(buf.lastIndexOf(QLatin1Char(' ')), QLatin1Char(' ') + p.second.toString(Qt::TextDate)); @@ -4381,14 +4381,12 @@ QString QDateTime::toString(Qt::DateFormat format) const } case Qt::ISODate: case Qt::ISODateWithMs: { + // No calendar dependence const QPair<QDate, QTime> p = getDateTime(d); - const QDate &dt = p.first; - const QTime &tm = p.second; - buf = dt.toString(Qt::ISODate); + buf = toStringIsoDate(p.first); if (buf.isEmpty()) return QString(); // failed to convert - buf += QLatin1Char('T'); - buf += tm.toString(format); + buf += QLatin1Char('T') + p.second.toString(format); switch (getSpec(d)) { case Qt::UTC: buf += QLatin1Char('Z'); @@ -4409,11 +4407,15 @@ QString QDateTime::toString(Qt::DateFormat format) const /*! \fn QString QDateTime::toString(const QString &format) const + \fn QString QDateTime::toString(const QString &format, QCalendar cal) const \fn QString QDateTime::toString(QStringView format) const + \fn QString QDateTime::toString(QStringView format, QCalendar cal) const Returns the datetime as a string. The \a format parameter determines the - format of the result string. See QTime::toString() and QDate::toString() for - the supported specifiers for time and date, respectively. + format of the result string. If \cal is supplied, it determines the calendar + used to represent the date; it defaults to Gregorian. See QTime::toString() + and QDate::toString() for the supported specifiers for time and date, + respectively. Any sequence of characters enclosed in single quotes will be included verbatim in the output string (stripped of the quotes), even if it contains @@ -4444,13 +4446,23 @@ QString QDateTime::toString(Qt::DateFormat format) const */ QString QDateTime::toString(QStringView format) const { - return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6 + return toString(format, QCalendar()); +} + +QString QDateTime::toString(QStringView format, QCalendar cal) const +{ + return QLocale::system().toString(*this, format, cal); // QLocale::c() ### Qt6 } #if QT_STRINGVIEW_LEVEL < 2 QString QDateTime::toString(const QString &format) const { - return toString(qToStringViewIgnoringNull(format)); + return toString(qToStringViewIgnoringNull(format), QCalendar()); +} + +QString QDateTime::toString(const QString &format, QCalendar cal) const +{ + return toString(qToStringViewIgnoringNull(format), cal); } #endif @@ -5198,9 +5210,14 @@ int QDateTime::utcOffset() const Returns the QDateTime represented by the \a string, using the \a format given, or an invalid datetime if this is not possible. - Note for Qt::TextDate: It is recommended that you use the - English short month names (e.g. "Jan"). Although localized month - names can also be used, they depend on the user's locale settings. + Note for Qt::TextDate: It is recommended that you use the English short + month names (e.g. "Jan"). Although localized month names can also be used in + Qt 5, they depend on the user's locale settings. + + \note Support for localized dates, including the format options + Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate, + Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate, + shall be removed in Qt 6. Use QLocale::toDateTime() instead. \sa toString(), QLocale::toDateTime() */ @@ -5210,6 +5227,7 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) return QDateTime(); switch (format) { +#if QT_DEPRECATED_SINCE(5, 15) case Qt::SystemLocaleDate: case Qt::SystemLocaleShortDate: return QLocale::system().toDateTime(string, QLocale::ShortFormat); @@ -5220,6 +5238,7 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) return QLocale().toDateTime(string, QLocale::ShortFormat); case Qt::DefaultLocaleLongDate: return QLocale().toDateTime(string, QLocale::LongFormat); +#endif // 5.15 case Qt::RFC2822Date: { const ParsedRfcDateTime rfc = rfcDateImpl(string); @@ -5470,7 +5489,7 @@ QDateTime QDateTime::fromString(const QString &string, const QString &format, QC QTime time; QDate date; - QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString, cal); + QDateTimeParser dt(QMetaType::QDateTime, QDateTimeParser::FromString, cal); // dt.setDefaultLocale(QLocale::c()); ### Qt 6 if (dt.parseFormat(format) && dt.fromString(string, &date, &time)) return QDateTime(date, time); diff --git a/src/corelib/time/qdatetime.h b/src/corelib/time/qdatetime.h index 3eae8ebf64..c1653b5585 100644 --- a/src/corelib/time/qdatetime.h +++ b/src/corelib/time/qdatetime.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** @@ -110,14 +110,15 @@ public: static QString longDayName(int weekday, MonthNameType type = DateFormat); #endif // textdate && deprecated #if QT_CONFIG(datestring) - QString toString(Qt::DateFormat f = Qt::TextDate) const; + QString toString(Qt::DateFormat format = Qt::TextDate) const; + QString toString(Qt::DateFormat format, QCalendar cal) const; + #if QT_STRINGVIEW_LEVEL < 2 QString toString(const QString &format) const; QString toString(const QString &format, QCalendar cal) const; #endif QString toString(QStringView format) const; - QString toString(Qt::DateFormat f, QCalendar cal) const; QString toString(QStringView format, QCalendar cal) const; #endif #if QT_DEPRECATED_SINCE(5,0) @@ -287,7 +288,9 @@ class Q_CORE_EXPORT QDateTime public: QDateTime() noexcept(Data::CanBeSmall); - explicit QDateTime(const QDate &); // ### Qt 6: plain QDate, QTime +#if QT_DEPRECATED_SINCE(5, 15) // ### Qt 6: remove + QT_DEPRECATED_X("Use QDate::startOfDay()") explicit QDateTime(const QDate &); +#endif QDateTime(const QDate &, const QTime &, Qt::TimeSpec spec = Qt::LocalTime); // ### Qt 6: Merge with above with default offsetSeconds = 0 QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, int offsetSeconds); @@ -330,11 +333,14 @@ public: void setSecsSinceEpoch(qint64 secs); #if QT_CONFIG(datestring) - QString toString(Qt::DateFormat f = Qt::TextDate) const; + QString toString(Qt::DateFormat format = Qt::TextDate) const; + QString toString(Qt::DateFormat format, QCalendar cal) const; #if QT_STRINGVIEW_LEVEL < 2 QString toString(const QString &format) const; + QString toString(const QString &format, QCalendar cal) const; #endif QString toString(QStringView format) const; + QString toString(QStringView format, QCalendar cal) const; #endif Q_REQUIRED_RESULT QDateTime addDays(qint64 days) const; Q_REQUIRED_RESULT QDateTime addMonths(int months) const; diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp index 24f3969851..790c20004a 100644 --- a/src/corelib/time/qdatetimeparser.cpp +++ b/src/corelib/time/qdatetimeparser.cpp @@ -410,7 +410,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; @@ -431,7 +431,7 @@ bool QDateTimeParser::parseFormat(const QString &newFormat) switch (sect) { case 'H': case 'h': - if (parserType != QVariant::Date) { + if (parserType != QMetaType::QDate) { const Section hour = (sect == 'h') ? Hour12Section : Hour24Section; const SectionNode sn = { hour, i - add, countRepeat(newFormat, i, 2), 0 }; newSectionNodes.append(sn); @@ -442,7 +442,7 @@ bool QDateTimeParser::parseFormat(const QString &newFormat) } break; case 'm': - if (parserType != QVariant::Date) { + if (parserType != QMetaType::QDate) { const SectionNode sn = { MinuteSection, i - add, countRepeat(newFormat, i, 2), 0 }; newSectionNodes.append(sn); appendSeparator(&newSeparators, newFormat, index, i - index, lastQuote); @@ -452,7 +452,7 @@ bool QDateTimeParser::parseFormat(const QString &newFormat) } break; case 's': - if (parserType != QVariant::Date) { + if (parserType != QMetaType::QDate) { const SectionNode sn = { SecondSection, i - add, countRepeat(newFormat, i, 2), 0 }; newSectionNodes.append(sn); appendSeparator(&newSeparators, newFormat, index, i - index, lastQuote); @@ -463,7 +463,7 @@ bool QDateTimeParser::parseFormat(const QString &newFormat) break; case 'z': - if (parserType != QVariant::Date) { + if (parserType != QMetaType::QDate) { const SectionNode sn = { MSecSection, i - add, countRepeat(newFormat, i, 3) < 3 ? 1 : 3, 0 }; newSectionNodes.append(sn); appendSeparator(&newSeparators, newFormat, index, i - index, lastQuote); @@ -474,7 +474,7 @@ bool QDateTimeParser::parseFormat(const QString &newFormat) break; case 'A': case 'a': - if (parserType != QVariant::Date) { + if (parserType != QMetaType::QDate) { const bool cap = (sect == 'A'); const SectionNode sn = { AmPmSection, i - add, (cap ? 1 : 0), 0 }; newSectionNodes.append(sn); @@ -488,7 +488,7 @@ bool QDateTimeParser::parseFormat(const QString &newFormat) } break; case 'y': - if (parserType != QVariant::Time) { + if (parserType != QMetaType::QTime) { const int repeat = countRepeat(newFormat, i, 4); if (repeat >= 2) { const SectionNode sn = { repeat == 4 ? YearSection : YearSection2Digits, @@ -502,7 +502,7 @@ bool QDateTimeParser::parseFormat(const QString &newFormat) } break; case 'M': - if (parserType != QVariant::Time) { + if (parserType != QMetaType::QTime) { const SectionNode sn = { MonthSection, i - add, countRepeat(newFormat, i, 4), 0 }; newSectionNodes.append(sn); newSeparators.append(unquote(newFormat.midRef(index, i - index))); @@ -512,7 +512,7 @@ bool QDateTimeParser::parseFormat(const QString &newFormat) } break; case 'd': - if (parserType != QVariant::Time) { + if (parserType != QMetaType::QTime) { const int repeat = countRepeat(newFormat, i, 4); const Section sectionType = (repeat == 4 ? DayOfWeekSectionLong : (repeat == 3 ? DayOfWeekSectionShort : DaySection)); @@ -525,7 +525,7 @@ bool QDateTimeParser::parseFormat(const QString &newFormat) } break; case 't': - if (parserType != QVariant::Time) { + if (parserType != QMetaType::QTime) { const SectionNode sn = { TimeZoneSection, i - add, countRepeat(newFormat, i, 4), 0 }; newSectionNodes.append(sn); appendSeparator(&newSeparators, newFormat, index, i - index, lastQuote); @@ -1164,7 +1164,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; @@ -1265,7 +1265,7 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, return StateNode(); } - if (parserType != QVariant::Time) { + if (parserType != QMetaType::QTime) { if (year % 100 != year2digits && (isSet & YearSection2Digits)) { if (!(isSet & YearSection)) { year = (year / 100) * 100; @@ -1335,7 +1335,7 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, } } - if (parserType != QVariant::Date) { + if (parserType != QMetaType::QDate) { if (isSet & Hour12Section) { const bool hasHour = isSet & Hour24Section; if (ampm == -1) { @@ -1373,7 +1373,7 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, // If hour wasn't specified, check the default we're using exists on the // given date (which might be a spring-forward, skipping an hour). - if (parserType == QVariant::DateTime && !(isSet & HourSectionMask) && !when.isValid()) { + if (parserType == QMetaType::QDateTime && !(isSet & HourSectionMask) && !when.isValid()) { qint64 msecs = when.toMSecsSinceEpoch(); // Fortunately, that gets a useful answer, even though when is invalid ... const QDateTime replace = @@ -1809,7 +1809,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..5c612ef6a4 100644 --- a/src/corelib/time/qdatetimeparser_p.h +++ b/src/corelib/time/qdatetimeparser_p.h @@ -83,8 +83,8 @@ public: FromString, DateTimeEdit }; - QDateTimeParser(QVariant::Type t, Context ctx, const QCalendar &cal = QCalendar()) - : currentSectionIndex(-1), display(nullptr), cachedDay(-1), parserType(t), + QDateTimeParser(QMetaType::Type t, Context ctx, const QCalendar &cal = QCalendar()) + : currentSectionIndex(-1), cachedDay(-1), parserType(t), fixday(false), spec(Qt::LocalTime), context(ctx), calendar(cal) { defaultLocale = QLocale::system(); @@ -295,7 +295,7 @@ protected: // for the benefit of QDateTimeEditPrivate QStringList separators; QString displayFormat; QLocale defaultLocale; - QVariant::Type parserType; + QMetaType::Type parserType; bool fixday; Qt::TimeSpec spec; // spec if used by QDateTimeEdit Context context; diff --git a/src/corelib/time/qtimezone.cpp b/src/corelib/time/qtimezone.cpp index 0bba2afc61..87d8ea75f1 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; } |