NiladriBose
NiladriBose

Reputation: 1905

Set system clock with QT on linux

How would we go about changing the system time on a linux system programatically using QT widget application ?

Upvotes: 0

Views: 6881

Answers (3)

NiladriBose
NiladriBose

Reputation: 1905

I found a simple solution. As my system is very minimalist i dont want to use things like dbus. As a root or sudoer this can be execute (fairly self explainatory )-

QString string = dateTime.toString("\"yyyy-MM-dd hh:mm\"");
QString dateTimeString ("date -s ");
dateTimeString.append(string);
int systemDateTimeStatus= system(dateTimeString.toStdString().c_str());
if (systemDateTimeStatus == -1)
{
    qDebug() << "Failed to change date time";
}
int systemHwClockStatus = system("/sbin/hwclock -w");
if (systemHwClockStatus == -1 )
{
    qDebug() << "Failed to sync hardware clock";
}

Upvotes: 2

Eligijus Pupeikis
Eligijus Pupeikis

Reputation: 1125

You can use dbus to interface with timedated daemon https://www.freedesktop.org/wiki/Software/systemd/timedated/

to set time and date.

Qt provides a way to generate interface code from xml http://doc.qt.io/qt-5/qdbusxml2cpp.html. You can get xml by introspection.

I don't like generated code formatting so I wrote interface code myself

h:

#ifndef TIMEDATE1SERVICE_H
#define TIMEDATE1SERVICE_H

#include <QObject>
#include <QString>
#include <QVariant>
#include <QtDBus>

class Timedate1Interface: public QDBusAbstractInterface
{
    Q_OBJECT
    Q_PROPERTY(bool CanNTP READ CanNTP)
    Q_PROPERTY(bool LocalRTC READ LocalRTC)
    Q_PROPERTY(bool NTP READ NTP)
    Q_PROPERTY(bool NTPSynchronized READ NTPSynchronized)
    Q_PROPERTY(qulonglong RTCTimeUSec READ RTCTimeUSec)
    Q_PROPERTY(qulonglong TimeUSec READ TimeUSec)
    Q_PROPERTY(QString Timezone READ Timezone)

public:
    explicit Timedate1Interface(QObject *parent = nullptr);

    bool CanNTP() const;
    bool LocalRTC() const;
    bool NTP() const;
    bool NTPSynchronized() const;
    qulonglong RTCTimeUSec() const;
    qulonglong TimeUSec() const;
    QString Timezone() const;

    void SetLocalRTC(bool localRTC, bool fixSystem, bool userInteraction);
    void SetNTP(bool useNTP, bool userInteraction);
    void SetTime(qlonglong usecUTC, bool relative, bool userInteraction);
    void SetTimezone(const QString &timezone, bool userInteraction);
};

#endif // TIMEDATE1SERVICE_H

cpp:

#include "timedate1service.h"

Timedate1Interface::Timedate1Interface(QObject *parent)
    : QDBusAbstractInterface("org.freedesktop.timedate1", "/org/freedesktop/timedate1",
                             "org.freedesktop.timedate1", QDBusConnection::systemBus(), parent)
{

}

bool Timedate1Interface::CanNTP() const
{
    return qvariant_cast<bool>(property("CanNTP"));
}

bool Timedate1Interface::LocalRTC() const
{
    return qvariant_cast<bool>(property("LocalRTC"));
}

bool Timedate1Interface::NTP() const
{
    return qvariant_cast<bool>(property("NTP"));
}

bool Timedate1Interface::NTPSynchronized() const
{
    return qvariant_cast<bool>(property("NTPSynchronized"));
}

qulonglong Timedate1Interface::RTCTimeUSec() const
{
    return qvariant_cast<qulonglong>(property("RTCTimeUSec"));
}

qulonglong Timedate1Interface::TimeUSec() const
{
    return qvariant_cast<qulonglong>(property("TimeUSec"));
}

QString Timedate1Interface::Timezone() const
{
    return qvariant_cast<QString>(property("Timezone"));
}

void Timedate1Interface::SetLocalRTC(bool localRTC, bool fixSystem, bool userInteraction)
{
    call("SetLocalRTC", localRTC, fixSystem, userInteraction);
}

void Timedate1Interface::SetNTP(bool useNTP, bool userInteraction)
{
    call("SetNTP", useNTP, userInteraction);
}

void Timedate1Interface::SetTime(qlonglong usecUTC, bool relative, bool userInteraction)
{
    call("SetTime", usecUTC, relative , userInteraction);
}

void Timedate1Interface::SetTimezone(const QString &timezone, bool userInteraction)
{
    call("SetTimezone", timezone, userInteraction);
}

Upvotes: 3

You cannot do that in pure Qt. You need to use Linux (or POSIX) specific things.

And you probably should not do that, but better yet configure your entire system to use NTP (e.g. by running some NTP client...). Most Linux distributions have that already.

If you really want to set the system time (but you should not do that directly from a Qt application, since Qt applications should not run as root, but see this), read time(7) then adjtimex(2) & settimeofday(2)

You need to be root for that, so you should not do that from a Qt application. You might use setuid techniques to run some specific command or program as root. Setuid is tricky (see credentials(7), execve(2), setreuid(2)...), could open a giant security hole if misused (and making mistakes is easy), so read something about Linux programming, e.g. the old ALP.

So if you insist doing that (and it is probably wrong), write a tiny specific program in C for that and make it setuid and run that setuid-program from your Qt application (e.g. using QProcess).

Upvotes: 3

Related Questions