LINUX.ORG.RU

Конструкторы QQmlApplicationEngine и QSettings портят таймзону (daylight). Что с этим делать и как обойти?

 , daylight, ,


1

2

Наткнулся на странное поведение конструктора QQmlApplicationEngine. Минимальный код main.cpp:

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    qDebug() << "1ST timezone=" << timezone << " daylight=" << daylight;
    tzset();
    qDebug() << "2ND timezone=" << timezone << " daylight=" << daylight;

    QQmlApplicationEngine engine;

    qDebug() << "3ND timezone=" << timezone << " daylight=" << daylight;

    return app.exec();
}

Результат работы:
1ST timezone= 0  daylight= 0
2ND timezone= -10800  daylight= 1
3ND timezone= -10800  daylight= 0

То есть, после срабатывания конструктора QQmlApplicationEngine портится daylight.

Я удивился, но работать надо и поэтому попытался обойти это дело так:
    long saveTimezone=timezone;
    int saveDaylight=daylight;

    QQmlApplicationEngine engine;

    timezone=saveTimezone;
    daylight=saveDaylight;

Сработало, однако в проекте я еще нашел одно место, в котором такое же поведение, после срабатывания конструктора QSettings (но уже в куче). Выглядит так:
        qDebug() << "CURRENT timezone=" << timezone << " daylight=" << daylight;
        QSettings *config=new QSettings(fileName, QSettings::IniFormat, this);
        qDebug() << "CURRENT timezone=" << timezone << " daylight=" << daylight;

CURRENT timezone= -10800  daylight= 1
CURRENT timezone= -10800  daylight= 0

В минимальном коде повторить такое не смог.

Вот. Где еще может слетать daylight я ума не приложу, но вероятности такой не исключаю. Проблема в том, что в моем проекте используется легаси библиотека, которая работает с daylight, и из-за этих проблем выдает неправильное время.

Вопросы: что это за ботва такая, почему некоторые Qt классы портят daylight, как это дело гарантированно обойти?

PS: Файл проекта что б быстро собрать минимальный пример:

time.pro
CONFIG+=c++11
CONFIG+=qml_debug
QT+=gui
QT+=core
QT+=quick
QT+=widgets
SOURCES += main.cpp
DEFINES += QT_DEPRECATED_WARNINGS

★★★★★

Я что-то не понял, а где у тебя в минимальном примере объявлены timezone и daylight?

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

Они должны быть в <ctime> или «time.h». В данном случае я эти заголовки не подключаю, а переменные timezone и daylight есть, точно так же как есть и функция tzset(). То есть, где-то в глубинах Qt это дело подключается.

Я дальше начал копать. Решил так: коль меняется daylight, а оно должно зависеть от enviroment переменной TZ, значит меняется TZ. Вставил код до и после проблемного конструктора:

    qDebug() << "TZ: " << getenv ("TZ");

В обоих случаях TZ является пустой строкой.

То есть daylight меняется не на основе TZ, а вообще непонятно как.

Более того, tzset() правильно выставляет timezone и daylight только один раз, если эту функцию вызвать до проблемного конструктора. После проблемного конструктора daylight сбрасывается с 1 в 0, и если еще раз вызвать tzset(), то эта функция не выставит daylight в 1 как в первый раз, а оставит daylight = 0.

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

Понятия не имею, я с QML не работал

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

Мне бы на других линуксах и Qt проверить.

Вот тут ничего конструктивного не говорят, зато прицепились к версии линуха и Qt.

https://forum.qt.io/topic/90848/the-constructors-qqmlapplicationengine-and-qs...

Если есть возможность, у себя проверь.

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

Попробуй поставь Дебиановскую версию Qt о всеми нужными -dev пакетами и воспроизведи. Это просто для информации, которую нужно прикрепить к багрепорту. Наврятли тебе помогут где-либо, если это баг в Qt.

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

Ты уверен, что дело в Qt? Собери тест без Qt с тремя вызовами tzset() и printf(«%d\n», daylight) после каждого.

anonymous
()
Ответ на: комментарий от anonymous
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
    printf("%d\n", daylight);
    tzset();
    printf("%d\n", daylight);
    tzset();
    printf("%d\n", daylight);
    tzset();
    printf("%d\n", daylight);

    return 0;
}


Результат:

0
1
1
1

Первый вызов tzset() устанавливает daylight с 0 на 1, и потом везде сохраняется 1. Это нормально, и совсем не походит на то, что происходит при обращении к Qt классам.

Xintrea ★★★★★
() автор топика

ubuntu 16.04 amd64 подтверждаю

вот стек трейс где портится

1  update_vars                                  tzset.c                   156  0x7ffff63d8e1d 
2  __tzset_parse_tz                             tzset.c                   391  0x7ffff63d8e1d 
3  __tzfile_compute                             tzfile.c                  691  0x7ffff63db438 
4  __tz_convert                                 tzset.c                   624  0x7ffff63d9d7f 
5  __localtime_r                                localtime.c               30   0x7ffff63d792d 
6  getLocalTZA                                  qv4dateobject.cpp         623  0x7ffff74354e1 
7  QV4::DatePrototype::init                     qv4dateobject.cpp         728  0x7ffff743d14d 
8  QV4::ExecutionEngine::ExecutionEngine        qv4engine.cpp             387  0x7ffff740e58c 
9  QV8Engine::QV8Engine                         qv8engine.cpp             150  0x7ffff75ad0c9 
10 QJSEngine::QJSEngine                         qjsengine.cpp             305  0x7ffff73a4dc4 
11 QQmlEngine::QQmlEngine                       qqmlengine.cpp            1007 0x7ffff74ec741 
12 QQmlApplicationEngine::QQmlApplicationEngine qqmlapplicationengine.cpp 208  0x7ffff7591fc2 
13 main                                         main.cpp                  16   0x401061       

вот место:

qt5.9.4/qtdeclarative/src/qml/jsruntime/qv4dateobject.cpp

static double getLocalTZA()
{
#ifndef Q_OS_WIN
    struct tm t;
    time_t curr;
    tzset();
    time(&curr);
    localtime_r(&curr, &t); << вот здесь портится
    time_t locl = mktime(&t);
    gmtime_r(&curr, &t);
    time_t globl = mktime(&t);
    return (double(locl) - double(globl)) * 1000.0;
#else
  ...
}

ЗЫ: прокачай скилл «Data breakpoint»

делаем ссылку

int &mydaylight = daylight;

н.р. в креаторе ставим брекпоинт тут и после остановки в ватчере на этой переменной устанавливаем «Add data breakpoint»

дальше дело техники

maxxant
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.