summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qdatetime.cpp
diff options
context:
space:
mode:
authorJohn Layt <jlayt@kde.org>2013-07-18 11:37:57 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-06 01:53:11 +0200
commit61b56a89a1cf8a388ff925492700e5eef019c3aa (patch)
tree4897244d0ca1b1b335e1c30d4016f3c3a38adfc3 /src/corelib/tools/qdatetime.cpp
parent8b02a62685953ad1b1e35750187e3e857d9d3ccd (diff)
QDateTime - Clean up Qt::DateFormat formatting and parsing
Clean-up the implementation of toString() and fromString() methods in QDate, QTime and QDateTime code to be more consistent in ISODate and TextDate behavior, especially when handling TimeSpec. Reformat some code so all methods are consistent in appearance and function to make maintenance easier. This changes some corner-case behavior in TextDate and ISODate, but this either fixes bugs or makes the behavior match the documentation. Change-Id: I457aa1d7cd4f448cd9f8a2e80ec635f3cb98e58c Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Mitch Curtis <mitch.curtis@digia.com>
Diffstat (limited to 'src/corelib/tools/qdatetime.cpp')
-rw-r--r--src/corelib/tools/qdatetime.cpp580
1 files changed, 271 insertions, 309 deletions
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index 114f97c2e0..014f2e4202 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -872,45 +872,42 @@ QString QDate::longDayName(int weekday, MonthNameType type)
\sa shortDayName(), shortMonthName()
*/
-QString QDate::toString(Qt::DateFormat f) const
+QString QDate::toString(Qt::DateFormat format) const
{
if (!isValid())
return QString();
+
int y, m, d;
- getDateFromJulianDay(jd, &y, &m, &d);
- switch (f) {
+
+ switch (format) {
case Qt::SystemLocaleDate:
case Qt::SystemLocaleShortDate:
+ return QLocale::system().toString(*this, QLocale::ShortFormat);
case Qt::SystemLocaleLongDate:
- return QLocale::system().toString(*this, f == Qt::SystemLocaleLongDate ? QLocale::LongFormat
- : QLocale::ShortFormat);
+ return QLocale::system().toString(*this, QLocale::LongFormat);
case Qt::LocaleDate:
case Qt::DefaultLocaleShortDate:
+ return QLocale().toString(*this, QLocale::ShortFormat);
case Qt::DefaultLocaleLongDate:
- return QLocale().toString(*this, f == Qt::DefaultLocaleLongDate ? QLocale::LongFormat
- : QLocale::ShortFormat);
+ return QLocale().toString(*this, QLocale::LongFormat);
+ case Qt::RFC2822Date:
+ return toString(QStringLiteral("dd MMM yyyy"));
default:
#ifndef QT_NO_TEXTDATE
case Qt::TextDate:
- {
- return QString::fromLatin1("%0 %1 %2 %3")
- .arg(shortDayName(dayOfWeek()))
- .arg(shortMonthName(m))
- .arg(d)
- .arg(y);
- }
+ getDateFromJulianDay(jd, &y, &m, &d);
+ return QString::fromUtf8("%1 %2 %3 %4").arg(shortDayName(dayOfWeek()))
+ .arg(shortMonthName(m))
+ .arg(d)
+ .arg(y);
#endif
- case Qt::RFC2822Date:
- return toString(QStringLiteral("dd MMM yyyy"));
case Qt::ISODate:
- {
- if (year() < 0 || year() > 9999)
- return QString();
- QString year(QString::number(y).rightJustified(4, QLatin1Char('0')));
- QString month(QString::number(m).rightJustified(2, QLatin1Char('0')));
- QString day(QString::number(d).rightJustified(2, QLatin1Char('0')));
- return year + QLatin1Char('-') + month + QLatin1Char('-') + day;
- }
+ getDateFromJulianDay(jd, &y, &m, &d);
+ if (y < 0 || y > 9999)
+ return QString();
+ return QString::fromUtf8("%1-%2-%3").arg(y, 4, 10, QLatin1Char('0'))
+ .arg(m, 2, 10, QLatin1Char('0'))
+ .arg(d, 2, 10, QLatin1Char('0'));
}
}
@@ -1224,44 +1221,34 @@ qint64 QDate::daysTo(const QDate &d) const
English short month names (e.g. "Jan"). Although localized month
names can also be used, they depend on the user's locale settings.
*/
-QDate QDate::fromString(const QString& s, Qt::DateFormat f)
+QDate QDate::fromString(const QString& string, Qt::DateFormat format)
{
- if (s.isEmpty())
+ if (string.isEmpty())
return QDate();
- switch (f) {
- case Qt::ISODate:
- {
- int year(s.mid(0, 4).toInt());
- int month(s.mid(5, 2).toInt());
- int day(s.mid(8, 2).toInt());
- if (year && month && day)
- return QDate(year, month, day);
- }
- break;
+ switch (format) {
case Qt::SystemLocaleDate:
case Qt::SystemLocaleShortDate:
+ return QLocale::system().toDate(string, QLocale::ShortFormat);
case Qt::SystemLocaleLongDate:
- return fromString(s, QLocale::system().dateFormat(f == Qt::SystemLocaleLongDate ? QLocale::LongFormat
- : QLocale::ShortFormat));
+ return QLocale::system().toDate(string, QLocale::LongFormat);
case Qt::LocaleDate:
case Qt::DefaultLocaleShortDate:
+ return QLocale().toDate(string, QLocale::ShortFormat);
case Qt::DefaultLocaleLongDate:
- return fromString(s, QLocale().dateFormat(f == Qt::DefaultLocaleLongDate ? QLocale::LongFormat
- : QLocale::ShortFormat));
+ return QLocale().toDate(string, QLocale::LongFormat);
case Qt::RFC2822Date: {
QDate date;
- rfcDateImpl(s, &date);
+ rfcDateImpl(string, &date);
return date;
}
default:
#ifndef QT_NO_TEXTDATE
case Qt::TextDate: {
- QStringList parts = s.split(QLatin1Char(' '), QString::SkipEmptyParts);
+ QStringList parts = string.split(QLatin1Char(' '), QString::SkipEmptyParts);
- if (parts.count() != 4) {
+ if (parts.count() != 4)
return QDate();
- }
QString monthName = parts.at(1);
int month = -1;
@@ -1280,28 +1267,25 @@ QDate QDate::fromString(const QString& s, Qt::DateFormat f)
break;
}
}
- if (month == -1) {
+ if (month == -1)
// Month name matches neither English nor other localised name.
return QDate();
- }
}
- bool ok;
- int day = parts.at(2).toInt(&ok);
- if (!ok) {
+ bool ok = false;
+ int year = parts.at(3).toInt(&ok);
+ if (!ok)
return QDate();
- }
- int year = parts.at(3).toInt(&ok);
- if (!ok) {
+ return QDate(year, month, parts.at(2).toInt());
+ }
+#endif // QT_NO_TEXTDATE
+ case Qt::ISODate: {
+ const int year = string.mid(0, 4).toInt();
+ if (year <= 0 || year > 9999)
return QDate();
+ return QDate(year, string.mid(5, 2).toInt(), string.mid(8, 2).toInt());
}
-
- return QDate(year, month, day);
- }
-#else
- break;
-#endif
}
return QDate();
}
@@ -1633,6 +1617,8 @@ int QTime::msec() const
"23:59:20".
If the time is invalid, an empty string will be returned.
+
+ \sa QDate::toString(), QDateTime::toString()
*/
QString QTime::toString(Qt::DateFormat format) const
@@ -1643,28 +1629,25 @@ QString QTime::toString(Qt::DateFormat format) const
switch (format) {
case Qt::SystemLocaleDate:
case Qt::SystemLocaleShortDate:
+ return QLocale::system().toString(*this, QLocale::ShortFormat);
case Qt::SystemLocaleLongDate:
- return QLocale::system().toString(*this, format == Qt::SystemLocaleLongDate ? QLocale::LongFormat
- : QLocale::ShortFormat);
+ return QLocale::system().toString(*this, QLocale::LongFormat);
case Qt::LocaleDate:
case Qt::DefaultLocaleShortDate:
+ return QLocale().toString(*this, QLocale::ShortFormat);
case Qt::DefaultLocaleLongDate:
- return QLocale().toString(*this, format == Qt::DefaultLocaleLongDate ? QLocale::LongFormat
- : QLocale::ShortFormat);
-
+ return QLocale().toString(*this, QLocale::LongFormat);
case Qt::RFC2822Date:
- return QString::fromLatin1("%1:%2:%3")
- .arg(hour(), 2, 10, QLatin1Char('0'))
- .arg(minute(), 2, 10, QLatin1Char('0'))
- .arg(second(), 2, 10, QLatin1Char('0'));
- default:
+ return QString::fromLatin1("%1:%2:%3").arg(hour(), 2, 10, QLatin1Char('0'))
+ .arg(minute(), 2, 10, QLatin1Char('0'))
+ .arg(second(), 2, 10, QLatin1Char('0'));
case Qt::ISODate:
case Qt::TextDate:
- return QString::fromLatin1("%1:%2:%3.%4")
- .arg(hour(), 2, 10, QLatin1Char('0'))
- .arg(minute(), 2, 10, QLatin1Char('0'))
- .arg(second(), 2, 10, QLatin1Char('0'))
- .arg(msec(), 3, 10, QLatin1Char('0'));
+ default:
+ return QString::fromUtf8("%1:%2:%3.%4").arg(hour(), 2, 10, QLatin1Char('0'))
+ .arg(minute(), 2, 10, QLatin1Char('0'))
+ .arg(second(), 2, 10, QLatin1Char('0'))
+ .arg(msec(), 3, 10, QLatin1Char('0'));
}
}
@@ -1899,104 +1882,68 @@ int QTime::msecsTo(const QTime &t) const
#ifndef QT_NO_DATESTRING
-// These anonymous functions tidy up QDateTime::fromString()
-// and avoid confusion of responsibility between it and QTime::fromString().
-namespace {
-inline bool isMidnight(int hour, int minute, int second, int msec)
+static QTime fromIsoTimeString(const QString &string, Qt::DateFormat format, bool *isMidnight24)
{
- return hour == 24 && minute == 0 && second == 0 && msec == 0;
-}
+ if (isMidnight24)
+ *isMidnight24 = false;
-QTime fromStringImpl(const QString &s, Qt::DateFormat f, bool &isMidnight24)
-{
- if (s.isEmpty()) {
- // Return a null time.
+ const int size = string.size();
+ if (size < 5)
return QTime();
- }
- switch (f) {
- case Qt::SystemLocaleDate:
- case Qt::SystemLocaleShortDate:
- case Qt::SystemLocaleLongDate:
- {
- QLocale::FormatType formatType(Qt::SystemLocaleLongDate ? QLocale::LongFormat : QLocale::ShortFormat);
- return QTime::fromString(s, QLocale::system().timeFormat(formatType));
- }
- case Qt::LocaleDate:
- case Qt::DefaultLocaleShortDate:
- case Qt::DefaultLocaleLongDate:
- {
- QLocale::FormatType formatType(f == Qt::DefaultLocaleLongDate ? QLocale::LongFormat : QLocale::ShortFormat);
- return QTime::fromString(s, QLocale().timeFormat(formatType));
- }
- case Qt::RFC2822Date: {
- QTime time;
- rfcDateImpl(s, 0, &time);
- return time;
- }
- case Qt::TextDate:
- case Qt::ISODate:
- {
- bool ok = true;
- const int hour(s.mid(0, 2).toInt(&ok));
- if (!ok)
+ bool ok = false;
+ int hour = string.mid(0, 2).toInt(&ok);
+ if (!ok)
+ return QTime();
+ const int minute = string.mid(3, 2).toInt(&ok);
+ if (!ok)
+ return QTime();
+ int second = 0;
+ int msec = 0;
+
+ if (size == 5) {
+ // HH:MM format
+ second = 0;
+ msec = 0;
+ } else if (string.at(5) == QLatin1Char(',') || string.at(5) == QLatin1Char('.')) {
+ if (format == Qt::TextDate)
return QTime();
- const int minute(s.mid(3, 2).toInt(&ok));
+ // ISODate HH:MM.SSSSSS format
+ // We only want 5 digits worth of fraction of minute. This follows the existing
+ // behavior that determines how milliseconds are read; 4 millisecond digits are
+ // read and then rounded to 3. If we read at most 5 digits for fraction of minute,
+ // the maximum amount of millisecond digits it will expand to once converted to
+ // seconds is 4. E.g. 12:34,99999 will expand to 12:34:59.9994. The milliseconds
+ // will then be rounded up AND clamped to 999.
+ const float minuteFraction = QString::fromUtf8("0.%1").arg(string.mid(6, 5)).toFloat(&ok);
if (!ok)
return QTime();
- if (f == Qt::ISODate) {
- if (s.size() == 5) {
- // Do not need to specify seconds if using ISO format.
- return QTime(hour, minute, 0, 0);
- } else if ((s.size() > 6) && (s[5] == QLatin1Char(',') || s[5] == QLatin1Char('.'))) {
- // Possibly specifying fraction of a minute.
-
- // We only want 5 digits worth of fraction of minute. This follows the existing
- // behaviour that determines how milliseconds are read; 4 millisecond digits are
- // read and then rounded to 3. If we read at most 5 digits for fraction of minute,
- // the maximum amount of millisecond digits it will expand to once converted to
- // seconds is 4. E.g. 12:34,99999 will expand to 12:34:59.9994. The milliseconds
- // will then be rounded up AND clamped to 999.
- const QString minuteFractionStr(QLatin1String("0.") + s.mid(6, 5));
- const float minuteFraction = minuteFractionStr.toFloat(&ok);
- if (!ok)
- return QTime();
- const float secondWithMs = minuteFraction * 60;
- const float second = std::floor(secondWithMs);
- const float millisecond = 1000 * (secondWithMs - second);
- const int millisecondRounded = qMin(qRound(millisecond), 999);
-
- if (isMidnight(hour, minute, second, millisecondRounded)) {
- isMidnight24 = true;
- return QTime(0, 0, 0, 0);
- }
-
- return QTime(hour, minute, second, millisecondRounded);
- }
- }
-
- const int second(s.mid(6, 2).toInt(&ok));
+ const float secondWithMs = minuteFraction * 60;
+ const float secondNoMs = std::floor(secondWithMs);
+ const float secondFraction = secondWithMs - secondNoMs;
+ second = secondNoMs;
+ msec = qMin(qRound(secondFraction * 1000.0), 999);
+ } else {
+ // HH:MM:SS or HH:MM:SS.sssss
+ second = string.mid(6, 2).toInt(&ok);
if (!ok)
return QTime();
- const QString msec_s(QLatin1String("0.") + s.mid(9, 4));
- const double msec(msec_s.toDouble(&ok));
- if (!ok)
- return QTime(hour, minute, second, 0);
-
- if (f == Qt::ISODate) {
- if (isMidnight(hour, minute, second, msec)) {
- isMidnight24 = true;
- return QTime(0, 0, 0, 0);
- }
+ if (size > 8 && (string.at(8) == QLatin1Char(',') || string.at(8) == QLatin1Char('.'))) {
+ const double secondFraction = QString::fromUtf8("0.%1").arg(string.mid(9, 4)).toDouble(&ok);
+ if (!ok)
+ return QTime();
+ msec = qMin(qRound(secondFraction * 1000.0), 999);
}
- return QTime(hour, minute, second, qMin(qRound(msec * 1000.0), 999));
}
+
+ if (format == Qt::ISODate && hour == 24 && minute == 0 && second == 0 && msec == 0) {
+ if (isMidnight24)
+ *isMidnight24 = true;
+ hour = 0;
}
- Q_UNREACHABLE();
- return QTime();
-}
-}
+ return QTime(hour, minute, second, msec);
+}
/*!
\fn QTime QTime::fromString(const QString &string, Qt::DateFormat format)
@@ -2010,10 +1957,32 @@ QTime fromStringImpl(const QString &s, Qt::DateFormat f, bool &isMidnight24)
fails for the default locale). This should be considered an
implementation detail.
*/
-QTime QTime::fromString(const QString& s, Qt::DateFormat f)
+QTime QTime::fromString(const QString& string, Qt::DateFormat format)
{
- bool unused;
- return fromStringImpl(s, f, unused);
+ if (string.isEmpty())
+ return QTime();
+
+ switch (format) {
+ case Qt::SystemLocaleDate:
+ case Qt::SystemLocaleShortDate:
+ return QLocale::system().toTime(string, QLocale::ShortFormat);
+ case Qt::SystemLocaleLongDate:
+ return QLocale::system().toTime(string, QLocale::LongFormat);
+ case Qt::LocaleDate:
+ case Qt::DefaultLocaleShortDate:
+ return QLocale().toTime(string, QLocale::ShortFormat);
+ case Qt::DefaultLocaleLongDate:
+ return QLocale().toTime(string, QLocale::LongFormat);
+ case Qt::RFC2822Date: {
+ QTime time;
+ rfcDateImpl(string, 0, &time);
+ return time;
+ }
+ case Qt::ISODate:
+ case Qt::TextDate:
+ default:
+ return fromIsoTimeString(string, format, 0);
+ }
}
/*!
@@ -2814,30 +2783,24 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC)
\sa QDate::toString(), QTime::toString(), Qt::DateFormat
*/
-QString QDateTime::toString(Qt::DateFormat f) const
+QString QDateTime::toString(Qt::DateFormat format) const
{
QString buf;
if (!isValid())
return buf;
- if (f == Qt::ISODate) {
- buf = d->date.toString(Qt::ISODate);
- if (buf.isEmpty())
- return QString(); // failed to convert
- buf += QLatin1Char('T');
- buf += d->time.toString(Qt::ISODate);
- switch (d->spec) {
- case QDateTimePrivate::UTC:
- buf += QLatin1Char('Z');
- break;
- case QDateTimePrivate::OffsetFromUTC: {
- buf += toOffsetString(Qt::ISODate, d->m_offsetFromUtc);
- break;
- }
- default:
- break;
- }
- } else if (f == Qt::RFC2822Date) {
+ switch (format) {
+ case Qt::SystemLocaleDate:
+ case Qt::SystemLocaleShortDate:
+ return QLocale::system().toString(*this, QLocale::ShortFormat);
+ case Qt::SystemLocaleLongDate:
+ return QLocale::system().toString(*this, QLocale::LongFormat);
+ case Qt::LocaleDate:
+ case Qt::DefaultLocaleShortDate:
+ return QLocale().toString(*this, QLocale::ShortFormat);
+ case Qt::DefaultLocaleLongDate:
+ return QLocale().toString(*this, QLocale::LongFormat);
+ case Qt::RFC2822Date: {
buf = toString(QStringLiteral("dd MMM yyyy hh:mm:ss "));
int utcOffset = d->m_offsetFromUtc;
@@ -2859,50 +2822,42 @@ QString QDateTime::toString(Qt::DateFormat f) const
if (min < 10)
buf += QLatin1Char('0');
buf += QString::number(min);
+ return buf;
}
+ default:
#ifndef QT_NO_TEXTDATE
- else if (f == Qt::TextDate) {
-#ifndef Q_OS_WIN
- buf = d->date.shortDayName(d->date.dayOfWeek());
- buf += QLatin1Char(' ');
- buf += d->date.shortMonthName(d->date.month());
- buf += QLatin1Char(' ');
- buf += QString::number(d->date.day());
-#else
- wchar_t out[255];
- GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILDATE, out, 255);
- QString winstr = QString::fromWCharArray(out);
- switch (winstr.toInt()) {
- case 1:
- buf = d->date.shortDayName(d->date.dayOfWeek());
- buf += QLatin1Char(' ');
- buf += QString::number(d->date.day());
- buf += QLatin1String(". ");
- buf += d->date.shortMonthName(d->date.month());
- break;
- default:
- buf = d->date.shortDayName(d->date.dayOfWeek());
- buf += QLatin1Char(' ');
- buf += d->date.shortMonthName(d->date.month());
- buf += QLatin1Char(' ');
- buf += QString::number(d->date.day());
+ case Qt::TextDate:
+ //We cant use date.toString(Qt::TextDate) as we need to insert the time before the year
+ buf = QString::fromUtf8("%1 %2 %3 %4 %5").arg(d->date.shortDayName(d->date.dayOfWeek()))
+ .arg(d->date.shortMonthName(d->date.month()))
+ .arg(d->date.day())
+ .arg(d->time.toString(Qt::TextDate))
+ .arg(d->date.year());
+ if (timeSpec() != Qt::LocalTime) {
+ buf += QStringLiteral(" GMT");
+ if (d->spec == QDateTimePrivate::OffsetFromUTC)
+ buf += toOffsetString(Qt::TextDate, d->m_offsetFromUtc);
}
+ return buf;
#endif
- buf += QLatin1Char(' ');
- buf += d->time.toString();
- buf += QLatin1Char(' ');
- buf += QString::number(d->date.year());
- }
-#endif
- else {
- buf = d->date.toString(f);
+ case Qt::ISODate:
+ buf = d->date.toString(Qt::ISODate);
if (buf.isEmpty())
return QString(); // failed to convert
- buf += QLatin1Char(' ');
- buf += d->time.toString(f);
+ buf += QLatin1Char('T');
+ buf += d->time.toString(Qt::ISODate);
+ switch (d->spec) {
+ case QDateTimePrivate::UTC:
+ buf += QLatin1Char('Z');
+ break;
+ case QDateTimePrivate::OffsetFromUTC:
+ buf += toOffsetString(Qt::ISODate, d->m_offsetFromUtc);
+ break;
+ default:
+ break;
+ }
+ return buf;
}
-
- return buf;
}
/*!
@@ -3675,55 +3630,27 @@ static int fromShortMonthName(const QString &monthName)
English short month names (e.g. "Jan"). Although localized month
names can also be used, they depend on the user's locale settings.
*/
-QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f)
+QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format)
{
- if (s.isEmpty()) {
+ if (string.isEmpty())
return QDateTime();
- }
-
- switch (f) {
- case Qt::ISODate: {
- QString tmp = s;
- Qt::TimeSpec ts = Qt::LocalTime;
- QDate date = QDate::fromString(tmp.left(10), Qt::ISODate);
- if (tmp.size() == 10)
- return QDateTime(date);
- tmp = tmp.mid(11);
-
- // Recognize UTC specifications
- if (tmp.endsWith(QLatin1Char('Z'))) {
- ts = Qt::UTC;
- tmp.chop(1);
- }
-
- // Recognize timezone specifications
- int offset = 0;
- const int signIndex = tmp.indexOf(QRegExp(QStringLiteral("[+-]")));
- if (signIndex >= 0) {
- bool ok;
- offset = fromOffsetString(tmp.mid(signIndex), &ok);
- if (!ok)
- return QDateTime();
- tmp = tmp.left(signIndex);
- ts = Qt::OffsetFromUTC;
- }
-
- bool isMidnight24 = false;
- // Might be end of day (24:00, including variants), which QTime considers invalid.
- QTime time(fromStringImpl(tmp, Qt::ISODate, isMidnight24));
- if (isMidnight24) {
- // ISO 8601 (section 4.2.3) says that 24:00 is equivalent to 00:00 the next day.
- date = date.addDays(1);
- }
-
- return QDateTime(date, time, ts, offset);
- }
+ switch (format) {
+ case Qt::SystemLocaleDate:
+ case Qt::SystemLocaleShortDate:
+ return QLocale::system().toDateTime(string, QLocale::ShortFormat);
+ case Qt::SystemLocaleLongDate:
+ return QLocale::system().toDateTime(string, QLocale::LongFormat);
+ case Qt::LocaleDate:
+ case Qt::DefaultLocaleShortDate:
+ return QLocale().toDateTime(string, QLocale::ShortFormat);
+ case Qt::DefaultLocaleLongDate:
+ return QLocale().toDateTime(string, QLocale::LongFormat);
case Qt::RFC2822Date: {
QDate date;
QTime time;
int utcOffset = 0;
- rfcDateImpl(s, &date, &time, &utcOffset);
+ rfcDateImpl(string, &date, &time, &utcOffset);
if (!date.isValid() || !time.isValid())
return QDateTime();
@@ -3732,81 +3659,115 @@ QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f)
dateTime.setOffsetFromUtc(utcOffset);
return dateTime;
}
- case Qt::SystemLocaleDate:
- case Qt::SystemLocaleShortDate:
- case Qt::SystemLocaleLongDate:
- return fromString(s, QLocale::system().dateTimeFormat(f == Qt::SystemLocaleLongDate ? QLocale::LongFormat
- : QLocale::ShortFormat));
- case Qt::LocaleDate:
- case Qt::DefaultLocaleShortDate:
- case Qt::DefaultLocaleLongDate:
- return fromString(s, QLocale().dateTimeFormat(f == Qt::DefaultLocaleLongDate ? QLocale::LongFormat
- : QLocale::ShortFormat));
+ case Qt::ISODate: {
+ const int size = string.size();
+ if (size < 10)
+ return QDateTime();
+
+ QString isoString = string;
+ Qt::TimeSpec spec = Qt::LocalTime;
+
+ QDate date = QDate::fromString(isoString.left(10), Qt::ISODate);
+ if (!date.isValid())
+ return QDateTime();
+ if (size == 10)
+ return QDateTime(date);
+
+ isoString.remove(0, 11);
+ int offset = 0;
+ // Check end of string for Time Zone definition, either Z for UTC or [+-]HH:MM for Offset
+ if (isoString.endsWith(QLatin1Char('Z'))) {
+ spec = Qt::UTC;
+ isoString.chop(1);
+ } else {
+ const int signIndex = isoString.indexOf(QRegExp(QStringLiteral("[+-]")));
+ if (signIndex >= 0) {
+ bool ok;
+ offset = fromOffsetString(isoString.mid(signIndex), &ok);
+ if (!ok)
+ return QDateTime();
+ isoString = isoString.left(signIndex);
+ spec = Qt::OffsetFromUTC;
+ }
+ }
+
+ // Might be end of day (24:00, including variants), which QTime considers invalid.
+ // ISO 8601 (section 4.2.3) says that 24:00 is equivalent to 00:00 the next day.
+ bool isMidnight24 = false;
+ QTime time = fromIsoTimeString(isoString, Qt::ISODate, &isMidnight24);
+ if (!time.isValid())
+ return QDateTime();
+ if (isMidnight24)
+ date = date.addDays(1);
+ return QDateTime(date, time, spec, offset);
+ }
#if !defined(QT_NO_TEXTDATE)
case Qt::TextDate: {
- QStringList parts = s.split(QLatin1Char(' '), QString::SkipEmptyParts);
+ QStringList parts = string.split(QLatin1Char(' '), QString::SkipEmptyParts);
- if ((parts.count() < 5) || (parts.count() > 6)) {
+ if ((parts.count() < 5) || (parts.count() > 6))
return QDateTime();
- }
// Accept "Sun Dec 1 13:02:00 1974" and "Sun 1. Dec 13:02:00 1974"
- int month = -1, day = -1;
- bool ok;
+ int month = 0;
+ int day = 0;
+ bool ok = false;
+ // First try month then day
month = fromShortMonthName(parts.at(1));
- if (month != -1) {
- day = parts.at(2).toInt(&ok);
- if (!ok)
- day = -1;
- }
+ if (month)
+ day = parts.at(2).toInt();
- if (month == -1 || day == -1) {
- // first variant failed, lets try the other
+ // If failed try day then month
+ if (!month || !day) {
month = fromShortMonthName(parts.at(2));
- if (month != -1) {
+ if (month) {
QString dayStr = parts.at(1);
if (dayStr.endsWith(QLatin1Char('.'))) {
dayStr.chop(1);
- day = dayStr.toInt(&ok);
- if (!ok)
- day = -1;
- } else {
- day = -1;
+ day = dayStr.toInt();
}
}
}
- if (month == -1 || day == -1) {
- // both variants failed, give up
+ // If both failed, give up
+ if (!month || !day)
return QDateTime();
- }
- int year;
- QStringList timeParts = parts.at(3).split(QLatin1Char(':'));
- if ((timeParts.count() == 3) || (timeParts.count() == 2)) {
- // Year is after time, e.g. "Sun Dec 1 13:02:00 1974"
- year = parts.at(4).toInt(&ok);
- if (!ok)
- return QDateTime();
- } else { // Year is before time, e.g. "Sun Dec 1 1974 13:02:00"
- timeParts = parts.at(4).split(QLatin1Char(':'));
- if ((timeParts.count() != 3) && (timeParts.count() != 2))
- return QDateTime();
- year = parts.at(3).toInt(&ok);
- if (!ok)
- return QDateTime();
+ // Year can be before or after time, "Sun Dec 1 1974 13:02:00" or "Sun Dec 1 13:02:00 1974"
+ // Guess which by looking for ':' in the time
+ int year = 0;
+ int yearPart = 0;
+ int timePart = 0;
+ if (parts.at(3).contains(QLatin1Char(':'))) {
+ yearPart = 4;
+ timePart = 3;
+ } else if (parts.at(4).contains(QLatin1Char(':'))) {
+ yearPart = 3;
+ timePart = 4;
+ } else {
+ return QDateTime();
}
+ year = parts.at(yearPart).toInt(&ok);
+ if (!ok)
+ return QDateTime();
+
+ QDate date(year, month, day);
+ if (!date.isValid())
+ return QDateTime();
+
+ QStringList timeParts = parts.at(timePart).split(QLatin1Char(':'));
+ if (timeParts.count() < 2 || timeParts.count() > 3)
+ return QDateTime();
+
int hour = timeParts.at(0).toInt(&ok);
- if (!ok) {
+ if (!ok)
return QDateTime();
- }
int minute = timeParts.at(1).toInt(&ok);
- if (!ok) {
+ if (!ok)
return QDateTime();
- }
int second = 0;
int millisecond = 0;
@@ -3829,8 +3790,9 @@ QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f)
}
}
- QDate date(year, month, day);
QTime time(hour, minute, second, millisecond);
+ if (!time.isValid())
+ return QDateTime();
if (parts.count() == 5)
return QDateTime(date, time, Qt::LocalTime);