fix time events for rules

old code would compare QTime == QTime() every second which might not trigger
if e.g. milliseconds don't match. New code checks the interval between the
last check and the current one.
This commit is contained in:
Michael Zanetti 2017-07-05 19:01:37 +02:00
parent ac179d0f70
commit 414d25c870
6 changed files with 28 additions and 16 deletions

View File

@ -122,7 +122,8 @@ namespace guhserver {
instance available from \l{GuhCore}. This one should be used instead of creating multiple ones. instance available from \l{GuhCore}. This one should be used instead of creating multiple ones.
*/ */
RuleEngine::RuleEngine(QObject *parent) : RuleEngine::RuleEngine(QObject *parent) :
QObject(parent) QObject(parent),
m_lastEvaluationTime(QDateTime::currentDateTime())
{ {
GuhSettings settings(GuhSettings::SettingsRoleRules); GuhSettings settings(GuhSettings::SettingsRoleRules);
qCDebug(dcRuleEngine) << "loading rules from" << settings.fileName(); qCDebug(dcRuleEngine) << "loading rules from" << settings.fileName();
@ -396,7 +397,7 @@ QList<Rule> RuleEngine::evaluateTime(const QDateTime &dateTime)
// check if this rule is based on calendarItems // check if this rule is based on calendarItems
if (!rule.timeDescriptor().calendarItems().isEmpty()) { if (!rule.timeDescriptor().calendarItems().isEmpty()) {
//qCDebug(dcRuleEngine()) << "Evaluate CalendarItem against" << dateTime.toString("dd:MM:yyyy hh:mm") << "for rule" << rule.id().toString(); //qCDebug(dcRuleEngine()) << "Evaluate CalendarItem against" << dateTime.toString("dd:MM:yyyy hh:mm") << "for rule" << rule.id().toString();
bool active = rule.timeDescriptor().evaluate(dateTime); bool active = rule.timeDescriptor().evaluate(m_lastEvaluationTime, dateTime);
if (active) { if (active) {
if (!m_activeRules.contains(rule.id())) { if (!m_activeRules.contains(rule.id())) {
qCDebug(dcRuleEngine) << "Rule" << rule.id().toString() << "active."; qCDebug(dcRuleEngine) << "Rule" << rule.id().toString() << "active.";
@ -418,7 +419,7 @@ QList<Rule> RuleEngine::evaluateTime(const QDateTime &dateTime)
// check if this rule is based on timeEventItems // check if this rule is based on timeEventItems
if (!rule.timeDescriptor().timeEventItems().isEmpty()) { if (!rule.timeDescriptor().timeEventItems().isEmpty()) {
bool valid = rule.timeDescriptor().evaluate(dateTime); bool valid = rule.timeDescriptor().evaluate(m_lastEvaluationTime, dateTime);
if (valid) { if (valid) {
rules.append(rule); rules.append(rule);
} }
@ -426,6 +427,7 @@ QList<Rule> RuleEngine::evaluateTime(const QDateTime &dateTime)
} }
} }
m_lastEvaluationTime = QDateTime::currentDateTime();
return rules; return rules;
} }

View File

@ -112,6 +112,8 @@ private:
QList<RuleId> m_ruleIds; // Keeping a list of RuleIds to keep sorting order... QList<RuleId> m_ruleIds; // Keeping a list of RuleIds to keep sorting order...
QHash<RuleId, Rule> m_rules; // ...but use a Hash for faster finding QHash<RuleId, Rule> m_rules; // ...but use a Hash for faster finding
QList<RuleId> m_activeRules; QList<RuleId> m_activeRules;
QDateTime m_lastEvaluationTime;
}; };
} }

View File

@ -82,7 +82,7 @@ bool TimeDescriptor::isEmpty() const
valid if the \l{TimeEventItem}{TimeEventItems} or \l{CalendarItem}{CalendarItems} match valid if the \l{TimeEventItem}{TimeEventItems} or \l{CalendarItem}{CalendarItems} match
the given \a dateTime. the given \a dateTime.
*/ */
bool TimeDescriptor::evaluate(const QDateTime &dateTime) const bool TimeDescriptor::evaluate(const QDateTime &lastEvaluationTime, const QDateTime &dateTime) const
{ {
// If there are calendarItems (always OR connected) // If there are calendarItems (always OR connected)
if (!m_calendarItems.isEmpty()) { if (!m_calendarItems.isEmpty()) {
@ -96,7 +96,7 @@ bool TimeDescriptor::evaluate(const QDateTime &dateTime) const
// If there are timeEventItems (always OR connected) // If there are timeEventItems (always OR connected)
if (!m_timeEventItems.isEmpty()) { if (!m_timeEventItems.isEmpty()) {
foreach (const TimeEventItem &timeEventItem, m_timeEventItems) { foreach (const TimeEventItem &timeEventItem, m_timeEventItems) {
if (timeEventItem.evaluate(dateTime)) { if (timeEventItem.evaluate(lastEvaluationTime, dateTime)) {
return true; return true;
} }
} }

View File

@ -41,7 +41,7 @@ public:
bool isValid() const; bool isValid() const;
bool isEmpty() const; bool isEmpty() const;
bool evaluate(const QDateTime &dateTime) const; bool evaluate(const QDateTime &lastEvaluationTime, const QDateTime &dateTime) const;
// void dumpToSettings(GuhSettings &settings, const QString &groupName) const; // void dumpToSettings(GuhSettings &settings, const QString &groupName) const;
// static TimeDescriptor loadFromSettings(GuhSettings &settings, const QString &groupPrefix); // static TimeDescriptor loadFromSettings(GuhSettings &settings, const QString &groupPrefix);

View File

@ -90,22 +90,30 @@ bool TimeEventItem::isValid() const
} }
/*! Returns true, if the given \a dateTime matches this \l{TimeEventItem}. */ /*! Returns true, if the given \a dateTime matches this \l{TimeEventItem}. */
bool TimeEventItem::evaluate(const QDateTime &dateTime) const bool TimeEventItem::evaluate(const QDateTime &lastEvaluationTime, const QDateTime &dateTime) const
{ {
// Check time matches // Check time matches
if (m_time.isValid()) { if (m_time.isValid()) {
switch (m_repeatingOption.mode()) { switch (m_repeatingOption.mode()) {
case RepeatingOption::RepeatingModeNone:
// If there is no repeating option, we assume it is meant daily. // If there is no repeating option, we assume it is meant daily.
return m_time == dateTime.time();; case RepeatingOption::RepeatingModeNone:
case RepeatingOption::RepeatingModeHourly:
return m_time.minute() == dateTime.time().minute();
case RepeatingOption::RepeatingModeDaily: case RepeatingOption::RepeatingModeDaily:
return m_time == dateTime.time();; return lastEvaluationTime.time() < m_time && m_time <= dateTime.time();
case RepeatingOption::RepeatingModeHourly: {
QTime begin, vut, end;
begin.setHMS(0, lastEvaluationTime.time().minute(), lastEvaluationTime.time().second());
end.setHMS(0, dateTime.time().minute(), dateTime.time().second());
vut.setHMS(0, m_time.minute(), m_time.second());
return begin < vut && vut < end;
}
case RepeatingOption::RepeatingModeWeekly: case RepeatingOption::RepeatingModeWeekly:
return m_repeatingOption.evaluateWeekDay(dateTime) && m_time == dateTime.time(); return m_repeatingOption.evaluateWeekDay(dateTime) &&
lastEvaluationTime.time() < m_time &&
m_time <= dateTime.time();
case RepeatingOption::RepeatingModeMonthly: case RepeatingOption::RepeatingModeMonthly:
return m_repeatingOption.evaluateMonthDay(dateTime) && m_time == dateTime.time(); return m_repeatingOption.evaluateMonthDay(dateTime) &&
lastEvaluationTime.time() < m_time &&
m_time <= dateTime.time();
case RepeatingOption::RepeatingModeYearly: case RepeatingOption::RepeatingModeYearly:
return false; return false;
} }
@ -115,7 +123,7 @@ bool TimeEventItem::evaluate(const QDateTime &dateTime) const
if (m_repeatingOption.mode() == RepeatingOption::RepeatingModeYearly) if (m_repeatingOption.mode() == RepeatingOption::RepeatingModeYearly)
return m_dateTime.date().month() == dateTime.date().month() && return m_dateTime.date().month() == dateTime.date().month() &&
m_dateTime.date().day() == dateTime.date().day() && m_dateTime.date().day() == dateTime.date().day() &&
m_dateTime.time() == dateTime.time(); lastEvaluationTime.time() < m_dateTime.time() && m_dateTime.time() <= dateTime.time();
// Check dateTime matches // Check dateTime matches
return dateTime == m_dateTime; return dateTime == m_dateTime;

View File

@ -45,7 +45,7 @@ public:
bool isValid() const; bool isValid() const;
bool evaluate(const QDateTime &dateTime) const; bool evaluate(const QDateTime &lastEvaluationTime, const QDateTime &dateTime) const;
private: private:
QDateTime m_dateTime; QDateTime m_dateTime;