/* ** Copyright (C) 2023 Victron Energy B.V. ** See LICENSE.txt for license information. */ #include "clocktime.h" #if !defined(VENUS_WEBASSEMBLY_BUILD) #include #endif using namespace Victron::VenusOS; ClockTime::ClockTime(QObject *parent) : QObject(parent) { } ClockTime* ClockTime::create(QQmlEngine *engine, QJSEngine *) { static ClockTime* clockTime = new ClockTime(nullptr); return clockTime; } QDateTime ClockTime::dateTime() const { return m_dateTime; } void ClockTime::setDateTime(const QDateTime &dt) { if (m_dateTime != dt || m_dateTime.timeZoneAbbreviation() != dt.timeZoneAbbreviation()) { const QDateTime old = m_dateTime; m_dateTime = dt; emit dateTimeChanged(); emit clockTimeChanged(); if (old.date().year() != dt.date().year()) emit yearChanged(); if (old.date().month() != dt.date().month()) emit monthChanged(); if (old.date().day() != dt.date().day()) emit dayChanged(); if (old.time().hour() != dt.time().hour()) emit hourChanged(); if (old.time().minute() != dt.time().minute()) emit minuteChanged(); if (old.time().second() != dt.time().second()) emit secondChanged(); if (old.time().msec() != dt.time().msec()) emit msecChanged(); if (old.date().year() != dt.date().year() || old.date().month() != dt.date().month() || old.date().day() != dt.date().day()) emit currentDateChanged(); if (old.time().hour() != dt.time().hour() || old.time().minute() != dt.time().minute()) emit currentTimeChanged(); emit currentDateTimeUtcChanged(); } } int ClockTime::year() const { return m_dateTime.date().year(); } int ClockTime::month() const { return m_dateTime.date().month(); } int ClockTime::day() const { return m_dateTime.date().day(); } int ClockTime::hour() const { return m_dateTime.time().hour(); } int ClockTime::minute() const { return m_dateTime.time().minute(); } int ClockTime::second() const { return m_dateTime.time().second(); } int ClockTime::msec() const { return m_dateTime.time().msec(); } qint64 ClockTime::clockTime() const { return m_dateTime.toSecsSinceEpoch(); } void ClockTime::setClockTime(qint64 secondsSinceEpoch) { if (clockTime() == secondsSinceEpoch) { return; } updateTime(secondsSinceEpoch); // Wait until just after the next clock minute, then update the time properties. const int secsUntilNextMin = 60 - m_dateTime.time().second(); scheduleNextTimeCheck((secsUntilNextMin + 1) * 1000); } QString ClockTime::systemTimeZone() const { return m_systemTimeZone; } void ClockTime::setSystemTimeZone(const QString &tz) { if (m_systemTimeZone != tz) { m_systemTimeZone = tz; updateTime(clockTime()); emit systemTimeZoneChanged(); } } QString ClockTime::currentDate() const { return m_dateTime.toString("yyyy-MM-dd"); } QString ClockTime::currentTime() const { return m_dateTime.toString("hh:mm"); } QString ClockTime::currentDateTimeUtc() const { return m_dateTime.toUTC().toString("yyyy-MM-dd hh:mm"); } QString ClockTime::formatTime(int hour, int minute) const { QTime t(hour, minute); return t.toString("hh:mm"); } QString ClockTime::formatDeltaDate(qint64 secondsDelta, const QString &format) const { return m_dateTime.addSecs(secondsDelta).toString(format); } qint64 ClockTime::otherClockTime(int year, int month, int day, int hour, int minute) const { // assume that the specified date/time is in our current clock time's timezone. QDateTime other = m_dateTime; QDate d = other.date(); d.setDate(year, month, day); other.setDate(d); QTime t = other.time(); t.setHMS(hour, minute, t.second(), t.msec()); other.setTime(t); return other.toSecsSinceEpoch(); } bool ClockTime::isDateValid(int year, int month, int day) const { static const QCalendar calendar; return calendar.isDateValid(year, month, day); } int ClockTime::daysInMonth(int month, int year) const { static const QCalendar calendar; return calendar.daysInMonth(month, year); } void ClockTime::timerEvent(QTimerEvent *) { qint64 secsSinceEpoch = clockTime(); if (secsSinceEpoch <= 0) { return; } secsSinceEpoch += (m_timerInterval / 1000); updateTime(secsSinceEpoch); scheduleNextTimeCheck(60 * 1000); } void ClockTime::updateTime(qint64 secsSinceEpoch) { if (secsSinceEpoch <= 0) { return; } const QDateTime currentUtc = QDateTime::fromSecsSinceEpoch(secsSinceEpoch, Qt::UTC); if (m_systemTimeZone.compare(QStringLiteral("/UTC"), Qt::CaseInsensitive) == 0 || m_systemTimeZone.compare(QStringLiteral("UTC"), Qt::CaseInsensitive) == 0) { setDateTime(currentUtc); } else { #if defined(VENUS_WEBASSEMBLY_BUILD) // Cannot use QTimeZone in Emscripten builds. // We thus cannot convert to the specified timezone offset. // The local time will be the local time of the browser. setDateTime(currentUtc.toLocalTime()); #else setDateTime(currentUtc.toTimeZone(QTimeZone(m_systemTimeZone.toUtf8()))); #endif } } void ClockTime::scheduleNextTimeCheck(int interval) { if (m_timerId > 0) { killTimer(m_timerId); } m_timerInterval = interval; m_timerId = startTimer(interval); }