| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 |
- #pragma once
- #include <chrono>
- #include <optional>
- #include <string>
- #include "common/error.hpp"
- namespace smartbotic::common {
- // A five-field cron expression: minute hour day-of-month month day-of-week.
- //
- // Supports the forms people actually write - "*", "5", "1,15", "2-6", "*/15",
- // "2-8/2" - and Sunday as either 0 or 7. Seconds are not a field: the scheduler
- // ticks in minutes, and offering a resolution it cannot honour would be a lie.
- //
- // This exists because the schedule-trigger node has offered a cron expression
- // and a timezone since it was written, and nothing ever read them. A workflow
- // set to "0 2 * * 1" ran every N minutes instead, and nothing said so.
- class CronSchedule {
- public:
- // Parses, or explains what is wrong with the expression. The message names
- // the offending field, because "invalid cron expression" tells somebody
- // staring at five numbers nothing they did not already know.
- static Result<CronSchedule> parse(const std::string& expression);
- // The first matching time strictly after `after`, in the named timezone.
- //
- // Returns nothing when the expression can never match - "30 4 31 2 *", the
- // 31st of February - rather than searching for ever. A schedule that cannot
- // fire is a mistake worth reporting, not a workflow that quietly never runs.
- //
- // An unknown timezone falls back to UTC and is reported by the caller; DST
- // is the standard library's problem, not this class's.
- std::optional<std::chrono::system_clock::time_point> nextAfter(
- std::chrono::system_clock::time_point after,
- const std::string& timezone) const;
- const std::string& expression() const { return expression_; }
- private:
- // One bit per possible value, so matching is a lookup rather than a search.
- bool minutes_[60] = {};
- bool hours_[24] = {};
- bool days_of_month_[32] = {}; // 1-31, index 0 unused
- bool months_[13] = {}; // 1-12, index 0 unused
- bool days_of_week_[7] = {}; // 0-6, Sunday is 0
- // Cron's day rule is an OR when both day fields are restricted, and an AND
- // when only one is - the historical behaviour every implementation copies.
- bool day_of_month_restricted_ = false;
- bool day_of_week_restricted_ = false;
- std::string expression_;
- };
- } // namespace smartbotic::common
|