LINUX.ORG.RU

QTime пустая строка

 , ,


1

1

Есть запрос QSqlQueryModel.

Записи в бд postgreSQL есть и всё, кроме строки Time (тип данных time with time zone видит и вытаскивает) .

QSqlQueryModel Query;
Query.setQuery (select * from myTable);
for (int I = 0,I < Query.rowCount(); I++) 
{
   QTime time = Query.record(I).value("Time").toTime ()) ;
}

И вот это Time пустое. Как исправить?



Последнее исправление: Fruct (всего исправлений: 1)
Ответ на: комментарий от XMs

Возвращает пустую строку… Хотя в бд значение есть и название столбца соответствует. Для проверки вбил неверное время и мне выдало -1, т.е дело не в названии столбца или неправильном подключении к бд.

Fruct
() автор топика
for (int I = 0,I < Query.rowCount(); I++)

Есть ощущение, что этот код не скопипащен из исходника, а перенабит руками. Догадайся, почему.

P.S. Почему именно QSlqModel, а не QSlqQuery? Нет, если эту модель потом планируется подключать к QTable(Tree,List)View, вопрос снимается. Но если надо именно перебрать данные и что-то с ними сделать – с QSlqQuery проще и логичнее.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от Fruct

дело не в названии столбца или неправильном подключении к бд.

Дело точно в Qt6.

Один и тот же код, с одним и тем же запросом:
собранный с Qt5:

"23:32:42.452"
QVariant(QTime, QTime("23:32:42.452"))
собранный с Qt6:
""
QVariant(QTime, QTime(Invalid))

Qt5 просто отбрасывает информацию о смещении по зоне, что бы там ни было (а должно было быть 23:32:42.451583+00).
Qt6 видимо и этого не делает.

Не знаю, как с этим бороться. Я этот ваш Qt вообще второй раз в руки взял по этому случаю.

Toxo2 ★★★★
()
Ответ на: комментарий от guyvernk

Я ж не ТС.

Я тут мимо проходил, глазом зацепился. Дай, думаю, в Qt по случаю потыкаю пока бессонница.

Моя б воля - я б всех отправлял разговаривать с БД только через процедуры, которые им БДшники напишут.

-----------------

Минимально воспроизводимый пример (если у вас ПГ на локалхосте настроен как у меня):

#include <QtCore>
#include <QtSql>

int main(int argc, char *argv[]) {
    //Qt6 без этого не работает
    QCoreApplication a(argc, argv);

    QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
    db.setHostName("/var/run/postgresql");
    db.setUserName("postgres");
    bool ok = db.open();
    if (ok)
    {
	QSqlQuery query("SELECT now()::timetz AS tmtz;");
	while (query.next())
	{
	    qWarning() << query.value(0).toString();
	}
	
	QSqlQueryModel model;
	model.setQuery ("SELECT now()::timetz AS tmtz;");
	for (int i = 0; i < model.rowCount(); i++) 
	{
	    QTime tm = model.record(i).value("tmtz").toTime();
	    qWarning() << tm << tm.minute() << tm.second();
	}
    }
    else
    {
	qDebug() << "ERRORDB";
    };

    return 0;
}

$ g++ $(pkg-config --cflags --libs Qt5Sql) -fPIC -lpq -o db5 db2.cpp
$ ./db5
"07:55:30.522"
QTime("07:55:30.523") 55 30
$ g++ $(pkg-config --cflags --libs Qt6Sql) -fPIC -lpq -o db6 db2.cpp
$ ./db6
""
QTime(Invalid) -1 -1
Toxo2 ★★★★
()
Последнее исправление: Toxo2 (всего исправлений: 2)
Ответ на: комментарий от Toxo2

Моя б воля - я б всех отправлял разговаривать с БД только через процедуры, которые им БДшники напишут.

Так не суть же: судя по твоему коду, уже query.value(0).toString() для селекта возвращает пустую строку в Qt6. Так что скорее всего и ответ из хранимки такой же был бы.

static_lab ★★★★★
()
Ответ на: комментарий от static_lab

Так не суть же...Так что скорее всего и ответ из хранимки такой же был бы.

Суть в том, что с вероятностью 99% тут не нужен ни timetz ни timestamptz, если это реальная задача.

Другая суть в том, что БДшник бы мог вернуть ответ в готовом JSONе, чтоб ваши клиентские библиотеки не пытались умничать с типами полей ПГ.

В общем - не надо бэкам думать о таких штуках. Объясни словами, что хочешь. Я тебе отдам как тебе удобно. Эмммммм...... это работа такая )

Toxo2 ★★★★
()

Там, в Qt5 vs Qt6, оказывается вообще как-то сильно по-разному клиент с ПГ разговаривает.

Одним и тем же кодом подключиться и сразу сдёрнуть SELECT setting FROM pg_settings WHERE name = 'TimeZone'; временную зону - сразу разные значения.

Под Qt5 у меня оно QVariant(QString, "Asia/Novosibirsk"), а под Qt6 QVariant(QString, "UTC") "UTC"

Тут тоже надо разбираться - что такого поменяли в Qt6, что теперь клиентская зона подключения стала другая.

А так, в целом, ей-богу должна быть какая-то невероятно веская причина связываться с этими зонами.

Toxo2 ★★★★
()
Ответ на: комментарий от Toxo2

Тут тоже надо разбираться - что такого поменяли в Qt6, что теперь клиентская зона подключения стала другая.

Не уверен, что это связанные вещи, но в Qt6, напомню, пытались ещё и неюникодные кодировки выкинуть (в 6.4 вроде как вернули), возможно, и часовые пояса пострадали «за компанию». Но это так, мысли вслух, с большой вероятностью — бредовые.

hobbit ★★★★★
()
Ответ на: комментарий от hobbit

Не уверен, что это связанные вещи

Не, едва ли.

Посмотрел в лог ПГ - Qt6 прям в явном виде посылает при подключении такое:

[215388] LOG:  statement: SET TIME ZONE 'UTC'
[215388] LOG:  statement: SET bytea_output TO escape
[215388] LOG:  statement: SET DATESTYLE TO 'ISO'
[215388] LOG:  statement: SET CLIENT_ENCODING TO 'UNICODE'
[215388] LOG:  statement: SELECT '\\' x
[215388] LOG:  statement: SELECT version()
У Qt5 нет первой строчки. Но всё остальное - то же самое при подключении. Просто - подключении.

Удивителен мир клиентов БД.

Я ещё ничего не хочу. Хочу просто установить соединение с БД. С какого перепугу Qt-шные библиотеки ещё и кучку SETов наваливают, которые никто не просил?

Toxo2 ★★★★
()
Ответ на: комментарий от Toxo2

С какого перепугу Qt-шные библиотеки ещё и кучку SETов наваливают, которые никто не просил?

Как раз чтобы получать данные(время) в удобоваримом(кодировка) формате. Ну а эскейпинг это так, на сладкое :-)

Pinkbyte ★★★★★
()
Ответ на: комментарий от Pinkbyte

Две большие конторы, в которых работал, зачем-то прибили гвоздями свои БД к MSK зоне. Так сказать - исторически так получилось. Вот всё, что лежит в БД про дату/время - по Москве.

Причём одна из контор ещё хотя бы приводит к timezone('MSK', now()), когда сравнивает датувремя. Вторая и этого не делает, считает, что у них все клиенты в MSK живут по определению.

И тут приходит Qt6 и давай в UTC разговаривать никого не предупредив. И здрасте сегодня/завтра не там где надо гарантировано.

Правда маловероятно, что кому-то там в голову придёт клиентов на Qt6 писать.

Toxo2 ★★★★
()
Ответ на: комментарий от Toxo2

С какого перепугу Qt-шные библиотеки ещё и кучку SETов наваливают, которые никто не просил?

https://github.com/qt/qtbase/commit/b71f185ffc54245197149d7a6f8b5f756c9b9393

Они в 6.8.0 внезапно решили, что стоит поменять поведение 🤦‍♂️

static_lab ★★★★★
()
Ответ на: комментарий от Pinkbyte

А фактически — нет. Для полей типа TIMETZ (который возвращает строку вида 21:20:52.016783+04) используется тип QTime, который не поддерживает таймзоны:

[Qt6] Unlike QDateTime, QTime knows nothing about time zones or daylight-saving time (DST).

При этом в коде драйвера PSQL для Qt5 таймзона просто игнорировалась, буквально специально вырезалась.

В коде Qt6 запилили поддержку таймзон, и этот костыль из драйвера убрали.

Однако QTime в Qt6 не поддерживает таймзоны, при разборе строки обнаруживает, что после десятичной точки не идут строго цифры, и создаёт пустой невалидный объект QTime.

Вывод: разработчики Qt — тупоголовые идиоты, и работать с постгресовским типом данных TIMETZ ни в Qt5, ни в Qt6 нельзя.

static_lab ★★★★★
()
Последнее исправление: static_lab (всего исправлений: 3)
Ответ на: комментарий от static_lab

Я что-то не очень по коду понял из твоих примеров - в твоей же ссылки выше в 6.8.0 возвращается QDateTime (в котором вроде как с поддержкой таймзон всё окей).

А по другим ссылкам там уже QTime.

Может ТСу стоит проверить что там внутри QVariant-а и вместо toTime() использовать toDateTime(), если реально нужна таймзона ?

Update: а, увидел, они там еще ставят таймзону UTC принудительно. Как раз таки походу что поддержка есть, но видимо далеко не везде. Ну ой, тут только пилить багрепорт.

Pinkbyte ★★★★★
()
Последнее исправление: Pinkbyte (всего исправлений: 1)
Ответ на: комментарий от Pinkbyte

Может ТСу стоит проверить что там внутри QVariant-а и вместо toTime() использовать toDateTime(), если реально нужна таймзона?

В QVariant уже лежит преобразованная строка. Решение, в какой кутешный тип преобразовывать, принимает сам Qt уже на этапе получения столбца:

Повлиять на это, я так понимаю, нельзя.

static_lab ★★★★★
()
Последнее исправление: static_lab (всего исправлений: 2)
Ответ на: комментарий от Pinkbyte

К слову, это тоже писалось без проверки, судя по всему. Потому что может получаться невалидная строка. Я сначала удивился, как это будет работать, но месяц назад поправили. Ещё раз: закостылили UTC 16 марта, пофиксили, чтобы хотя бы как-то работало с таймзонами, 18 октября.

static_lab ★★★★★
()