Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
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:
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.
It's a rounding issue. The secsTo
function doesn't round to the nearest integer, but just drops the decimal part (this is what compilers do by default):
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;
or 4.x version:
int QTime::secsTo(const QTime &t) const
return (t.ds() - ds()) / 1000;
So what you probably see is:
4.8 -> 4
3.8 -> 3
2.8 -> 2
1.8 -> 1
0.8 -> 0
-0.2 -> 0
-1.2 -> -1
-2.2 -> -2
-3.2 -> -3
-4.2 -> -4
For the expected result, use something like:
qint64 secondsLeft = qRound64(currentDateTime.msecsTo(m_targetTime) / 1000.0);
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.