From 71fa4c5578eb2ea57899e63c3aa5c42461502483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jo=C5=84ski?= Date: Thu, 12 Aug 2021 17:42:43 +0200 Subject: [PATCH] [BH-721] Fix and add new rrule generator methods Add rrule generator for next incoming timestamp Add ical iterator wrapper Fix existing range generator to include event start timestamp Use time lib TimePoint definition Add neccessary public dependencies --- module-utils/rrule/CMakeLists.txt | 1 + module-utils/rrule/rrule/rrule.cpp | 93 ++++++++++++++++--- module-utils/rrule/rrule/rrule.hpp | 31 +++++-- module-utils/rrule/test/unittest_rrule.cpp | 102 ++++++++++++++++++--- module-utils/time/CMakeLists.txt | 2 +- module-utils/time/time/dateCommon.hpp | 1 + 6 files changed, 196 insertions(+), 34 deletions(-) diff --git a/module-utils/rrule/CMakeLists.txt b/module-utils/rrule/CMakeLists.txt index 210becaca7ad1b95e003287e60e3167651961c75..2e5550b5f305a512b1c204a6888a9e10c6d33869 100644 --- a/module-utils/rrule/CMakeLists.txt +++ b/module-utils/rrule/CMakeLists.txt @@ -13,6 +13,7 @@ target_include_directories(rrule PUBLIC $ + extern "C" { #include @@ -22,13 +24,44 @@ namespace rrule template unsigned vectorToIcalArray(const std::vector &vect, arrayT *array, unsigned max_size); + RRuleIter::RRuleIter(const RRule &rrule, const TimePoint eventStart) + { + auto icalEventStart = icaltime_from_timet_with_zone(std::chrono::system_clock::to_time_t(eventStart), 0, NULL); + iter = icalrecur_iterator_new(RRuletoIcalRecurrenceType(rrule), icalEventStart); + } + + RRuleIter::~RRuleIter() + { + icalrecur_iterator_free(iter); + iter = nullptr; + } + + void RRuleIter::setRange(const TimePoint rangeStart, const TimePoint rangeEnd) + { + auto icalTimeStart = icaltime_from_timet_with_zone(std::chrono::system_clock::to_time_t(rangeStart), 0, NULL); + auto icalTimeEnd = icaltime_from_timet_with_zone(std::chrono::system_clock::to_time_t(rangeEnd), 0, NULL); + + icalrecur_iterator_set_range(iter, icalTimeStart, icalTimeEnd); + } + + TimePoint RRuleIter::next() + { + icaltimetype nextIcal = icalrecur_iterator_next(iter); + if (icaltime_is_null_time(nextIcal)) { + return TIME_POINT_INVALID; + } + else { + return std::chrono::system_clock::from_time_t(icaltime_as_timet(nextIcal)); + } + } + void RRule::parseFromString(std::string_view str) { const auto icalRrule = icalrecurrencetype_from_string(str.data()); const time_t untilTimeT = icaltime_as_timet(icalRrule.until); if (untilTimeT == 0) { - until = TimePoint::min(); + until = TIME_POINT_INVALID; } else { until = std::chrono::system_clock::from_time_t(untilTimeT); @@ -57,31 +90,61 @@ namespace rrule return std::string{icalrecurrencetype_as_string(&icalRRule)}; } - std::vector RRule::generateEventTimePoints(const TimePoint start, - const TimePoint end, + std::vector RRule::generateEventTimePoints(const TimePoint eventStart, + const TimePoint rangeStart, + const TimePoint rangeEnd, const unsigned int count) { std::vector eventsTimePoints; - auto icalTimeStart = icaltime_from_timet_with_zone(std::chrono::system_clock::to_time_t(start), 0, NULL); - auto icalTimeEnd = icaltime_from_timet_with_zone(std::chrono::system_clock::to_time_t(end), 0, NULL); unsigned int counter = 0; - const icalrecurrencetype recur = RRuletoIcalRecurrenceType(*this); - auto ritr = icalrecur_iterator_new(recur, icalTimeStart); - icalrecur_iterator_set_range(ritr, icalTimeStart, icalTimeEnd); - icaltimetype next = icalrecur_iterator_next(ritr); + TimePoint singleEventTimePoint; + auto rruleIter = RRuleIter(*this, eventStart); + rruleIter.setRange(eventStart, rangeEnd); - while (!icaltime_is_null_time(next) && counter < count) { - auto singleEventTimePoint = std::chrono::system_clock::from_time_t(icaltime_as_timet(next)); - next = icalrecur_iterator_next(ritr); + do { + singleEventTimePoint = rruleIter.next(); + if (singleEventTimePoint < rangeStart) { + continue; + } eventsTimePoints.push_back(singleEventTimePoint); counter++; - } + } while (singleEventTimePoint != TIME_POINT_INVALID && singleEventTimePoint < rangeEnd && counter < count); - icalrecur_iterator_free(ritr); return eventsTimePoints; } + TimePoint RRule::generateNextTimePoint(const TimePoint eventStart, const TimePoint rangeStart) + { + TimePoint singleEventTimePoint; + auto rruleIter = RRuleIter(*this, eventStart); + + do { + singleEventTimePoint = rruleIter.next(); + + } while (singleEventTimePoint != TIME_POINT_INVALID && singleEventTimePoint < rangeStart); + + return singleEventTimePoint; + } + + TimePoint RRule::generateLastTimePoint(const TimePoint eventStart) + { + if (until == TIME_POINT_INVALID && count == 0) { + return TIME_POINT_MAX; + } + + auto lastValidEventTimePoint = TIME_POINT_MAX; + auto singleEventTimePoint = TIME_POINT_MAX; + auto rruleIter = RRuleIter(*this, eventStart); + do { + lastValidEventTimePoint = singleEventTimePoint; + singleEventTimePoint = rruleIter.next(); + + } while (singleEventTimePoint != TIME_POINT_INVALID); + + return lastValidEventTimePoint; + } + icalrecurrencetype RRuletoIcalRecurrenceType(const RRule &rrule) { icalrecurrencetype icalRrule = ICALRECURRENCETYPE_INITIALIZER; @@ -89,7 +152,7 @@ namespace rrule icalRrule.freq = RRuleFrequencyToIcalFrequency(rrule.freq); icalRrule.count = rrule.count; - if (rrule.until != TimePoint::min()) { + if (rrule.until != TIME_POINT_INVALID) { icalRrule.until = icaltime_from_timet_with_zone(std::chrono::system_clock::to_time_t(rrule.until), 0, NULL); } icalRrule.interval = rrule.interval; diff --git a/module-utils/rrule/rrule/rrule.hpp b/module-utils/rrule/rrule/rrule.hpp index 54dd3d95521be35de386a9fa13d414a12dc24681..bd4ff1b1eb6ba4afdcab3080c37ac5096aeb824f 100644 --- a/module-utils/rrule/rrule/rrule.hpp +++ b/module-utils/rrule/rrule/rrule.hpp @@ -1,16 +1,17 @@ // Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md -#include +#include