添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
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?

It's always the same. Try the code – I ran this quite often before adding the workaround … – Tobias Leupold Aug 4, 2017 at 20:34 If I had a best guess, it would be that QDateTime::secsTo() is doing something weird with postive/negative integers. It looks like it is doing an integer ceiling for negative numbers, and an integer floor for positive numbers. Try switching to mSecsTo and report back. – user2836202 Aug 4, 2017 at 20:35 I would be interested in the millisecond differences printed along with the second differences using QDateTime::msecsTo() – drescherjm Aug 4, 2017 at 20:35

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.