if (myNetworkId != msgNetworkId)
return false;
- uint messageTimestamp = sourceModel()->data(sourceIdx, MessageModel::TimestampRole).value<QDateTime>().toTime_t();
+ qint64 messageTimestamp = sourceModel()->data(sourceIdx, MessageModel::TimestampRole)
+ .value<QDateTime>().toMSecsSinceEpoch();
QString quiter = sourceModel()->data(sourceIdx, Qt::DisplayRole).toString().section(' ', 0, 0, QString::SectionSkipEmpty).toLower();
if (quiter != bufferName().toLower())
return false;
void init();
QSet<BufferId> _validBuffers;
- QMultiHash<QString, uint> _filteredQuitMsgs;
+ QMultiHash<QString, qint64> _filteredQuitMsgs;
int _messageTypeFilter;
int _userNoticesTarget;
QDateTime now = QDateTime::currentDateTime();
now.setTimeSpec(Qt::UTC);
_nextDayChange.setTimeSpec(Qt::UTC);
- _nextDayChange.setTime_t(((now.toTime_t() / 86400) + 1) * 86400);
+ _nextDayChange.setMSecsSinceEpoch(
+ ((now.toMSecsSinceEpoch() / DAY_IN_MSECS) + 1) * DAY_IN_MSECS);
_nextDayChange.setTimeSpec(Qt::LocalTime);
_dayChangeTimer.setInterval(QDateTime::currentDateTime().secsTo(_nextDayChange) * 1000);
_dayChangeTimer.start();
QDateTime prevTs = msglist.last().timestamp();
nextTs.setTimeSpec(Qt::UTC);
prevTs.setTimeSpec(Qt::UTC);
- uint nextDay = nextTs.toTime_t() / 86400;
- uint prevDay = prevTs.toTime_t() / 86400;
+ qint64 nextDay = nextTs.toMSecsSinceEpoch() / DAY_IN_MSECS;
+ qint64 prevDay = prevTs.toMSecsSinceEpoch() / DAY_IN_MSECS;
if (nextDay != prevDay) {
- nextTs.setTime_t(nextDay * 86400);
+ nextTs.setMSecsSinceEpoch(nextDay * DAY_IN_MSECS);
nextTs.setTimeSpec(Qt::LocalTime);
dayChangeMsg = Message::ChangeOfDay(nextTs);
dayChangeMsg.setMsgId(msglist.last().msgId());
QDateTime prevTs = (*iter).timestamp();
nextTs.setTimeSpec(Qt::UTC);
prevTs.setTimeSpec(Qt::UTC);
- uint nextDay = nextTs.toTime_t() / 86400;
- uint prevDay = prevTs.toTime_t() / 86400;
+ qint64 nextDay = nextTs.toMSecsSinceEpoch() / DAY_IN_MSECS;
+ qint64 prevDay = prevTs.toMSecsSinceEpoch() / DAY_IN_MSECS;
if (nextDay != prevDay) {
- nextTs.setTime_t(nextDay * 86400);
+ nextTs.setMSecsSinceEpoch(nextDay * DAY_IN_MSECS);
nextTs.setTimeSpec(Qt::LocalTime);
Message dayChangeMsg = Message::ChangeOfDay(nextTs);
dayChangeMsg.setMsgId((*iter).msgId());
QDateTime prevTs = (*iter).timestamp();
nextTs.setTimeSpec(Qt::UTC);
prevTs.setTimeSpec(Qt::UTC);
- uint nextDay = nextTs.toTime_t() / 86400;
- uint prevDay = prevTs.toTime_t() / 86400;
+ qint64 nextDay = nextTs.toMSecsSinceEpoch() / DAY_IN_MSECS;
+ qint64 prevDay = prevTs.toMSecsSinceEpoch() / DAY_IN_MSECS;
if (nextDay != prevDay) {
- nextTs.setTime_t(nextDay * 86400);
+ nextTs.setMSecsSinceEpoch(nextDay * DAY_IN_MSECS);
nextTs.setTimeSpec(Qt::LocalTime);
Message dayChangeMsg = Message::ChangeOfDay(nextTs);
dayChangeMsg.setMsgId((*iter).msgId());
void MessageModel::changeOfDay()
{
- _dayChangeTimer.setInterval(86400000);
+ _dayChangeTimer.setInterval(DAY_IN_MSECS);
if (!messagesIsEmpty()) {
int idx = messageCount();
while (idx > 0 && messageItemAt(idx - 1)->timestamp() > _nextDayChange) {
insertMessage__(idx, dayChangeMsg);
endInsertRows();
}
- _nextDayChange = _nextDayChange.addSecs(86400);
+ _nextDayChange = _nextDayChange.addMSecs(DAY_IN_MSECS);
}
QTimer _dayChangeTimer;
QDateTime _nextDayChange;
QHash<BufferId, int> _messagesWaiting;
+
+ /// Period of time for one day in milliseconds
+ /// 24 hours * 60 minutes * 60 seconds * 1000 milliseconds
+ const qint64 DAY_IN_MSECS = 24 * 60 * 60 * 1000;
};
#include "ircevent.h"
#include "networkevent.h"
#include "messageevent.h"
+#include "peer.h"
+#include "signalproxy.h"
Event::Event(EventManager::EventType type)
: _type(type)
return;
}
+ Q_ASSERT(SignalProxy::current());
+ Q_ASSERT(SignalProxy::current()->sourcePeer());
+
setFlags(static_cast<EventManager::EventFlags>(map.take("flags").toInt())); // TODO sanity check?
- setTimestamp(QDateTime::fromTime_t(map.take("timestamp").toUInt()));
+
+ if (SignalProxy::current()->sourcePeer()->hasFeature(Quassel::Feature::LongTime)) {
+ // timestamp is a qint64, signed rather than unsigned
+ setTimestamp(QDateTime::fromMSecsSinceEpoch(map.take("timestamp").toLongLong()));
+ } else {
+ setTimestamp(QDateTime::fromTime_t(map.take("timestamp").toUInt()));
+ }
}
void Event::toVariantMap(QVariantMap &map) const
{
+ Q_ASSERT(SignalProxy::current());
+ Q_ASSERT(SignalProxy::current()->targetPeer());
+
map["type"] = static_cast<int>(type());
map["flags"] = static_cast<int>(flags());
- map["timestamp"] = timestamp().toTime_t();
+ if (SignalProxy::current()->targetPeer()->hasFeature(Quassel::Feature::LongTime)) {
+ // toMSecs returns a qint64, signed rather than unsigned
+ map["timestamp"] = timestamp().toMSecsSinceEpoch();
+ } else {
+ map["timestamp"] = timestamp().toTime_t();
+ }
}
QDateTime IrcUser::idleTime()
{
- if (QDateTime::currentDateTime().toTime_t() - _idleTimeSet.toTime_t() > 1200)
+ if ((QDateTime::currentDateTime().toMSecsSinceEpoch() - _idleTimeSet.toMSecsSinceEpoch())
+ > 1200000) {
+ // 20 * 60 * 1000 = 1200000
+ // 20 minutes have elapsed, clear the known idle time as it's likely inaccurate by now
_idleTime = QDateTime();
+ }
return _idleTime;
}
// We do not serialize the sender prefixes until we have a new protocol or client-features implemented
out << msg.msgId();
- if (SignalProxy::current()->targetPeer()->hasFeature(Quassel::Feature::LongMessageTime)) {
- out << (quint64) msg.timestamp().toMSecsSinceEpoch();
+ if (SignalProxy::current()->targetPeer()->hasFeature(Quassel::Feature::LongTime)) {
+ // toMSecs returns a qint64, signed rather than unsigned
+ out << (qint64) msg.timestamp().toMSecsSinceEpoch();
} else {
out << (quint32) msg.timestamp().toTime_t();
}
in >> msg._msgId;
- if (SignalProxy::current()->sourcePeer()->hasFeature(Quassel::Feature::LongMessageTime)) {
- quint64 timeStamp;
+ if (SignalProxy::current()->sourcePeer()->hasFeature(Quassel::Feature::LongTime)) {
+ // timestamp is a qint64, signed rather than unsigned
+ qint64 timeStamp;
in >> timeStamp;
msg._timestamp = QDateTime::fromMSecsSinceEpoch(timeStamp);
} else {
if (!QString(GIT_HEAD).isEmpty()) {
buildInfo.commitHash = GIT_HEAD;
QDateTime date;
- date.setTime_t(GIT_COMMIT_DATE);
+#if QT_VERSION >= 0x050800
+ date.setSecsSinceEpoch(GIT_COMMIT_DATE);
+#else
+ // toSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#toMSecsSinceEpoch
+ // Warning generated if not converting the 1000 to a qint64 first.
+ date.setMSecsSinceEpoch(GIT_COMMIT_DATE * (qint64)1000);
+#endif
buildInfo.commitDate = date.toString();
}
else if (!QString(DIST_HASH).contains("Format")) {
SenderPrefixes, ///< Show prefixes for senders in backlog
RemoteDisconnect, ///< Allow this peer to be remotely disconnected
ExtendedFeatures, ///< Extended features
- LongMessageTime, ///< Serialize message time as 64-bit
+ LongTime, ///< Serialize time as 64-bit values
RichMessages, ///< Real Name and Avatar URL in backlog
BacklogFilterType, ///< BacklogManager supports filtering backlog by MessageType
#if QT_VERSION >= 0x050500
{
Q_ASSERT(!_registeredStorageBackends.empty());
- qsrand(QDateTime::currentDateTime().toTime_t());
+ qsrand(QDateTime::currentDateTime().toMSecsSinceEpoch());
int pass = 0;
for (int i = 0; i < 10; i++) {
pass *= 10;
void CoreNetwork::sendPing()
{
- uint now = QDateTime::currentDateTime().toTime_t();
+ qint64 now = QDateTime::currentDateTime().toMSecsSinceEpoch();
if (_pingCount != 0) {
qDebug() << "UserId:" << userId() << "Network:" << networkName() << "missed" << _pingCount << "pings."
<< "BA:" << socket.bytesAvailable() << "BTW:" << socket.bytesToWrite();
}
- if ((int)_pingCount >= networkConfig()->maxPingCount() && now - _lastPingTime <= (uint)(_pingTimer.interval() / 1000) + 1) {
+ if ((int)_pingCount >= networkConfig()->maxPingCount()
+ && (now - _lastPingTime) <= (_pingTimer.interval() + (1 * 1000))) {
+ // In transitioning to 64-bit time, the interval no longer needs converted down to seconds.
+ // However, to reduce the risk of breaking things by changing past behavior, we still allow
+ // up to 1 second missed instead of enforcing a stricter 1 millisecond allowance.
+ //
// the second check compares the actual elapsed time since the last ping and the pingTimer interval
// if the interval is shorter then the actual elapsed time it means that this thread was somehow blocked
// and unable to even handle a ping answer. So we ignore those misses.
int _lastUsedServerIndex;
QTimer _pingTimer;
- uint _lastPingTime;
+ qint64 _lastPingTime;
uint _pingCount;
bool _sendPings;
int idleSecs = e->params()[1].toInt();
if (e->params().count() > 3) { // if we have more then 3 params we have the above mentioned "real life" situation
- int logintime = e->params()[2].toInt();
- loginTime = QDateTime::fromTime_t(logintime);
+ // Allow for 64-bit time
+ qint64 logintime = e->params()[2].toLongLong();
+ // Time in IRC protocol is defined as seconds. Convert from seconds instead.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromSecsSinceEpoch
+#if QT_VERSION >= 0x050800
+ loginTime = QDateTime::fromSecsSinceEpoch(logintime);
+#else
+ // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for
+ // now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
+ loginTime = QDateTime::fromMSecsSinceEpoch((qint64)(logintime * 1000));
+#endif
}
IrcUser *ircuser = e->network()->ircUser(e->params()[0]);
target = nick;
IrcUser *ircuser = e->network()->ircUser(nick);
if (ircuser) {
+ // FIXME: This needs converted to 64-bit time.
+ // For legacy protocol, keep the 32-bit signed int time. For modern protocol, just send
+ // the actual QDateTime() instead, don't bother converting it.
int now = QDateTime::currentDateTime().toTime_t();
+ // FIXME: Convert to millisecond comparison, comment the constant value as needed
const int silenceTime = 60;
if (ircuser->lastAwayMessage() + silenceTime >= now)
send = false;
int idleSecs = e->params()[1].toInt();
if (e->params().count() > 3) { // if we have more then 3 params we have the above mentioned "real life" situation
- QDateTime loginTime = QDateTime::fromTime_t(e->params()[2].toInt()).toUTC();
+ // Time in IRC protocol is defined as seconds. Convert from seconds instead.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromSecsSinceEpoch
+#if QT_VERSION >= 0x050800
+ QDateTime loginTime = QDateTime::fromSecsSinceEpoch(e->params()[2].toLongLong()).toUTC();
+#else
+ // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
+ QDateTime loginTime = QDateTime::fromMSecsSinceEpoch(
+ (qint64)(e->params()[2].toLongLong() * 1000)).toUTC();
+#endif
displayMsg(e, Message::Server, tr("[Whois] %1 is logged in since %2")
.arg(e->params()[0], loginTime.toString("yyyy-MM-dd hh:mm:ss UTC")));
}
return;
QString channel = e->params()[0];
- uint unixtime = e->params()[1].toUInt();
+ // Allow for 64-bit time
+ qint64 unixtime = e->params()[1].toLongLong();
if (!unixtime) {
qWarning() << Q_FUNC_INFO << "received invalid timestamp:" << e->params()[1];
return;
}
- QDateTime time = QDateTime::fromTime_t(unixtime).toUTC();
+ // Time in IRC protocol is defined as seconds. Convert from seconds instead.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromSecsSinceEpoch
+#if QT_VERSION >= 0x050800
+ QDateTime time = QDateTime::fromSecsSinceEpoch(unixtime).toUTC();
+#else
+ // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
+ QDateTime time = QDateTime::fromMSecsSinceEpoch((qint64)(unixtime * 1000)).toUTC();
+#endif
displayMsg(e, Message::Topic, tr("Channel %1 created on %2")
.arg(channel, time.toString("yyyy-MM-dd hh:mm:ss UTC")),
QString(), channel);
return;
QString channel = e->params().first();
- QDateTime topicSetTime = QDateTime::fromTime_t(e->params()[2].toInt()).toUTC();
+ // Time in IRC protocol is defined as seconds. Convert from seconds instead.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromSecsSinceEpoch
+#if QT_VERSION >= 0x050800
+ QDateTime topicSetTime = QDateTime::fromSecsSinceEpoch(e->params()[2].toLongLong()).toUTC();
+#else
+ // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
+ QDateTime topicSetTime = QDateTime::fromMSecsSinceEpoch(
+ (qint64)(e->params()[2].toLongLong() * 1000)).toUTC();
+#endif
displayMsg(e, Message::Topic, tr("Topic set by %1 on %2")
.arg(e->params()[1],
topicSetTime.toString("yyyy-MM-dd hh:mm:ss UTC")), QString(), channel);
}
QVariantList params;
+ // PostgreSQL handles QDateTime()'s serialized format by default, and QDateTime() serializes
+ // to a 64-bit time compatible format by default.
params << msg.timestamp()
<< msg.bufferInfo().bufferId().toInt()
<< msg.type()
for (int i = 0; i < msgs.count(); i++) {
Message &msg = msgs[i];
QVariantList params;
+ // PostgreSQL handles QDateTime()'s serialized format by default, and QDateTime() serializes
+ // to a 64-bit time compatible format by default.
params << msg.timestamp()
<< msg.bufferInfo().bufferId().toInt()
<< msg.type()
QDateTime timestamp;
while (query.next()) {
+ // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+ // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
timestamp = query.value(1).toDateTime();
timestamp.setTimeSpec(Qt::UTC);
Message msg(timestamp,
QDateTime timestamp;
while (query.next()) {
+ // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+ // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
timestamp = query.value(1).toDateTime();
timestamp.setTimeSpec(Qt::UTC);
Message msg(timestamp,
QDateTime timestamp;
for (int i = 0; i < limit && query.next(); i++) {
+ // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+ // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
timestamp = query.value(2).toDateTime();
timestamp.setTimeSpec(Qt::UTC);
Message msg(timestamp,
QDateTime timestamp;
for (int i = 0; i < limit && query.next(); i++) {
+ // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+ // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
timestamp = query.value(2).toDateTime();
timestamp.setTimeSpec(Qt::UTC);
Message msg(timestamp,
{
QSqlQuery logMessageQuery(db);
logMessageQuery.prepare(queryString("insert_message"));
-
- logMessageQuery.bindValue(":time", msg.timestamp().toTime_t());
+ // Store timestamp in seconds as 64-bit integer
+ //
+ // NOTE: This is a loss of precision. The database time column would need to store a
+ // fractional number to support toMSecsSinceEpoch(), or an upgrade step would need to
+ // convert all past times to milliseconds, multiplying by 1000.
+#if QT_VERSION >= 0x050800
+ logMessageQuery.bindValue(":time", msg.timestamp().toSecsSinceEpoch());
+#else
+ // toSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#toMSecsSinceEpoch
+ logMessageQuery.bindValue(":time", (qint64)(msg.timestamp().toMSecsSinceEpoch() / 1000));
+#endif
logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
logMessageQuery.bindValue(":type", msg.type());
logMessageQuery.bindValue(":flags", (int)msg.flags());
logMessageQuery.prepare(queryString("insert_message"));
for (int i = 0; i < msgs.count(); i++) {
Message &msg = msgs[i];
-
- logMessageQuery.bindValue(":time", msg.timestamp().toTime_t());
+ // Store timestamp in seconds as 64-bit integer
+ //
+ // NOTE: This is a loss of precision. The database time column would need to store a
+ // fractional number to support toMSecsSinceEpoch(), or an upgrade step would need to
+ // convert all past times to milliseconds, multiplying by 1000.
+#if QT_VERSION >= 0x050800
+ logMessageQuery.bindValue(":time", msg.timestamp().toSecsSinceEpoch());
+#else
+ // toSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#toMSecsSinceEpoch
+ logMessageQuery.bindValue(":time",
+ (qint64)(msg.timestamp().toMSecsSinceEpoch() / 1000));
+#endif
logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
logMessageQuery.bindValue(":type", msg.type());
logMessageQuery.bindValue(":flags", (int)msg.flags());
watchQuery(query);
while (query.next()) {
- Message msg(QDateTime::fromTime_t(query.value(1).toInt()),
+ Message msg(
+ // Read timestamp in seconds as 64-bit integer
+ //
+ // NOTE: This is a loss of precision. The database time column would need to store
+ // a fractional number to support fromMSecsSinceEpoch(), or an upgrade step would
+ // need to convert all past times to milliseconds, multiplying by 1000.
+#if QT_VERSION >= 0x050800
+ QDateTime::fromSecsSinceEpoch(query.value(1).toLongLong()),
+#else
+ // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for
+ // now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
+ QDateTime::fromMSecsSinceEpoch((qint64)(query.value(1).toLongLong() * 1000)),
+#endif
bufferInfo,
(Message::Type)query.value(2).toInt(),
query.value(8).toString(),
watchQuery(query);
while (query.next()) {
- Message msg(QDateTime::fromTime_t(query.value(1).toInt()),
+ Message msg(
+ // Read timestamp in seconds as 64-bit integer
+ //
+ // NOTE: This is a loss of precision. The database time column would need
+ // to store a fractional number to support fromMSecsSinceEpoch(), or an
+ // upgrade step would need to convert all past times to milliseconds,
+ // multiplying by 1000.
+#if QT_VERSION >= 0x050800
+ QDateTime::fromSecsSinceEpoch(query.value(1).toLongLong()),
+#else
+ // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to
+ // seconds for now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
+ QDateTime::fromMSecsSinceEpoch(
+ (qint64)(query.value(1).toLongLong() * 1000)),
+#endif
bufferInfo,
(Message::Type)query.value(2).toInt(),
query.value(8).toString(),
watchQuery(query);
while (query.next()) {
- Message msg(QDateTime::fromTime_t(query.value(2).toInt()),
+ Message msg(
+ // Read timestamp in seconds as 64-bit integer
+ //
+ // NOTE: This is a loss of precision. The database time column would need to store
+ // a fractional number to support fromMSecsSinceEpoch(), or an upgrade step would
+ // need to convert all past times to milliseconds, multiplying by 1000.
+#if QT_VERSION >= 0x050800
+ QDateTime::fromSecsSinceEpoch(query.value(2).toLongLong()),
+#else
+ // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for
+ // now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
+ QDateTime::fromMSecsSinceEpoch((qint64)(query.value(2).toLongLong() * 1000)),
+#endif
bufferInfoHash[query.value(1).toInt()],
(Message::Type)query.value(3).toInt(),
query.value(9).toString(),
watchQuery(query);
while (query.next()) {
- Message msg(QDateTime::fromTime_t(query.value(2).toInt()),
+ Message msg(
+ // Read timestamp in seconds as 64-bit integer
+ //
+ // NOTE: This is a loss of precision. The database time column would need
+ // to store a fractional number to support fromMSecsSinceEpoch(), or an
+ // upgrade step would need to convert all past times to milliseconds,
+ // multiplying by 1000.
+#if QT_VERSION >= 0x050800
+ QDateTime::fromSecsSinceEpoch(query.value(2).toLongLong()),
+#else
+ // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to
+ // seconds for now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
+ QDateTime::fromMSecsSinceEpoch(
+ (qint64)(query.value(2).toLongLong() * 1000)),
+#endif
bufferInfoHash[query.value(1).toInt()],
(Message::Type)query.value(3).toInt(),
query.value(9).toString(),
}
backlog.messageid = value(0).toLongLong();
- backlog.time = QDateTime::fromTime_t(value(1).toInt()).toUTC();
+ // Read timestamp in seconds as 64-bit integer
+ //
+ // NOTE: This is a loss of precision. The database time column would need to store a
+ // fractional number to support fromMSecsSinceEpoch(), or an upgrade step would need to convert
+ // all past times to milliseconds, multiplying by 1000.
+#if QT_VERSION >= 0x050800
+ backlog.time = QDateTime::fromSecsSinceEpoch(value(1).toLongLong()).toUTC();
+#else
+ // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for
+ // now.
+ // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
+ backlog.time = QDateTime::fromMSecsSinceEpoch((qint64)(value(1).toLongLong() * 1000)
+ ).toUTC();
+#endif
backlog.bufferid = value(2).toInt();
backlog.type = value(3).toInt();
backlog.flags = value(4).toInt();