SQL/MySQL: use utc datetime in formatValue()
We store timestamps as utc in the database but QSqlDriver::formatValue() does not format the datetime string as utc. Fix it by converting the datetime object to utc first. This amends 2781c3b6248fe4410a7afffd41bad72d8567fc95 Pick-to: 6.9 6.8 Fixes: QTBUG-135135 Change-Id: Id26b251e9ed9800d6caff7f43de25fd9e9b08f43 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
06ef995a7d
commit
219e9fe7a2
@ -1614,7 +1614,7 @@ QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) cons
|
||||
}
|
||||
Q_FALLTHROUGH();
|
||||
case QMetaType::QDateTime:
|
||||
if (QDateTime dt = field.value().toDateTime(); dt.isValid()) {
|
||||
if (QDateTime dt = field.value().toDateTime().toUTC(); dt.isValid()) {
|
||||
// MySQL format doesn't like the "Z" at the end, but does allow
|
||||
// "+00:00" starting in version 8.0.19. However, if we got here,
|
||||
// it's because the MySQL server is too old for prepared queries
|
||||
|
@ -28,6 +28,9 @@ private slots:
|
||||
void record();
|
||||
void primaryIndex();
|
||||
void formatValue();
|
||||
#if QT_CONFIG(timezone)
|
||||
void formatDateTimeValue();
|
||||
#endif
|
||||
};
|
||||
|
||||
static bool driverSupportsDefaultValues(QSqlDriver::DbmsType dbType)
|
||||
@ -83,7 +86,7 @@ void tst_QSqlDriver::dropTables()
|
||||
{
|
||||
for (const QString &dbName : std::as_const(dbs.dbNames)) {
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
QStringList tables = {qTableName("relTEST1", __FILE__, db)};
|
||||
QStringList tables = {qTableName("relTEST1", __FILE__, db), qTableName("formatDateTimeValue", __FILE__, db)};
|
||||
const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db);
|
||||
if (dbType == QSqlDriver::Oracle)
|
||||
tables.push_back(qTableName("clobTable", __FILE__, db));
|
||||
@ -256,5 +259,44 @@ void tst_QSqlDriver::formatValue()
|
||||
QCOMPARE(db.driver()->formatValue(rec.field("more_data")), QString("1.234567"));
|
||||
}
|
||||
|
||||
#if QT_CONFIG(timezone)
|
||||
void tst_QSqlDriver::formatDateTimeValue()
|
||||
{
|
||||
QFETCH_GLOBAL(QString, dbName);
|
||||
QSqlDatabase db = QSqlDatabase::database(dbName);
|
||||
QSqlDriver *drv = db.driver();
|
||||
CHECK_DATABASE(db);
|
||||
QString tablename(qTableName("formatDateTimeValue", __FILE__, db));
|
||||
QSqlQuery qry(db);
|
||||
QString query = "CREATE TABLE " + tablename + " (id int, dt " + tst_Databases::dateTimeTypeName(db) + ")";
|
||||
QVERIFY_SQL(qry, exec(query));
|
||||
// some databases don't store milliseconds, so use a hard-coded date without milliseconds
|
||||
const QDateTime dtUtc(QDate(2025, 03, 29), QTime(00, 33, 00), QTimeZone::utc());
|
||||
const QDateTime dt1(dtUtc.toTimeZone(QTimeZone(3600)));
|
||||
QCOMPARE(dtUtc.toMSecsSinceEpoch(), dt1.toMSecsSinceEpoch());
|
||||
|
||||
QSqlField fieldDt1("datetime", QMetaType(QMetaType::QDateTime), QString());
|
||||
fieldDt1.setValue(dt1);
|
||||
QSqlField fieldUtc("datetime", QMetaType(QMetaType::QDateTime), QString());
|
||||
fieldUtc.setValue(dtUtc);
|
||||
|
||||
QVERIFY_SQL(qry, prepare("INSERT INTO " + tablename + " (id, dt) VALUES (:id, :dt)"));
|
||||
qry.bindValue(":id", 1);
|
||||
qry.bindValue(":dt", dtUtc);
|
||||
QVERIFY_SQL(qry, exec());
|
||||
qry.bindValue(":id", 2);
|
||||
qry.bindValue(":dt", dt1);
|
||||
QVERIFY_SQL(qry, exec());
|
||||
QVERIFY_SQL(qry, exec("INSERT INTO " + tablename + " (id, dt) VALUES (3, " + drv->formatValue(fieldUtc) + ")"));
|
||||
QVERIFY_SQL(qry, exec("INSERT INTO " + tablename + " (id, dt) VALUES (4, " + drv->formatValue(fieldDt1) + ")"));
|
||||
QVERIFY_SQL(qry, exec("SELECT dt FROM " + tablename + " ORDER BY id ASC"));
|
||||
for (int i = 1; i <= 4; ++i) {
|
||||
QVERIFY(qry.next());
|
||||
const auto dt = qry.value(0).toDateTime();
|
||||
QCOMPARE(dt.toSecsSinceEpoch(), dtUtc.toSecsSinceEpoch());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
QTEST_MAIN(tst_QSqlDriver)
|
||||
#include "tst_qsqldriver.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user