2016-11-15 47 views
1

我不明白什麼是錯的。Qt。 QDateTime不可預知的行爲與時區和addSecs

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),它的工作原理很奇怪

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) 

回答

1

奇怪的事情,我就轉載使用Qt 5.6.0和這個調整的例子。

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); 

輸出:

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

縱觀一些time zone map人們可能會注意到,這兩個區域之間的偏移是完全小時。那麼+ 3h從哪裏來?

不用說,我跑了另一個測試。

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")); 

輸出:

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是不是transfering計算之前的時區爲UTC,而是使用它作爲UTC導致與相應的偏移量後移。

別急...

QDateTime dt = QDateTime(QDate(2016, 11, 11), QTime(15, 00), Qt::UTC); 
qDebug() << dt.toLocalTime(); 
qDebug() << dt.toTimeZone(QTimeZone("Asia/Yekaterinburg")); 
qDebug() << dt.toUTC(); 

輸出:

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需要當地時間,這是顯而易見的。

因爲它沒有記錄在哪裏它usedbe這對我來說似乎是一個錯誤。


長話短說,該怎麼辦?

如果適用,嘗試提供時間作爲本地時間或UTC,將它們轉換爲UTC,與它們一起計算,然後格式化爲所需的輸出。

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")); 

輸出:

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) 
+0

我需要與時區只用於調度操作。例如我的汽車離開葉卡捷琳堡,當地時間是15:00,所以當我抵達莫斯科時,第二天18:00當地時間葉卡捷琳堡,我想改變時區,這將導致莫斯科當地時間的改變。 所以我明白QDateTime的行爲是非常奇怪的,對於我的任務沒有必要設置時區,我可以在舊時區和新時區之間應用移位。唯一的問題是要記住上一次的時區 –

+0

但它不工作太...:D 'QTimeZone zoneNew(QTimeZone(「Europe/Moscow」)); QTimeZone zoneOld(QTimeZone(「Asia/Yekaterinburg」)); QDateTime test = QDateTime :: currentDateTimeUtc(); test.setTime(QTime(18,00)); qDebug()<< zoneOld.offsetFromUtc(test); // 0 qDebug()<< zoneNew.offsetFromUtc(test); // 10800' 非常奇怪 –

+0

@AnnesNess查看我最後一個爲我工作的例子。它讓我感到困惑,也是Qt在那裏做什麼。 – maxik

1

另一種可能的解決方法是使用這樣free, open source, C++11/14 library其中建立在<chrono>

#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'; 
} 

的輸出是:

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