I recently wrote a stopwatch and noticed some strange behavior of QDateTime::secsTo
. I'm not sure if it's a bug or a feature (or perhaps I only did a crappy implementation ;-).
My stopwatch code can be stripped down to this minimal example to produce the questionable result (at least on Linux using Qt 5.7.1):
StopWatch.h
#ifndef STOPWATCH_H
#define STOPWATCH_H
#include <QDialog>
#include <QDateTime>
class QTimer;
class StopWatch : public QDialog
{
Q_OBJECT
public:
explicit StopWatch(QWidget *parent);
private slots:
void update();
private:
QTimer *m_timer;
QDateTime m_targetTime;
};
#endif // STOPWATCH_H
StopWatch.cpp
#include "StopWatch.h"
#include <QDebug>
#include <QTimer>
StopWatch::StopWatch(QWidget *parent) : QDialog(parent)
{
m_timer = new QTimer(this);
m_timer->setTimerType(Qt::PreciseTimer);
connect(m_timer, &QTimer::timeout, this, &StopWatch::update);
m_targetTime = QDateTime::currentDateTime().addSecs(10);
m_timer->start(1000);
}
void StopWatch::update()
{
QDateTime currentDateTime = QDateTime::currentDateTime();
qint64 secondsLeft = currentDateTime.secsTo(m_targetTime);
qDebug() << secondsLeft;
}
And here's (a part of) the output:
4
3
2
1
0
0
-1
-2
-3
-4
So here we are: QDateTime::secsTo
outputs 0
for the same QDateTime
and for a QDateTime
one second before.
I worked around this by doing
if (currentDateTime <= m_targetTime) {
secondsLeft++;
}
but I don't understand the behavoir. Why is this the case?
Looking at the source code http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qdatetime.cpp
int QTime::secsTo(const QTime &t) const
{
if (!isValid() || !t.isValid())
return 0;
// Truncate milliseconds as we do not want to consider them.
int ourSeconds = ds() / 1000;
int theirSeconds = t.ds() / 1000;
return theirSeconds - ourSeconds;
}
It looks like it takes two positive integers that are under 1000, divides them by 1000, and then subtracts them from each other. If you use mSecsTo(), you will not have this problem.