summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qdatetime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qdatetime.cpp')
-rw-r--r--src/corelib/tools/qdatetime.cpp1592
1 files changed, 940 insertions, 652 deletions
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index d8e3a78cdf..ab5a516e8a 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -158,10 +158,135 @@ static const char monthDays[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,
static const char * const qt_shortMonthNames[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+int qt_monthNumberFromShortName(const QString &shortName)
+{
+ for (unsigned int i = 0; i < sizeof(qt_shortMonthNames) / sizeof(qt_shortMonthNames[0]); ++i) {
+ if (shortName == QLatin1String(qt_shortMonthNames[i]))
+ return i + 1;
+ }
+ return -1;
+}
#endif
+
#ifndef QT_NO_DATESTRING
-static QString fmtDateTime(const QString& f, const QTime* dt = 0, const QDate* dd = 0);
+static void rfcDateImpl(const QString &s, QDate *dd = 0, QTime *dt = 0, int *utfcOffset = 0);
#endif
+static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time);
+static void utcToOffset(QDate *date, QTime *time, qint32 offset);
+static QDate adjustDate(QDate date);
+
+// Return offset in [+-]HH:MM format
+// Qt::ISODate puts : between the hours and minutes, but Qt:TextDate does not
+static QString toOffsetString(Qt::DateFormat format, int offset)
+{
+ QString result;
+ if (format == Qt::TextDate)
+ result = QStringLiteral("%1%2%3");
+ else // Qt::ISODate
+ result = QStringLiteral("%1%2:%3");
+
+ return result.arg(offset >= 0 ? QLatin1Char('+') : QLatin1Char('-'))
+ .arg(qAbs(offset) / SECS_PER_HOUR, 2, 10, QLatin1Char('0'))
+ .arg((offset / 60) % 60, 2, 10, QLatin1Char('0'));
+}
+
+// Parse offset in [+-]HH[:]MM format
+static int fromOffsetString(const QString &offsetString, bool *valid)
+{
+ *valid = false;
+
+ const int size = offsetString.size();
+ if (size < 2 || size > 6)
+ return 0;
+
+ // First char must be + or -
+ const QChar sign = offsetString.at(0);
+ if (sign != QLatin1Char('+') && sign != QLatin1Char('-'))
+ return 0;
+
+ // Split the hour and minute parts
+ QStringList parts = offsetString.split(QLatin1Char(':'));
+ if (parts.count() == 1) {
+ // [+-]HHMM format
+ parts.append(parts.at(0).mid(3));
+ parts[0] = parts.at(0).left(3);
+ }
+
+ bool ok = false;
+ const int hour = parts.at(0).toInt(&ok);
+ if (!ok)
+ return 0;
+
+ const int minute = parts.at(1).toInt(&ok);
+ if (!ok || minute < 0 || minute > 59)
+ return 0;
+
+ *valid = true;
+ return ((hour * 60) + minute) * 60;
+}
+
+#if !defined(Q_OS_WINCE)
+// Calls the platform variant of mktime for the given date and time,
+// and updates the date, time, spec and abbreviation with the returned values
+// If the date falls outside the 1970 to 2037 range supported by mktime / time_t
+// then null date/time will be returned, you should call adjustDate() first if
+// you need a guaranteed result.
+static time_t qt_mktime(QDate *date, QTime *time, QDateTimePrivate::Spec *spec,
+ QString *abbreviation, bool *ok)
+{
+ if (ok)
+ *ok = false;
+ int yy, mm, dd;
+ date->getDate(&yy, &mm, &dd);
+ tm local;
+ local.tm_sec = time->second();
+ local.tm_min = time->minute();
+ local.tm_hour = time->hour();
+ local.tm_mday = dd;
+ local.tm_mon = mm - 1;
+ local.tm_year = yy - 1900;
+ local.tm_wday = 0;
+ local.tm_yday = 0;
+ local.tm_isdst = -1;
+#if defined(Q_OS_WIN)
+ _tzset();
+#else
+ tzset();
+#endif // Q_OS_WIN
+ const time_t secsSinceEpoch = mktime(&local);
+ if (secsSinceEpoch != time_t(-1)) {
+ *date = QDate(local.tm_year + 1900, local.tm_mon + 1, local.tm_mday);
+ *time = QTime(local.tm_hour, local.tm_min, local.tm_sec, time->msec());
+ if (local.tm_isdst == 1) {
+ if (spec)
+ *spec = QDateTimePrivate::LocalDST;
+ if (abbreviation)
+ *abbreviation = QString::fromLocal8Bit(tzname[1]);
+ } else if (local.tm_isdst == 0) {
+ if (spec)
+ *spec = QDateTimePrivate::LocalStandard;
+ if (abbreviation)
+ *abbreviation = QString::fromLocal8Bit(tzname[0]);
+ } else {
+ if (spec)
+ *spec = QDateTimePrivate::LocalUnknown;
+ if (abbreviation)
+ *abbreviation = QString::fromLocal8Bit(tzname[0]);
+ }
+ if (ok)
+ *ok = true;
+ } else {
+ *date = QDate();
+ *time = QTime();
+ if (spec)
+ *spec = QDateTimePrivate::LocalUnknown;
+ if (abbreviation)
+ *abbreviation = QString();
+ }
+ return secsSinceEpoch;
+}
+#endif // !Q_OS_WINCE
/*****************************************************************************
QDate member functions
@@ -543,8 +668,8 @@ int QDate::weekNumber(int *yearNumber) const
\li 12 = "Dec"
\endlist
- The month names will be localized according to the system's default
- locale settings.
+ The month names will be localized according to the system's
+ locale settings, i.e. using QLocale::system().
Returns an empty string if the date is invalid.
@@ -590,8 +715,8 @@ QString QDate::shortMonthName(int month, QDate::MonthNameType type)
\li 12 = "December"
\endlist
- The month names will be localized according to the system's default
- locale settings.
+ The month names will be localized according to the system's
+ locale settings, i.e. using QLocale::system().
Returns an empty string if the date is invalid.
@@ -632,8 +757,8 @@ QString QDate::longMonthName(int month, MonthNameType type)
\li 7 = "Sun"
\endlist
- The day names will be localized according to the system's default
- locale settings.
+ The day names will be localized according to the system's
+ locale settings, i.e. using QLocale::system().
Returns an empty string if the date is invalid.
@@ -674,8 +799,8 @@ QString QDate::shortDayName(int weekday, MonthNameType type)
\li 7 = "Sunday"
\endlist
- The day names will be localized according to the system's default
- locale settings.
+ The day names will be localized according to the system's
+ locale settings, i.e. using QLocale::system().
Returns an empty string if the date is invalid.
@@ -712,7 +837,7 @@ QString QDate::longDayName(int weekday, MonthNameType type)
If the \a format is Qt::TextDate, the string is formatted in
the default way. QDate::shortDayName() and QDate::shortMonthName()
are used to generate the string, so the day and month names will
- be localized names using the default locale from the system. An
+ be localized names using the system locale, i.e. QLocale::system(). An
example of this formatting is "Sat May 20 1995".
If the \a format is Qt::ISODate, the string format corresponds
@@ -735,6 +860,10 @@ QString QDate::longDayName(int weekday, MonthNameType type)
QLocale::ShortFormat) or QLocale().toString(date,
QLocale::LongFormat).
+ If the \a format is Qt::RFC2822Date, the string is formatted in
+ an \l{RFC 2822} compatible way. An example of this formatting is
+ "20 May 1995".
+
If the date is invalid, an empty string will be returned.
\warning The Qt::ISODate format is only valid for years in the
@@ -743,43 +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::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'));
}
}
@@ -795,18 +923,18 @@ QString QDate::toString(Qt::DateFormat f) const
\row \li dd \li the day as number with a leading zero (01 to 31)
\row \li ddd
\li the abbreviated localized day name (e.g. 'Mon' to 'Sun').
- Uses QDate::shortDayName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li dddd
\li the long localized day name (e.g. 'Monday' to 'Sunday').
- Uses QDate::longDayName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li M \li the month as number without a leading zero (1 to 12)
\row \li MM \li the month as number with a leading zero (01 to 12)
\row \li MMM
\li the abbreviated localized month name (e.g. 'Jan' to 'Dec').
- Uses QDate::shortMonthName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li MMMM
\li the long localized month name (e.g. 'January' to 'December').
- Uses QDate::longMonthName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li yy \li the year as two digit number (00 to 99)
\row \li yyyy \li the year as four digit number. If the year is negative,
a minus sign is prepended in addition.
@@ -829,18 +957,12 @@ QString QDate::toString(Qt::DateFormat f) const
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.
-
- \sa QDateTime::toString(), QTime::toString()
+ \sa QDateTime::toString(), QTime::toString(), QLocale::toString()
*/
QString QDate::toString(const QString& format) const
{
- if (year() > 9999)
- return QString();
- return fmtDateTime(format, 0, this);
+ return QLocale::system().toString(*this, format);
}
#endif //QT_NO_DATESTRING
@@ -1099,39 +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(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;
@@ -1150,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();
}
@@ -1190,18 +1304,18 @@ QDate QDate::fromString(const QString& s, Qt::DateFormat f)
\row \li dd \li The day as a number with a leading zero (01 to 31)
\row \li ddd
\li The abbreviated localized day name (e.g. 'Mon' to 'Sun').
- Uses QDate::shortDayName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li dddd
\li The long localized day name (e.g. 'Monday' to 'Sunday').
- Uses QDate::longDayName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li M \li The month as a number without a leading zero (1 to 12)
\row \li MM \li The month as a number with a leading zero (01 to 12)
\row \li MMM
\li The abbreviated localized month name (e.g. 'Jan' to 'Dec').
- Uses QDate::shortMonthName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li MMMM
\li The long localized month name (e.g. 'January' to 'December').
- Uses QDate::longMonthName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li yy \li The year as two digit number (00 to 99)
\row \li yyyy \li The year as four digit number. If the year is negative,
a minus sign is prepended in addition.
@@ -1474,15 +1588,15 @@ int QTime::msec() const
/*!
\overload
- Returns the time as a string. Milliseconds are not included. The
- \a format parameter determines the format of the string.
+ Returns the time as a string. The \a format parameter determines
+ the format of the string.
- If \a format is Qt::TextDate, the string format is HH:MM:SS; e.g. 1
- second before midnight would be "23:59:59".
+ If \a format is Qt::TextDate, the string format is HH:MM:SS.zzz;
+ e.g. 1 second before midnight would be "23:59:59.000".
If \a format is Qt::ISODate, the string format corresponds to the
- ISO 8601 extended specification for representations of dates,
- which is also HH:MM:SS.
+ ISO 8601 extended specification (with decimal fractions) for
+ representations of dates; also HH:MM:SS.zzz.
If the \a format is Qt::SystemLocaleShortDate or
Qt::SystemLocaleLongDate, the string format depends on the locale
@@ -1498,7 +1612,13 @@ int QTime::msec() const
QLocale::ShortFormat) or QLocale().toString(time,
QLocale::LongFormat).
+ If the \a format is Qt::RFC2822Date, the string is formatted in
+ an \l{RFC 2822} compatible way. An example of this formatting is
+ "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
@@ -1509,22 +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);
-
- default:
+ 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'));
case Qt::ISODate:
case Qt::TextDate:
- 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::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'));
}
}
@@ -1574,11 +1697,11 @@ QString QTime::toString(Qt::DateFormat format) const
If the time is invalid, an empty string will be returned.
If \a format is empty, the default format "hh:mm:ss" is used.
- \sa QDate::toString(), QDateTime::toString()
+ \sa QDate::toString(), QDateTime::toString(), QLocale::toString()
*/
QString QTime::toString(const QString& format) const
{
- return fmtDateTime(format, this, 0);
+ return QLocale::system().toString(*this, format);
}
#endif //QT_NO_DATESTRING
/*!
@@ -1759,99 +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::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)
@@ -1865,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);
+ }
}
/*!
@@ -2129,6 +2243,20 @@ int QTime::elapsed() const
time zone before 1970, even if the system's time zone database
supports that information.
+ \section2 Offset From UTC
+
+ A Qt::TimeSpec of Qt::OffsetFromUTC is also supported. This allows you
+ to define a QDateTime relative to UTC at a fixed offset of a given number
+ of seconds from UTC. For example, an offset of +3600 seconds is one hour
+ ahead of UTC and is usually written in ISO standard notation as
+ "UTC+01:00". Daylight Savings Time never applies with this TimeSpec.
+
+ There is no explicit size restriction to the offset seconds, but there is
+ an implicit limit imposed when using the toString() and fromString()
+ methods which use a format of [+|-]hh:mm, effectively limiting the range
+ to +/- 99 hours and 59 minutes and whole minutes only. Note that currently
+ no time zone lies outside the range of +/- 14 hours.
+
\sa QDate, QTime, QDateTimeEdit
*/
@@ -2150,10 +2278,8 @@ QDateTime::QDateTime()
*/
QDateTime::QDateTime(const QDate &date)
- : d(new QDateTimePrivate)
+ : d(new QDateTimePrivate(date, QTime(0, 0, 0), Qt::LocalTime, 0))
{
- d->date = date;
- d->time = QTime(0, 0, 0);
}
/*!
@@ -2161,14 +2287,72 @@ QDateTime::QDateTime(const QDate &date)
the time specification defined by \a spec.
If \a date is valid and \a time is not, the time will be set to midnight.
+
+ If \a spec is Qt::OffsetFromUTC then it will be set to Qt::UTC, i.e. an
+ offset of 0 seconds. To create a Qt::OffsetFromUTC datetime use the
+ correct constructor.
*/
QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec)
- : d(new QDateTimePrivate)
+ : d(new QDateTimePrivate(date, time, spec, 0))
{
- d->date = date;
- d->time = date.isValid() && !time.isValid() ? QTime(0, 0, 0) : time;
- d->spec = (spec == Qt::UTC) ? QDateTimePrivate::UTC : QDateTimePrivate::LocalUnknown;
+}
+
+/*!
+ \since 5.2
+
+ Constructs a datetime with the given \a date and \a time, using
+ the time specification defined by \a spec and \a offsetSeconds seconds.
+
+ If \a date is valid and \a time is not, the time will be set to midnight.
+
+ If the \a spec is not Qt::OffsetFromUTC then \a offsetSeconds will be ignored.
+
+ If the \a spec is Qt::OffsetFromUTC and \a offsetSeconds is 0 then the
+ timeSpec() will be set to Qt::UTC, i.e. an offset of 0 seconds.
+*/
+
+QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, int offsetSeconds)
+ : d(new QDateTimePrivate(date, time, spec, offsetSeconds))
+{
+}
+
+/*!
+ \internal
+ \since 5.2
+
+ Private.
+
+ Create a datetime with the given \a date, \a time, \a spec and \a offsetSeconds
+*/
+
+QDateTimePrivate::QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec,
+ int offsetSeconds)
+{
+ date = toDate;
+
+ if (!toTime.isValid() && toDate.isValid())
+ time = QTime(0, 0, 0);
+ else
+ time = toTime;
+
+ m_offsetFromUtc = 0;
+
+ switch (toSpec) {
+ case Qt::UTC :
+ spec = QDateTimePrivate::UTC;
+ break;
+ case Qt::OffsetFromUTC :
+ if (offsetSeconds == 0) {
+ spec = QDateTimePrivate::UTC;
+ } else {
+ spec = QDateTimePrivate::OffsetFromUTC;
+ m_offsetFromUtc = offsetSeconds;
+ }
+ break;
+ case Qt::LocalTime :
+ spec = QDateTimePrivate::LocalUnknown;
+ }
}
/*!
@@ -2271,6 +2455,77 @@ Qt::TimeSpec QDateTime::timeSpec() const
}
/*!
+ \since 5.2
+
+ Returns the current Offset From UTC in seconds.
+
+ If the timeSpec() is Qt::OffsetFromUTC this will be the value originally set.
+
+ If the timeSpec() is Qt::LocalTime this will be the difference between the
+ Local Time and UTC including any Daylight Saving Offset.
+
+ If the timeSpec() is Qt::UTC this will be 0.
+
+ \sa setOffsetFromUtc()
+*/
+
+int QDateTime::offsetFromUtc() const
+{
+ switch (d->spec) {
+ case QDateTimePrivate::OffsetFromUTC:
+ return d->m_offsetFromUtc;
+ case QDateTimePrivate::UTC:
+ return 0;
+ default: // Any Qt::LocalTime
+ const QDateTime fakeDate(d->date, d->time, Qt::UTC);
+ return (fakeDate.toMSecsSinceEpoch() - toMSecsSinceEpoch()) / 1000;
+ }
+}
+
+/*!
+ \since 5.2
+
+ Returns the Time Zone Abbreviation for the datetime.
+
+ If the timeSpec() is Qt::UTC this will be "UTC".
+
+ If the timeSpec() is Qt::OffsetFromUTC this will be in the format
+ "UTC[+-]00:00".
+
+ If the timeSpec() is Qt::LocalTime then the host system is queried for the
+ correct abbreviation.
+
+ Note that abbreviations may or may not be localized.
+
+ Note too that the abbreviation is not guaranteed to be a unique value,
+ i.e. different time zones may have the same abbreviation.
+
+ \sa timeSpec()
+*/
+
+QString QDateTime::timeZoneAbbreviation() const
+{
+ switch (d->spec) {
+ case QDateTimePrivate::UTC:
+ return QStringLiteral("UTC");
+ case QDateTimePrivate::OffsetFromUTC:
+ return QLatin1String("UTC") + toOffsetString(Qt::ISODate, d->m_offsetFromUtc);
+ default: { // Any Qt::LocalTime
+#if defined(Q_OS_WINCE)
+ // TODO Stub to enable compilation on WinCE
+ return QString();
+#else
+ QDate dt = adjustDate(d->date);
+ QTime tm = d->time;
+ QString abbrev;
+ qt_mktime(&dt, &tm, 0, &abbrev, 0);
+ return abbrev;
+#endif // !Q_OS_WINCE
+ }
+ }
+}
+
+/*!
Sets the date part of this datetime to \a date.
If no time is set, it is set to midnight.
@@ -2307,6 +2562,9 @@ void QDateTime::setTime(const QTime &time)
Sets the time specification used in this datetime to \a spec.
The datetime will refer to a different point in time.
+ If \a spec is Qt::OffsetFromUTC then the timeSpec() will be set
+ to Qt::UTC, i.e. an effective offset of 0.
+
Example:
\snippet code/src_corelib_tools_qdatetime.cpp 19
@@ -2317,17 +2575,43 @@ void QDateTime::setTimeSpec(Qt::TimeSpec spec)
{
detach();
- switch(spec)
- {
- case Qt::UTC:
- d->spec = QDateTimePrivate::UTC;
- break;
- case Qt::OffsetFromUTC:
- d->spec = QDateTimePrivate::OffsetFromUTC;
- break;
- default:
- d->spec = QDateTimePrivate::LocalUnknown;
- break;
+ d->m_offsetFromUtc = 0;
+ switch (spec) {
+ case Qt::UTC:
+ case Qt::OffsetFromUTC:
+ d->spec = QDateTimePrivate::UTC;
+ break;
+ default:
+ d->spec = QDateTimePrivate::LocalUnknown;
+ break;
+ }
+}
+
+/*!
+ \since 5.2
+
+ Sets the timeSpec() to Qt::OffsetFromUTC and the offset to \a offsetSeconds.
+ The datetime will refer to a different point in time.
+
+ The maximum and minimum offset is 14 positive or negative hours. If
+ \a offsetSeconds is larger or smaller than that, then the result is
+ undefined.
+
+ If \a offsetSeconds is 0 then the timeSpec() will be set to Qt::UTC.
+
+ \sa isValid(), offsetFromUtc()
+*/
+
+void QDateTime::setOffsetFromUtc(int offsetSeconds)
+{
+ detach();
+
+ if (offsetSeconds == 0) {
+ d->spec = QDateTimePrivate::UTC;
+ d->m_offsetFromUtc = 0;
+ } else {
+ d->spec = QDateTimePrivate::OffsetFromUTC;
+ d->m_offsetFromUtc = offsetSeconds;
}
}
@@ -2410,8 +2694,6 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
{
detach();
- QDateTimePrivate::Spec oldSpec = d->spec;
-
qint64 ddays = msecs / MSECS_PER_DAY;
msecs %= MSECS_PER_DAY;
if (msecs < 0) {
@@ -2422,10 +2704,11 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
d->date = QDate(1970, 1, 1).addDays(ddays);
d->time = QTime(0, 0, 0).addMSecs(msecs);
- d->spec = QDateTimePrivate::UTC;
- if (oldSpec != QDateTimePrivate::UTC)
- d->spec = d->getLocal(d->date, d->time);
+ if (d->spec == QDateTimePrivate::OffsetFromUTC)
+ utcToOffset(&d->date, &d->time, d->m_offsetFromUtc);
+ else if (d->spec != QDateTimePrivate::UTC)
+ utcToLocal(d->date, d->time);
}
/*!
@@ -2443,14 +2726,13 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC)
{
detach();
- QDateTimePrivate::Spec oldSpec = d->spec;
-
d->date = QDate(1970, 1, 1).addDays(secsSince1Jan1970UTC / SECS_PER_DAY);
d->time = QTime(0, 0, 0).addSecs(secsSince1Jan1970UTC % SECS_PER_DAY);
- d->spec = QDateTimePrivate::UTC;
- if (oldSpec != QDateTimePrivate::UTC)
- d->spec = d->getLocal(d->date, d->time);
+ if (d->spec == QDateTimePrivate::OffsetFromUTC)
+ utcToOffset(&d->date, &d->time, d->m_offsetFromUtc);
+ else if (d->spec != QDateTimePrivate::UTC)
+ utcToLocal(d->date, d->time);
}
#ifndef QT_NO_DATESTRING
@@ -2464,16 +2746,17 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC)
If the \a format is Qt::TextDate, the string is formatted in
the default way. QDate::shortDayName(), QDate::shortMonthName(),
and QTime::toString() are used to generate the string, so the
- day and month names will be localized names. An example of this
- formatting is "Wed May 20 03:40:13 1998".
+ day and month names will be localized names using the system locale,
+ i.e. QLocale::system(). An example of this formatting is
+ "Wed May 20 03:40:13.456 1998".
If the \a format is Qt::ISODate, the string format corresponds
- to the ISO 8601 extended specification for representations of
- dates and times, taking the form YYYY-MM-DDTHH:MM:SS[Z|[+|-]HH:MM],
- depending on the timeSpec() of the QDateTime. If the timeSpec()
- is Qt::UTC, Z will be appended to the string; if the timeSpec() is
- Qt::OffsetFromUTC, the offset in hours and minutes from UTC will
- be appended to the string.
+ to the ISO 8601 extended specification (with decimal fractions) for
+ representations of dates and times, taking the form
+ YYYY-MM-DDTHH:MM:SS.zzz[Z|[+|-]HH:MM], depending on the timeSpec()
+ of the QDateTime. If the timeSpec() is Qt::UTC, Z will be appended
+ to the string; if the timeSpec() is Qt::OffsetFromUTC, the offset
+ in hours and minutes from UTC will be appended to the string.
If the \a format is Qt::SystemLocaleShortDate or
Qt::SystemLocaleLongDate, the string format depends on the locale
@@ -2489,6 +2772,9 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC)
QLocale::ShortFormat) or QLocale().toString(datetime,
QLocale::LongFormat).
+ If the \a format is Qt::RFC2822Date, the string is formatted
+ following \l{RFC 2822}.
+
If the datetime is invalid, an empty string will be returned.
\warning The Qt::ISODate format is only valid for years in the
@@ -2498,13 +2784,64 @@ 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) {
+ 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;
+ if (timeSpec() == Qt::LocalTime) {
+ QDateTime utc = toUTC();
+ utc.setTimeSpec(timeSpec());
+ utcOffset = utc.secsTo(*this);
+ }
+
+ const int offset = qAbs(utcOffset);
+ buf += QLatin1Char((offset == utcOffset) ? '+' : '-');
+
+ const int hour = offset / 3600;
+ if (hour < 10)
+ buf += QLatin1Char('0');
+ buf += QString::number(hour);
+
+ const int min = (offset - (hour * 3600)) / 60;
+ if (min < 10)
+ buf += QLatin1Char('0');
+ buf += QString::number(min);
+ return buf;
+ }
+ default:
+#ifndef QT_NO_TEXTDATE
+ 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
+ case Qt::ISODate:
buf = d->date.toString(Qt::ISODate);
if (buf.isEmpty())
return QString(); // failed to convert
@@ -2514,61 +2851,14 @@ QString QDateTime::toString(Qt::DateFormat f) const
case QDateTimePrivate::UTC:
buf += QLatin1Char('Z');
break;
- case QDateTimePrivate::OffsetFromUTC: {
- int sign = d->utcOffset >= 0 ? 1: -1;
- buf += QString::fromLatin1("%1%2:%3").
- arg(sign == 1 ? QLatin1Char('+') : QLatin1Char('-')).
- arg(d->utcOffset * sign / SECS_PER_HOUR, 2, 10, QLatin1Char('0')).
- arg((d->utcOffset / 60) % 60, 2, 10, QLatin1Char('0'));
+ case QDateTimePrivate::OffsetFromUTC:
+ buf += toOffsetString(Qt::ISODate, d->m_offsetFromUtc);
break;
- }
default:
break;
}
+ return buf;
}
-#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());
- }
-#endif
- buf += QLatin1Char(' ');
- buf += d->time.toString();
- buf += QLatin1Char(' ');
- buf += QString::number(d->date.year());
- }
-#endif
- else {
- buf = d->date.toString(f);
- if (buf.isEmpty())
- return QString(); // failed to convert
- buf += QLatin1Char(' ');
- buf += d->time.toString(f);
- }
-
- return buf;
}
/*!
@@ -2583,18 +2873,18 @@ QString QDateTime::toString(Qt::DateFormat f) const
\row \li dd \li the day as number with a leading zero (01 to 31)
\row \li ddd
\li the abbreviated localized day name (e.g. 'Mon' to 'Sun').
- Uses QDate::shortDayName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li dddd
\li the long localized day name (e.g. 'Monday' to 'Qt::Sunday').
- Uses QDate::longDayName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li M \li the month as number without a leading zero (1-12)
\row \li MM \li the month as number with a leading zero (01-12)
\row \li MMM
\li the abbreviated localized month name (e.g. 'Jan' to 'Dec').
- Uses QDate::shortMonthName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li MMMM
\li the long localized month name (e.g. 'January' to 'December').
- Uses QDate::longMonthName().
+ Uses the system locale to localize the name, i.e. QLocale::system().
\row \li yy \li the year as two digit number (00-99)
\row \li yyyy \li the year as four digit number
\endtable
@@ -2607,16 +2897,21 @@ QString QDateTime::toString(Qt::DateFormat f) const
\li the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
\row \li hh
\li the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
+ \row \li H
+ \li the hour without a leading zero (0 to 23, even with AM/PM display)
+ \row \li HH
+ \li the hour with a leading zero (00 to 23, even with AM/PM display)
\row \li m \li the minute without a leading zero (0 to 59)
\row \li mm \li the minute with a leading zero (00 to 59)
\row \li s \li the second without a leading zero (0 to 59)
\row \li ss \li the second with a leading zero (00 to 59)
\row \li z \li the milliseconds without leading zeroes (0 to 999)
\row \li zzz \li the milliseconds with leading zeroes (000 to 999)
- \row \li AP
- \li use AM/PM display. \e AP will be replaced by either "AM" or "PM".
- \row \li ap
- \li use am/pm display. \e ap will be replaced by either "am" or "pm".
+ \row \li AP or A
+ \li use AM/PM display. \e A/AP will be replaced by either "AM" or "PM".
+ \row \li ap or a
+ \li use am/pm display. \e a/ap will be replaced by either "am" or "pm".
+ \row \li t \li the timezone (for example "CEST")
\endtable
All other input characters will be ignored. Any sequence of characters that
@@ -2637,11 +2932,11 @@ QString QDateTime::toString(Qt::DateFormat f) const
If the datetime is invalid, an empty string will be returned.
- \sa QDate::toString(), QTime::toString()
+ \sa QDate::toString(), QTime::toString(), QLocale::toString()
*/
QString QDateTime::toString(const QString& format) const
{
- return fmtDateTime(format, &d->time, &d->date);
+ return QLocale::system().toString(*this, format);
}
#endif //QT_NO_DATESTRING
@@ -2655,7 +2950,10 @@ QString QDateTime::toString(const QString& format) const
QDateTime QDateTime::addDays(qint64 ndays) const
{
- return QDateTime(d->date.addDays(ndays), d->time, timeSpec());
+ QDateTime dt(*this);
+ dt.detach();
+ dt.d->date = d->date.addDays(ndays);
+ return dt;
}
/*!
@@ -2668,7 +2966,10 @@ QDateTime QDateTime::addDays(qint64 ndays) const
QDateTime QDateTime::addMonths(int nmonths) const
{
- return QDateTime(d->date.addMonths(nmonths), d->time, timeSpec());
+ QDateTime dt(*this);
+ dt.detach();
+ dt.d->date = d->date.addMonths(nmonths);
+ return dt;
}
/*!
@@ -2681,7 +2982,10 @@ QDateTime QDateTime::addMonths(int nmonths) const
QDateTime QDateTime::addYears(int nyears) const
{
- return QDateTime(d->date.addYears(nyears), d->time, timeSpec());
+ QDateTime dt(*this);
+ dt.detach();
+ dt.d->date = d->date.addYears(nyears);
+ return dt;
}
QDateTime QDateTimePrivate::addMSecs(const QDateTime &dt, qint64 msecs)
@@ -2692,10 +2996,13 @@ QDateTime QDateTimePrivate::addMSecs(const QDateTime &dt, qint64 msecs)
QDate utcDate;
QTime utcTime;
dt.d->getUTC(utcDate, utcTime);
-
addMSecs(utcDate, utcTime, msecs);
+ QDateTime utc(utcDate, utcTime, Qt::UTC);
- return QDateTime(utcDate, utcTime, Qt::UTC).toTimeSpec(dt.timeSpec());
+ if (dt.timeSpec() == Qt::OffsetFromUTC)
+ return utc.toOffsetFromUtc(dt.d->m_offsetFromUtc);
+ else
+ return utc.toTimeSpec(dt.timeSpec());
}
/*!
@@ -2846,12 +3153,14 @@ qint64 QDateTime::msecsTo(const QDateTime &other) const
+ static_cast<qint64>(selfTime.msecsTo(otherTime));
}
-
/*!
- \fn QDateTime QDateTime::toTimeSpec(Qt::TimeSpec specification) const
+ \fn QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
Returns a copy of this datetime converted to the given time
- \a specification.
+ \a spec.
+
+ If \a spec is Qt::OffsetFromUTC then it is set to Qt::UTC. To set to a
+ spec of Qt::OffsetFromUTC use toOffsetFromUtc().
Example:
\snippet code/src_corelib_tools_qdatetime.cpp 16
@@ -2861,19 +3170,41 @@ qint64 QDateTime::msecsTo(const QDateTime &other) const
QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
{
- if ((d->spec == QDateTimePrivate::UTC) == (spec == Qt::UTC))
- return *this;
+ if (spec == Qt::UTC || spec == Qt::OffsetFromUTC) {
+ QDate date;
+ QTime time;
+ d->getUTC(date, time);
+ return QDateTime(date, time, Qt::UTC, 0);
+ }
QDateTime ret;
- if (spec == Qt::UTC) {
- d->getUTC(ret.d->date, ret.d->time);
- ret.d->spec = QDateTimePrivate::UTC;
- } else {
- ret.d->spec = d->getLocal(ret.d->date, ret.d->time);
- }
+ ret.d->spec = d->getLocal(ret.d->date, ret.d->time);
return ret;
}
+
+/*!
+ \since 5.2
+
+ \fn QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const
+
+ Returns a copy of this datetime converted to a spec of Qt::OffsetFromUTC
+ with the given \a offsetSeconds.
+
+ If the \a offsetSeconds equals 0 then a UTC datetime will be returned
+
+ \sa setOffsetFromUtc(), offsetFromUtc(), toTimeSpec()
+*/
+
+QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const
+{
+ QDate date;
+ QTime time;
+ d->getUTC(date, time);
+ d->addMSecs(date, time, offsetSeconds * 1000);
+ return QDateTime(date, time, Qt::OffsetFromUTC, offsetSeconds);
+}
+
/*!
Returns true if this datetime is equal to the \a other datetime;
otherwise returns false.
@@ -2883,7 +3214,7 @@ QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
bool QDateTime::operator==(const QDateTime &other) const
{
- if (d->spec == other.d->spec && d->utcOffset == other.d->utcOffset)
+ if (d->spec == other.d->spec && d->m_offsetFromUtc == other.d->m_offsetFromUtc)
return d->time == other.d->time && d->date == other.d->date;
else {
QDate date1, date2;
@@ -3160,16 +3491,32 @@ qint64 QDateTime::currentMSecsSinceEpoch() Q_DECL_NOTHROW
Returns a datetime whose date and time are the number of \a seconds
that have passed since 1970-01-01T00:00:00, Coordinated Universal
- Time (Qt::UTC). On systems that do not support time zones, the time
- will be set as if local time were Qt::UTC.
+ Time (Qt::UTC) and converted to Qt::LocalTime. On systems that do not
+ support time zones, the time will be set as if local time were Qt::UTC.
\sa toTime_t(), setTime_t()
*/
QDateTime QDateTime::fromTime_t(uint seconds)
{
- QDateTime d;
- d.setTime_t(seconds);
- return d;
+ return fromMSecsSinceEpoch((qint64)seconds * 1000, Qt::LocalTime);
+}
+
+/*!
+ \since 5.2
+
+ Returns a datetime whose date and time are the number of \a seconds
+ that have passed since 1970-01-01T00:00:00, Coordinated Universal
+ Time (Qt::UTC) and converted to the given \a spec.
+
+ If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
+ ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
+ then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds.
+
+ \sa toTime_t(), setTime_t()
+*/
+QDateTime QDateTime::fromTime_t(uint seconds, Qt::TimeSpec spec, int offsetSeconds)
+{
+ return fromMSecsSinceEpoch((qint64)seconds * 1000, spec, offsetSeconds);
}
/*!
@@ -3177,8 +3524,8 @@ QDateTime QDateTime::fromTime_t(uint seconds)
Returns a datetime whose date and time are the number of milliseconds, \a msecs,
that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
- Time (Qt::UTC). On systems that do not support time zones, the time
- will be set as if local time were Qt::UTC.
+ Time (Qt::UTC), and converted to Qt::LocalTime. On systems that do not
+ support time zones, the time will be set as if local time were Qt::UTC.
Note that there are possible values for \a msecs that lie outside the valid
range of QDateTime, both negative and positive. The behavior of this
@@ -3188,67 +3535,79 @@ QDateTime QDateTime::fromTime_t(uint seconds)
*/
QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs)
{
- QDateTime d;
- d.setMSecsSinceEpoch(msecs);
- return d;
+ return fromMSecsSinceEpoch(msecs, Qt::LocalTime);
}
/*!
- \since 4.4
- \internal
+ \since 5.2
- Sets the offset from UTC to \a seconds, and also sets timeSpec() to
- Qt::OffsetFromUTC.
+ Returns a datetime whose date and time are the number of milliseconds \a msecs
+ that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
+ Time (Qt::UTC) and converted to the given \a spec.
- The maximum and minimum offset is 14 positive or negative hours. If
- \a seconds is larger or smaller than that, the result is undefined.
+ Note that there are possible values for \a msecs that lie outside the valid
+ range of QDateTime, both negative and positive. The behavior of this
+ function is undefined for those values.
- 0 as offset is identical to UTC. Therefore, if \a seconds is 0, the
- timeSpec() will be set to Qt::UTC. Hence the UTC offset always
- relates to UTC, and can never relate to local time.
+ If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
+ ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
+ then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds.
- \sa isValid(), utcOffset()
- */
-void QDateTime::setUtcOffset(int seconds)
+ \sa fromTime_t()
+*/
+QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetSeconds)
{
- detach();
-
- /* The motivation to also setting d->spec is to ensure that the QDateTime
- * instance stays in well-defined states all the time; instead of that,
- * we instruct the user to ensure it. */
- if(seconds == 0)
- d->spec = QDateTimePrivate::UTC;
- else
- d->spec = QDateTimePrivate::OffsetFromUTC;
+ QDate newDate = QDate(1970, 1, 1);
+ QTime newTime = QTime(0, 0, 0);
+ QDateTimePrivate::addMSecs(newDate, newTime, msecs);
- /* Even if seconds is 0 we assign it to utcOffset. */
- d->utcOffset = seconds;
+ switch (spec) {
+ case Qt::UTC:
+ return QDateTime(newDate, newTime, Qt::UTC);
+ case Qt::OffsetFromUTC:
+ utcToOffset(&newDate, &newTime, offsetSeconds);
+ return QDateTime(newDate, newTime, Qt::OffsetFromUTC, offsetSeconds);
+ default:
+ utcToLocal(newDate, newTime);
+ return QDateTime(newDate, newTime, Qt::LocalTime);
+ }
}
+#if QT_DEPRECATED_SINCE(5, 2)
/*!
- \since 4.4
- \internal
-
- Returns the UTC offset in seconds. If the timeSpec() isn't
- Qt::OffsetFromUTC, 0 is returned. However, since 0 is a valid UTC
- offset, the return value of this function cannot be used to determine
- whether a utcOffset() is used or is valid; in that case, timeSpec() must be
- checked.
+ \since 4.4
+ \internal
+ \obsolete
- Likewise, if this QDateTime() is invalid or if timeSpec() isn't
- Qt::OffsetFromUTC, 0 is returned.
+ This method was added in 4.4 but never documented as public. It was replaced
+ in 5.2 with public method setOffsetFromUtc() for consistency with QTimeZone.
- The UTC offset only applies if the timeSpec() is Qt::OffsetFromUTC.
+ This method should never be made public.
- \sa isValid(), setUtcOffset()
+ \sa setOffsetFromUtc()
*/
+void QDateTime::setUtcOffset(int seconds)
+{
+ setOffsetFromUtc(seconds);
+}
+
+/*!
+ \since 4.4
+ \internal
+ \obsolete
+
+ This method was added in 4.4 but never documented as public. It was replaced
+ in 5.1 with public method offsetFromUTC() for consistency with QTimeZone.
+
+ This method should never be made public.
+
+ \sa offsetFromUTC()
+*/
int QDateTime::utcOffset() const
{
- if(isValid() && d->spec == QDateTimePrivate::OffsetFromUTC)
- return d->utcOffset;
- else
- return 0;
+ return offsetFromUtc();
}
+#endif // QT_DEPRECATED_SINCE
#ifndef QT_NO_DATESTRING
@@ -3277,144 +3636,169 @@ 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) {
+ 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(string, &date, &time, &utcOffset);
+
+ if (!date.isValid() || !time.isValid())
+ return QDateTime();
+
+ QDateTime dateTime(date, time, Qt::UTC);
+ dateTime.setOffsetFromUtc(utcOffset);
+ return dateTime;
+ }
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);
+ const int size = string.size();
+ if (size < 10)
+ return QDateTime();
- tmp = tmp.mid(11);
+ QString isoString = string;
+ Qt::TimeSpec spec = Qt::LocalTime;
- // Recognize UTC specifications
- if (tmp.endsWith(QLatin1Char('Z'))) {
- ts = Qt::UTC;
- tmp.chop(1);
- }
+ QDate date = QDate::fromString(isoString.left(10), Qt::ISODate);
+ if (!date.isValid())
+ return QDateTime();
+ if (size == 10)
+ return QDateTime(date);
- // Recognize timezone specifications
- QRegExp rx(QLatin1String("[+-]"));
- if (tmp.contains(rx)) {
- int idx = tmp.indexOf(rx);
- QString tmp2 = tmp.mid(idx);
- tmp = tmp.left(idx);
- bool ok = true;
- int ntzhour = 1;
- int ntzminute = 3;
- if ( tmp2.indexOf(QLatin1Char(':')) == 3 )
- ntzminute = 4;
- const int tzhour(tmp2.mid(ntzhour, 2).toInt(&ok));
- const int tzminute(tmp2.mid(ntzminute, 2).toInt(&ok));
- QTime tzt(tzhour, tzminute);
- int utcOffset = (tzt.hour() * 60 + tzt.minute()) * 60;
- if ( utcOffset != 0 ) {
- ts = Qt::OffsetFromUTC;
- QDateTime dt(date, QTime::fromString(tmp, Qt::ISODate), ts);
- dt.setUtcOffset( utcOffset * (tmp2.startsWith(QLatin1Char('-')) ? -1 : 1) );
- return dt;
+ 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;
}
}
- 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.
+ // 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, ts);
+ return QDateTime(date, time, spec, offset);
}
- 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));
#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 = (timeParts.count() > 2) ? timeParts.at(2).toInt(&ok) : 0;
- if (!ok) {
- return QDateTime();
+ int second = 0;
+ int millisecond = 0;
+ if (timeParts.count() > 2) {
+ QStringList secondParts = timeParts.at(2).split(QLatin1Char('.'));
+ if (secondParts.size() > 2) {
+ return QDateTime();
+ }
+
+ second = secondParts.first().toInt(&ok);
+ if (!ok) {
+ return QDateTime();
+ }
+
+ if (secondParts.size() > 1) {
+ millisecond = secondParts.last().toInt(&ok);
+ if (!ok) {
+ return QDateTime();
+ }
+ }
}
- QDate date(year, month, day);
- QTime time(hour, minute, second);
+ QTime time(hour, minute, second, millisecond);
+ if (!time.isValid())
+ return QDateTime();
if (parts.count() == 5)
return QDateTime(date, time, Qt::LocalTime);
@@ -3422,26 +3806,15 @@ QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f)
QString tz = parts.at(5);
if (!tz.startsWith(QLatin1String("GMT"), Qt::CaseInsensitive))
return QDateTime();
- QDateTime dt(date, time, Qt::UTC);
- if (tz.length() > 3) {
- int tzoffset = 0;
- QChar sign = tz.at(3);
- if ((sign != QLatin1Char('+'))
- && (sign != QLatin1Char('-'))) {
- return QDateTime();
- }
- int tzhour = tz.mid(4, 2).toInt(&ok);
- if (!ok)
- return QDateTime();
- int tzminute = tz.mid(6).toInt(&ok);
+ tz.remove(0, 3);
+ if (!tz.isEmpty()) {
+ int offset = fromOffsetString(tz, &ok);
if (!ok)
return QDateTime();
- tzoffset = (tzhour*60 + tzminute) * 60;
- if (sign == QLatin1Char('-'))
- tzoffset = -tzoffset;
- dt.setUtcOffset(tzoffset);
+ return QDateTime(date, time, Qt::OffsetFromUTC, offset);
+ } else {
+ return QDateTime(date, time, Qt::UTC);
}
- return dt.toLocalTime();
}
#endif //QT_NO_TEXTDATE
}
@@ -3691,7 +4064,7 @@ QDataStream &operator>>(QDataStream &in, QTime &time)
*/
QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime)
{
- if (out.version() == 13) {
+ if (out.version() == QDataStream::Qt_5_0) {
if (dateTime.isValid()) {
// This approach is wrong and should not be used again; it breaks
// the guarantee that a deserialised local datetime is the same time
@@ -3704,8 +4077,12 @@ QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime)
out << (qint8)dateTime.timeSpec();
} else {
out << dateTime.d->date << dateTime.d->time;
- if (out.version() >= 7)
+ if (out.version() >= QDataStream::Qt_4_0)
out << (qint8)dateTime.d->spec;
+ if (out.version() >= QDataStream::Qt_5_2
+ && dateTime.d->spec == QDateTimePrivate::OffsetFromUTC) {
+ out << qint32(dateTime.offsetFromUtc());
+ }
}
return out;
}
@@ -3724,220 +4101,98 @@ QDataStream &operator>>(QDataStream &in, QDateTime &dateTime)
in >> dateTime.d->date >> dateTime.d->time;
- if (in.version() == 13) {
+ if (in.version() == QDataStream::Qt_5_0) {
qint8 ts = 0;
in >> ts;
if (dateTime.isValid()) {
- // We always store the datetime as UTC in 13 onwards.
+ // We incorrectly stored the datetime as UTC in Qt_5_0.
dateTime.d->spec = QDateTimePrivate::UTC;
dateTime = dateTime.toTimeSpec(static_cast<Qt::TimeSpec>(ts));
}
} else {
qint8 ts = (qint8)QDateTimePrivate::LocalUnknown;
- if (in.version() >= 7)
+ if (in.version() >= QDataStream::Qt_4_0)
in >> ts;
+ qint32 offset = 0;
+ if (in.version() >= QDataStream::Qt_5_2 && ts == qint8(QDateTimePrivate::OffsetFromUTC))
+ in >> offset;
dateTime.d->spec = (QDateTimePrivate::Spec)ts;
+ dateTime.d->m_offsetFromUtc = offset;
}
return in;
}
#endif // QT_NO_DATASTREAM
-
-// checks if there is an unquoted 'AP' or 'ap' in the string
-static bool hasUnquotedAP(const QString &f)
-{
- const QLatin1Char quote('\'');
- bool inquote = false;
- const int max = f.size();
- for (int i=0; i<max; ++i) {
- if (f.at(i) == quote) {
- inquote = !inquote;
- } else if (!inquote && f.at(i).toUpper() == QLatin1Char('A')) {
- return true;
- }
- }
- return false;
-}
-
-#ifndef QT_NO_DATESTRING
/*****************************************************************************
Some static function used by QDate, QTime and QDateTime
*****************************************************************************/
-// Replaces tokens by their value. See QDateTime::toString() for a list of valid tokens
-static QString getFmtString(const QString& f, const QTime* dt = 0, const QDate* dd = 0, bool am_pm = false)
-{
- if (f.isEmpty())
- return QString();
-
- QString buf = f;
- int removed = 0;
-
- if (dt) {
- if (f.startsWith(QLatin1String("hh")) || f.startsWith(QLatin1String("HH"))) {
- const bool hour12 = f.at(0) == QLatin1Char('h') && am_pm;
- if (hour12 && dt->hour() > 12)
- buf = QString::number(dt->hour() - 12).rightJustified(2, QLatin1Char('0'), true);
- else if (hour12 && dt->hour() == 0)
- buf = QLatin1String("12");
- else
- buf = QString::number(dt->hour()).rightJustified(2, QLatin1Char('0'), true);
- removed = 2;
- } else if (f.at(0) == QLatin1Char('h') || f.at(0) == QLatin1Char('H')) {
- const bool hour12 = f.at(0) == QLatin1Char('h') && am_pm;
- if (hour12 && dt->hour() > 12)
- buf = QString::number(dt->hour() - 12);
- else if (hour12 && dt->hour() == 0)
- buf = QLatin1String("12");
- else
- buf = QString::number(dt->hour());
- removed = 1;
- } else if (f.startsWith(QLatin1String("mm"))) {
- buf = QString::number(dt->minute()).rightJustified(2, QLatin1Char('0'), true);
- removed = 2;
- } else if (f.at(0) == (QLatin1Char('m'))) {
- buf = QString::number(dt->minute());
- removed = 1;
- } else if (f.startsWith(QLatin1String("ss"))) {
- buf = QString::number(dt->second()).rightJustified(2, QLatin1Char('0'), true);
- removed = 2;
- } else if (f.at(0) == QLatin1Char('s')) {
- buf = QString::number(dt->second());
- } else if (f.startsWith(QLatin1String("zzz"))) {
- buf = QString::number(dt->msec()).rightJustified(3, QLatin1Char('0'), true);
- removed = 3;
- } else if (f.at(0) == QLatin1Char('z')) {
- buf = QString::number(dt->msec());
- removed = 1;
- } else if (f.at(0).toUpper() == QLatin1Char('A')) {
- const bool upper = f.at(0) == QLatin1Char('A');
- buf = dt->hour() < 12 ? QLatin1String("am") : QLatin1String("pm");
- if (upper)
- buf = buf.toUpper();
- if (f.size() > 1 && f.at(1).toUpper() == QLatin1Char('P') &&
- f.at(0).isUpper() == f.at(1).isUpper()) {
- removed = 2;
- } else {
- removed = 1;
- }
+#ifndef QT_NO_DATESTRING
+static void rfcDateImpl(const QString &s, QDate *dd, QTime *dt, int *utcOffset)
+{
+ int day = -1;
+ int month = -1;
+ int year = -1;
+ int hour = -1;
+ int min = -1;
+ int sec = -1;
+ int hourOffset = 0;
+ int minOffset = 0;
+ bool positiveOffset = false;
+
+ // Matches "Wdy, DD Mon YYYY HH:MM:SS ±hhmm" (Wdy, being optional)
+ QRegExp rex(QStringLiteral("^(?:[A-Z][a-z]+,)?[ \\t]*(\\d{1,2})[ \\t]+([A-Z][a-z]+)[ \\t]+(\\d\\d\\d\\d)(?:[ \\t]+(\\d\\d):(\\d\\d)(?::(\\d\\d))?)?[ \\t]*(?:([+-])(\\d\\d)(\\d\\d))?"));
+ if (s.indexOf(rex) == 0) {
+ if (dd) {
+ day = rex.cap(1).toInt();
+ month = qt_monthNumberFromShortName(rex.cap(2));
+ year = rex.cap(3).toInt();
}
- }
-
- if (dd) {
- if (f.startsWith(QLatin1String("dddd"))) {
- buf = dd->longDayName(dd->dayOfWeek());
- removed = 4;
- } else if (f.startsWith(QLatin1String("ddd"))) {
- buf = dd->shortDayName(dd->dayOfWeek());
- removed = 3;
- } else if (f.startsWith(QLatin1String("dd"))) {
- buf = QString::number(dd->day()).rightJustified(2, QLatin1Char('0'), true);
- removed = 2;
- } else if (f.at(0) == QLatin1Char('d')) {
- buf = QString::number(dd->day());
- removed = 1;
- } else if (f.startsWith(QLatin1String("MMMM"))) {
- buf = dd->longMonthName(dd->month());
- removed = 4;
- } else if (f.startsWith(QLatin1String("MMM"))) {
- buf = dd->shortMonthName(dd->month());
- removed = 3;
- } else if (f.startsWith(QLatin1String("MM"))) {
- buf = QString::number(dd->month()).rightJustified(2, QLatin1Char('0'), true);
- removed = 2;
- } else if (f.at(0) == QLatin1Char('M')) {
- buf = QString::number(dd->month());
- removed = 1;
- } else if (f.startsWith(QLatin1String("yyyy"))) {
- const int year = dd->year();
- buf = QString::number(qAbs(year)).rightJustified(4, QLatin1Char('0'));
- if(year > 0)
- removed = 4;
- else
- {
- buf.prepend(QLatin1Char('-'));
- removed = 5;
+ if (dt) {
+ if (!rex.cap(4).isEmpty()) {
+ hour = rex.cap(4).toInt();
+ min = rex.cap(5).toInt();
+ sec = rex.cap(6).toInt();
}
-
- } else if (f.startsWith(QLatin1String("yy"))) {
- buf = QString::number(dd->year()).right(2).rightJustified(2, QLatin1Char('0'));
- removed = 2;
+ positiveOffset = (rex.cap(7) == QStringLiteral("+"));
+ hourOffset = rex.cap(8).toInt();
+ minOffset = rex.cap(9).toInt();
}
- }
- if (removed == 0 || removed >= f.size()) {
- return buf;
- }
-
- return buf + getFmtString(f.mid(removed), dt, dd, am_pm);
-}
-
-// Parses the format string and uses getFmtString to get the values for the tokens. Ret
-static QString fmtDateTime(const QString& f, const QTime* dt, const QDate* dd)
-{
- QString buf;
-
- if (f.isEmpty())
- return buf;
- if (dt && !dt->isValid())
- return buf;
- if (dd && !dd->isValid())
- return buf;
-
- const bool ap = hasUnquotedAP(f);
-
- QString frm;
- uint status = '0';
-
- for (int i = 0, n = f.length(); i < n; ++i) {
- const QChar c = f.at(i);
- const uint cc = c.unicode();
- if (cc == '\'') {
- if (status == cc) {
- if (i > 0 && f.at(i - 1).unicode() == cc)
- buf += c;
- status = '0';
- } else {
- if (!frm.isEmpty()) {
- buf += getFmtString(frm, dt, dd, ap);
- frm.clear();
- }
- status = cc;
+ if (utcOffset)
+ *utcOffset = ((hourOffset * 60 + minOffset) * (positiveOffset ? 60 : -60));
+ } else {
+ // Matches "Wdy Mon DD HH:MM:SS YYYY"
+ QRegExp rex(QStringLiteral("^[A-Z][a-z]+[ \\t]+([A-Z][a-z]+)[ \\t]+(\\d\\d)(?:[ \\t]+(\\d\\d):(\\d\\d):(\\d\\d))?[ \\t]+(\\d\\d\\d\\d)[ \\t]*(?:([+-])(\\d\\d)(\\d\\d))?"));
+ if (s.indexOf(rex) == 0) {
+ if (dd) {
+ month = qt_monthNumberFromShortName(rex.cap(1));
+ day = rex.cap(2).toInt();
+ year = rex.cap(6).toInt();
}
- } else if (status == '\'') {
- buf += c;
- } else if (c == status) {
- if (ap && (cc == 'P' || cc == 'p'))
- status = '0';
- frm += c;
- } else {
- buf += getFmtString(frm, dt, dd, ap);
- frm.clear();
- if (cc == 'h' || cc == 'm' || cc == 'H' || cc == 's' || cc == 'z') {
- status = cc;
- frm += c;
- } else if (cc == 'd' || cc == 'M' || cc == 'y') {
- status = cc;
- frm += c;
- } else if (ap && cc == 'A') {
- status = 'P';
- frm += c;
- } else if (ap && cc == 'a') {
- status = 'p';
- frm += c;
- } else {
- buf += c;
- status = '0';
+ if (dt) {
+ if (!rex.cap(3).isEmpty()) {
+ hour = rex.cap(3).toInt();
+ min = rex.cap(4).toInt();
+ sec = rex.cap(5).toInt();
+ }
+ positiveOffset = (rex.cap(7) == QStringLiteral("+"));
+ hourOffset = rex.cap(8).toInt();
+ minOffset = rex.cap(9).toInt();
}
+ if (utcOffset)
+ *utcOffset = ((hourOffset * 60 + minOffset) * (positiveOffset ? 60 : -60));
}
}
- buf += getFmtString(frm, dt, dd, ap);
-
- return buf;
+ if (dd)
+ *dd = QDate(year, month, day);
+ if (dt)
+ *dt = QTime(hour, min, sec);
}
#endif // QT_NO_DATESTRING
+
#ifdef Q_OS_WIN
static const int LowerYear = 1980;
#else
@@ -3968,6 +4223,7 @@ static QDate adjustDate(QDate date)
return date;
}
+// Convert passed in UTC datetime into LocalTime and return spec
static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time)
{
QDate fakeDate = adjustDate(date);
@@ -4021,6 +4277,7 @@ static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time)
}
}
+// Convert passed in LocalTime datetime into UTC
static void localToUtc(QDate &date, QTime &time, int isdst)
{
if (!date.isValid())
@@ -4093,44 +4350,75 @@ static void localToUtc(QDate &date, QTime &time, int isdst)
}
}
+// Convert passed in OffsetFromUTC datetime and offset into UTC
+static void offsetToUtc(QDate *outDate, QTime *outTime, qint32 offset)
+{
+ QDateTimePrivate::addMSecs(*outDate, *outTime, -(qint64(offset) * 1000));
+}
+
+// Convert passed in UTC datetime and offset into OffsetFromUTC
+static void utcToOffset(QDate *outDate, QTime *outTime, qint32 offset)
+{
+ QDateTimePrivate::addMSecs(*outDate, *outTime, (qint64(offset) * 1000));
+}
+
+// Get current date/time in LocalTime and put result in outDate and outTime
QDateTimePrivate::Spec QDateTimePrivate::getLocal(QDate &outDate, QTime &outTime) const
{
outDate = date;
outTime = time;
if (spec == QDateTimePrivate::UTC)
return utcToLocal(outDate, outTime);
+ if (spec == QDateTimePrivate::OffsetFromUTC) {
+ offsetToUtc(&outDate, &outTime, m_offsetFromUtc);
+ return utcToLocal(outDate, outTime);
+ }
return spec;
}
+// Get current date/time in UTC and put result in outDate and outTime
void QDateTimePrivate::getUTC(QDate &outDate, QTime &outTime) const
{
outDate = date;
outTime = time;
- const bool isOffset = spec == QDateTimePrivate::OffsetFromUTC;
- if (spec != QDateTimePrivate::UTC && !isOffset)
+ if (spec == QDateTimePrivate::OffsetFromUTC)
+ offsetToUtc(&outDate, &outTime, m_offsetFromUtc);
+ else if (spec != QDateTimePrivate::UTC)
localToUtc(outDate, outTime, (int)spec);
-
- if (isOffset)
- addMSecs(outDate, outTime, -(qint64(utcOffset) * 1000));
}
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_NO_DATESTRING)
QDebug operator<<(QDebug dbg, const QDate &date)
{
- dbg.nospace() << "QDate(" << date.toString() << ')';
+ dbg.nospace() << "QDate(" << date.toString(QStringLiteral("yyyy-MM-dd")) << ')';
return dbg.space();
}
QDebug operator<<(QDebug dbg, const QTime &time)
{
- dbg.nospace() << "QTime(" << time.toString() << ')';
+ dbg.nospace() << "QTime(" << time.toString(QStringLiteral("HH:mm:ss.zzz")) << ')';
return dbg.space();
}
QDebug operator<<(QDebug dbg, const QDateTime &date)
{
- dbg.nospace() << "QDateTime(" << date.toString() << ')';
+ QString spec;
+ switch (date.d->spec) {
+ case QDateTimePrivate::UTC :
+ spec = QStringLiteral(" Qt::UTC");
+ break;
+ case QDateTimePrivate::OffsetFromUTC :
+ spec = QString::fromUtf8(" Qt::OffsetFromUTC %1s").arg(date.offsetFromUtc());
+ break;
+ case QDateTimePrivate::LocalDST :
+ case QDateTimePrivate::LocalStandard :
+ case QDateTimePrivate::LocalUnknown :
+ default :
+ spec = QStringLiteral(" Qt::LocalTime");
+ }
+ QString output = date.toString(QStringLiteral("yyyy-MM-dd HH:mm:ss.zzz t")) + spec;
+ dbg.nospace() << "QDateTime(" << output << ')';
return dbg.space();
}
#endif