Fix storing of QDateTime timespec for Sqlite
Commit 9e64fc9e1c
caused a regression
which stored all QDateTime entries as if they were in localtime,
which causes them to be offset by the amount of local timezone
offset. This is fixed by adding "Z" if the time should be in UTC or
using "+/-hh:mm" if it should use fixed UTC offset or specific
timezone.
Task-number: QTBUG-57138
Change-Id: Ie60905dfb3a517db442b636ca41daf8348753d84
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Andy Shaw <andy.shaw@qt.io>
This commit is contained in:
parent
b7a898b8fe
commit
0a5f71c606
@ -51,6 +51,7 @@
|
|||||||
#include <qstringlist.h>
|
#include <qstringlist.h>
|
||||||
#include <qvector.h>
|
#include <qvector.h>
|
||||||
#include <qdebug.h>
|
#include <qdebug.h>
|
||||||
|
#include <QTimeZone>
|
||||||
|
|
||||||
#if defined Q_OS_WIN
|
#if defined Q_OS_WIN
|
||||||
# include <qt_windows.h>
|
# include <qt_windows.h>
|
||||||
@ -410,6 +411,32 @@ bool QSQLiteResult::prepare(const QString &query)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString secondsToOffset(int seconds)
|
||||||
|
{
|
||||||
|
const QChar sign = ushort(seconds < 0 ? '-' : '+');
|
||||||
|
seconds = qAbs(seconds);
|
||||||
|
const int hours = seconds / 3600;
|
||||||
|
const int minutes = (seconds % 3600) / 60;
|
||||||
|
|
||||||
|
return QString(QStringLiteral("%1%2:%3")).arg(sign).arg(hours, 2, 10, QLatin1Char('0')).arg(minutes, 2, 10, QLatin1Char('0'));
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString timespecToString(const QDateTime &dateTime)
|
||||||
|
{
|
||||||
|
switch (dateTime.timeSpec()) {
|
||||||
|
case Qt::LocalTime:
|
||||||
|
return QString();
|
||||||
|
case Qt::UTC:
|
||||||
|
return QStringLiteral("Z");
|
||||||
|
case Qt::OffsetFromUTC:
|
||||||
|
return secondsToOffset(dateTime.offsetFromUtc());
|
||||||
|
case Qt::TimeZone:
|
||||||
|
return secondsToOffset(dateTime.timeZone().offsetFromUtc(dateTime));
|
||||||
|
default:
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool QSQLiteResult::exec()
|
bool QSQLiteResult::exec()
|
||||||
{
|
{
|
||||||
Q_D(QSQLiteResult);
|
Q_D(QSQLiteResult);
|
||||||
@ -456,7 +483,7 @@ bool QSQLiteResult::exec()
|
|||||||
break;
|
break;
|
||||||
case QVariant::DateTime: {
|
case QVariant::DateTime: {
|
||||||
const QDateTime dateTime = value.toDateTime();
|
const QDateTime dateTime = value.toDateTime();
|
||||||
const QString str = dateTime.toString(QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz"));
|
const QString str = dateTime.toString(QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz") + timespecToString(dateTime));
|
||||||
res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
|
res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
|
||||||
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
||||||
break;
|
break;
|
||||||
|
@ -243,6 +243,9 @@ private slots:
|
|||||||
void integralTypesMysql_data() { generic_data("QMYSQL"); }
|
void integralTypesMysql_data() { generic_data("QMYSQL"); }
|
||||||
void integralTypesMysql();
|
void integralTypesMysql();
|
||||||
|
|
||||||
|
void QTBUG_57138_data() { generic_data("QSQLITE"); }
|
||||||
|
void QTBUG_57138();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// returns all database connections
|
// returns all database connections
|
||||||
void generic_data(const QString &engine=QString());
|
void generic_data(const QString &engine=QString());
|
||||||
@ -4083,5 +4086,40 @@ void tst_QSqlQuery::integralTypesMysql()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QSqlQuery::QTBUG_57138()
|
||||||
|
{
|
||||||
|
QDateTime utc = QDateTime(QDate(2150, 1, 5), QTime(14, 0, 0, 123), Qt::UTC);
|
||||||
|
QDateTime localtime = QDateTime(QDate(2150, 1, 5), QTime(14, 0, 0, 123), Qt::LocalTime);
|
||||||
|
QDateTime tzoffset = QDateTime(QDate(2150, 1, 5), QTime(14, 0, 0, 123), Qt::OffsetFromUTC, 3600);
|
||||||
|
|
||||||
|
QFETCH(QString, dbName);
|
||||||
|
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||||
|
CHECK_DATABASE(db);
|
||||||
|
|
||||||
|
QSqlQuery create(db);
|
||||||
|
QString tableName = qTableName("qtbug57138", __FILE__, db);
|
||||||
|
|
||||||
|
QVERIFY_SQL(create, exec("create table " + tableName + " (id int, dt_utc datetime, dt_lt datetime, dt_tzoffset datetime)"));
|
||||||
|
QVERIFY_SQL(create, prepare("insert into " + tableName + " (id, dt_utc, dt_lt, dt_tzoffset) values (?, ?, ?, ?)"));
|
||||||
|
|
||||||
|
create.addBindValue(0);
|
||||||
|
create.addBindValue(utc);
|
||||||
|
create.addBindValue(localtime);
|
||||||
|
create.addBindValue(tzoffset);
|
||||||
|
|
||||||
|
QVERIFY_SQL(create, exec());
|
||||||
|
|
||||||
|
QSqlQuery q(db);
|
||||||
|
q.prepare("SELECT dt_utc, dt_lt, dt_tzoffset FROM " + tableName + " WHERE id = ?");
|
||||||
|
q.addBindValue(0);
|
||||||
|
|
||||||
|
QVERIFY_SQL(q, exec());
|
||||||
|
QVERIFY(q.next());
|
||||||
|
|
||||||
|
QCOMPARE(q.value(0).toDateTime(), utc);
|
||||||
|
QCOMPARE(q.value(1).toDateTime(), localtime);
|
||||||
|
QCOMPARE(q.value(2).toDateTime(), tzoffset);
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN( tst_QSqlQuery )
|
QTEST_MAIN( tst_QSqlQuery )
|
||||||
#include "tst_qsqlquery.moc"
|
#include "tst_qsqlquery.moc"
|
||||||
|
Loading…
Reference in New Issue
Block a user