QDateTime修改时区导致时间戳不对的坑
结论:使用时间戳时,统一使用currentDateTimeUtc()或者currentMSecsSinceEpoch()获取时间戳,而不是currentDateTime()。
QDateTime部分函数源码:
QDateTime QDateTime::currentDateTime()
{QDate d;QTime t;SYSTEMTIME st;memset(&st, 0, sizeof(SYSTEMTIME));GetLocalTime(&st);d.jd = julianDayFromDate(st.wYear, st.wMonth, st.wDay);t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);return QDateTime(d, t);
}QDateTime QDateTime::currentDateTimeUtc()
{QDate d;QTime t;SYSTEMTIME st;memset(&st, 0, sizeof(SYSTEMTIME));GetSystemTime(&st);d.jd = julianDayFromDate(st.wYear, st.wMonth, st.wDay);t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);return QDateTime(d, t, Qt::UTC);
}qint64 QDateTime::currentMSecsSinceEpoch() Q_DECL_NOTHROW
{SYSTEMTIME st;memset(&st, 0, sizeof(SYSTEMTIME));GetSystemTime(&st);return msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds) +qint64(julianDayFromDate(st.wYear, st.wMonth, st.wDay)- julianDayFromDate(1970, 1, 1)) * Q_INT64_C(86400000);
}
通过QDateTime::currentDateTime()和QDateTime::currentDateTimeUtc()源码对比可以发现,在Windows下,currentDateTime()是调用GetLocalTime(&st),而currentDateTimeUtc()是调用GetSystemTime(&st),可能导致这两个函数拿到的时间戳是不一样,比如当前是UTC+8:00时区,如果你修改成UTC+10:00时区,可能会出现currentDateTime()的时间戳比currentDateTimeUtc()多了两个小时,而currentDateTimeUtc()的时间戳是对的;如果是UTC+8:00改成UTC+6:00,可能会出现currentDateTime()的时间戳比currentDateTimeUtc()少了两个小时。同理currentMSecsSinceEpoch()和currentDateTimeUtc是一样,所以QDateTime::currentDateTime().toMSecsSinceEpoch()和currentMSecsSinceEpoch()可能会出现QDateTime::currentDateTime()和QDateTime::currentDateTimeUtc()一样的问题。
例子:程序是定时跑如下代码,先开启程序,然后将时区从UTC+10:00改成UTC+8:00。会偶发出现下面的问题
auto dateTime1 = QDateTime::currentDateTime();
auto dateTime2 = QDateTime::currentDateTimeUtc();
qDebug() << dateTime1 << dateTime1.toMSecsSinceEpoch()<< dateTime2 << dateTime2.toMSecsSinceEpoch()<< QDateTime::currentMSecsSinceEpoch();
打印:
QDateTime(2025-05-14 14:01:33.989 太平洋西部标准时间 Qt::LocalTime) 1747195293989 QDateTime(2025-05-14 06:01:33.989 UTC Qt::UTC) 1747202493989 1747202493989
结果说明: 从打印结果来看,字符串时间是对的,但QDateTime::currentDateTime().toMSecsSinceEpoch()时间戳是错的,时间戳比字符串时间对应的时间戳是慢两个小时的。