首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Qt。QDateTime具有时区和addSecs的不可预测行为

Qt。QDateTime具有时区和addSecs的不可预测行为
EN

Stack Overflow用户
提问于 2016-11-15 18:48:54
回答 2查看 1.2K关注 0票数 1

我不知道怎么回事。

代码语言:javascript
复制
QTimeZone zone1(QTimeZone("Europe/Moscow"));
QTimeZone zone2(QTimeZone("Asia/Yekaterinburg"));
QDateTime test = QDateTime(QDate(2016, 11, 11), QTime(15,00), zone1);
qDebug() << test;//QDateTime(2016-11-11 15:00:00.000 MSK Qt::TimeSpec(TimeZone) Europe/Moscow)
test = test.addSecs(5*60);
qDebug() << test;//QDateTime(2016-11-11 15:05:00.000 MSK Qt::TimeSpec(TimeZone) Europe/Moscow)

这在欧洲/莫斯科(+3)很好,但当我将时区改为亚洲/叶卡捷琳堡(+5)时,效果非常奇怪。

代码语言:javascript
复制
QTimeZone zone2(QTimeZone("Asia/Yekaterinburg"));
QDateTime test = QDateTime(QDate(2016, 11, 11), QTime(15,00), zone2);
qDebug() << test;//QDateTime(2016-11-11 15:00:00.000  Qt::TimeSpec(TimeZone) Asia/Yekaterinburg)
test = test.addSecs(5*60);
qDebug() << test;//QDateTime(2016-11-11 10:05:00.000  Qt::TimeSpec(TimeZone) Asia/Yekaterinburg)
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-15 21:37:14

奇怪的是,我用QT5.6.0和这个调整的例子再现了它。

代码语言:javascript
复制
QDateTime test1 = QDateTime(QDate(2016, 11, 11), QTime(15, 00), QTimeZone("Europe/Moscow"));
QDateTime test2 = QDateTime(QDate(2016, 11, 11), QTime(15, 00), QTimeZone("Asia/Yekaterinburg"));
QDateTime test3 = QDateTime(QDate(2016, 11, 11), QTime(15, 00), QTimeZone("Europe/Berlin"));
qDebug() << test1;
qDebug() << test2;
qDebug() << test3;
qDebug() << test1.addSecs(5*60);
qDebug() << test2.addSecs(5*60);
qDebug() << test3.addSecs(5*60);

输出:

代码语言:javascript
复制
QDateTime(2016-11-11 15:00:00.000 RTZ 2 Qt::TimeSpec(TimeZone) Europe/Moscow)
QDateTime(2016-11-11 15:00:00.000 RTZ 4 Qt::TimeSpec(TimeZone) Asia/Yekaterinburg)
QDateTime(2016-11-11 15:00:00.000 MEZ   Qt::TimeSpec(TimeZone) Europe/Berlin)
QDateTime(2016-11-11 18:05:00.000 RTZ 2 Qt::TimeSpec(TimeZone) Europe/Moscow)
QDateTime(2016-11-11 20:05:00.000 RTZ 4 Qt::TimeSpec(TimeZone) Asia/Yekaterinburg)
QDateTime(2016-11-11 15:05:00.000 MEZ   Qt::TimeSpec(TimeZone) Europe/Berlin)
QDateTime(2016-11-11 18:05:00.000 RTZ 2 Qt::TimeSpec(TimeZone) Europe/Moscow)

请注意,我添加了另一个时区,即本地时区。您可能会注意到,这是工作的时区(Europe/Berlin)。

接下来要做的是偏移分析。您可以看到以下抵消:

  • Europe/Moscow:+3h
  • Asia/Yekaterinburg:+5h

看看一些时区地图,人们可能会注意到,这两个区域之间的偏移量正好是2h。那么,+3h从哪里来呢?

不用说,我又做了一次测试。

代码语言:javascript
复制
QDateTime dt = QDateTime(QDate(2016, 11, 11), QTime(15, 00), QTimeZone("UTC"));
qDebug() << dt;
qDebug() << dt.addSecs(5*60);
qDebug() << dt.addSecs(5*60).toTimeZone(QTimeZone("Asia/Yekaterinburg"));

输出:

代码语言:javascript
复制
QDateTime(2016-11-11 15:00:00.000 UTC   Qt::TimeSpec(TimeZone) UTC)
QDateTime(2016-11-11 15:05:00.000 UTC   Qt::TimeSpec(TimeZone) UTC)
QDateTime(2016-11-11 20:05:00.000 RTZ 4 Qt::TimeSpec(TimeZone) Asia/Yekaterinburg)

这里我们要说的是:在计算之前,Qt似乎并没有将时区转移到UTC,而是使用它作为UTC,这导致了一个带有相应偏移量的反向移位。

但是等等..。

代码语言:javascript
复制
QDateTime dt = QDateTime(QDate(2016, 11, 11), QTime(15, 00), Qt::UTC);
qDebug() << dt.toLocalTime();
qDebug() << dt.toTimeZone(QTimeZone("Asia/Yekaterinburg"));
qDebug() << dt.toUTC();

输出:

代码语言:javascript
复制
QDateTime(2016-11-11 16:00:00.000 MEZ   Qt::TimeSpec(LocalTime))
QDateTime(2016-11-11 20:00:00.000 RTZ 4 Qt::TimeSpec(TimeZone) Asia/Yekaterinburg)
QDateTime(2016-11-11 15:00:00.000 UTC   Qt::TimeSpec(UTC))

现在看起来,如果构造函数得到一个时区,它假设它是UTC,而不是提供的那个。如果把它排除在外,Qt会占用本地时间,这是显而易见的。

由于没有记录它从使用be的位置,在我看来,这似乎是一个bug。

长话短说,该怎么办?

如果适用,尝试将时间作为本地时间或UTC提供,将它们转换为UTC,用它们计算,然后格式化到所需的输出。

代码语言:javascript
复制
QDateTime dt = QDateTime(QDate(2016, 11, 11), QTime(10, 00), Qt::UTC);
qDebug() << dt.toTimeZone(QTimeZone("Asia/Yekaterinburg"));
qDebug() << dt.addSecs(5*60).toTimeZone(QTimeZone("Asia/Yekaterinburg"));

输出:

代码语言:javascript
复制
QDateTime(2016-11-11 15:00:00.000 RTZ 4 Qt::TimeSpec(TimeZone) Asia/Yekaterinburg)
QDateTime(2016-11-11 15:05:00.000 RTZ 4 Qt::TimeSpec(TimeZone) Asia/Yekaterinburg)
票数 2
EN

Stack Overflow用户

发布于 2016-11-15 22:27:34

另一个可能的解决方法是使用基于免费开放源码,C++11/14库<chrono>

代码语言:javascript
复制
#include "tz.h"
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std::chrono;
    auto zone1 = make_zoned("Europe/Moscow", local_days{2016_y/11/11} + 15h);
    std::cout << zone1 << '\n';
    zone1 = zone1.get_local_time() + 5min;
    std::cout << zone1 << '\n';

    auto zone2 = make_zoned("Asia/Yekaterinburg", local_days{2016_y/11/11} + 15h);
    std::cout << zone2 << '\n';
    zone2 = zone2.get_local_time() + 5min;
    std::cout << zone2 << '\n';
}

产出如下:

代码语言:javascript
复制
2016-11-11 15:00:00 MSK
2016-11-11 15:05:00 MSK
2016-11-11 15:00:00 +05
2016-11-11 15:05:00 +05

以下是与QDate之间的转换函数

https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes#QDate

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40617470

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档