Part of calculation

This commit is contained in:
Per Malmberg 2018-03-09 07:35:11 -08:00
parent a6dd20d150
commit 22da55666a
9 changed files with 175 additions and 28 deletions

View File

@ -8,4 +8,11 @@ include_directories(externals/date)
add_library(${PROJECT_NAME}
Cron.h
Cron.cpp Task.h CronData.h TimeTypes.h CronData.cpp)
Cron.cpp
Task.h
CronData.h
TimeTypes.h
CronData.cpp
CronSchedule.cpp
CronSchedule.h
externals/date/date.h DateTime.h)

View File

@ -7,7 +7,7 @@ bool libcron::Cron::add_schedule(const std::string &schedule, std::function<void
bool res = cron.is_valid();
if (res)
{
items.emplace(Task(cron, std::move(work)));
items.emplace(Task(CronSchedule(cron), std::move(work)));
}
return res;

View File

@ -1,11 +1,10 @@
#pragma once
#include <set>
#include "TimeTypes.h"
#include <regex>
#include <chrono>
#include <string>
#include <vector>
#include "TimeTypes.h"
namespace libcron
{
@ -96,6 +95,12 @@ namespace libcron
return day_of_week;
}
template<typename T>
static uint8_t value_of(T t)
{
return static_cast<uint8_t>(t);
}
private:
void parse(const std::string& cron_expression);
@ -123,12 +128,6 @@ namespace libcron
template<typename T>
bool get_step(const std::string& s, uint8_t& start, uint8_t& step);
template<typename T>
uint8_t value_of(T t)
{
return static_cast<uint8_t>(t);
}
std::vector<std::string> split(const std::string& s, char token);
bool is_number(const std::string& s);

61
libcron/CronSchedule.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "CronSchedule.h"
using namespace std::chrono;
using namespace date;
namespace libcron
{
std::chrono::system_clock::time_point
CronSchedule::calculate_from(const std::chrono::system_clock::time_point& from)
{
auto curr = from;
year_month_day ymd = date::floor<days>(curr);
// Add months until one of the allowed days are found, or stay at the current one.
while (data.get_months().find(static_cast<Months>(unsigned(ymd.month()))) == data.get_months().end())
{
curr += months{1};
ymd = date::floor<days>(curr);
};
// If all days are allowed, then the 'day of week' takes precedence, which also means that
// day of week only is ignored when specific days of months are specified.
if (data.get_day_of_month().size() != CronData::value_of(DayOfMonth::Last))
{
// Add days until one of the allowed days are found, or stay at the current one.
while (data.get_day_of_month().find(static_cast<DayOfMonth>(unsigned(ymd.day()))) ==
data.get_day_of_month().end())
{
curr += days{1};
ymd = date::floor<days>(curr);
};
}
else
{
//Add days until the current weekday is one of the allowed weekdays
year_month_weekday ymw = date::floor<days>(curr);
while (data.get_day_of_week().find(static_cast<DayOfWeek>(unsigned(ymw.weekday()))) ==
data.get_day_of_week().end())
{
curr += days{1};
ymw = date::floor<days>(curr);
};
}
// 'curr' now represents the next year, month and day matching the expression, with a time of 0:0:0.
// Re-add the hours, minutes and seconds to 'curr'
auto date_time = to_calendar_time(from);
curr += hours{date_time.hour};
curr += minutes{date_time.min};
curr += seconds{date_time.sec};
auto t = to_calendar_time(from);
return curr;
}
}

44
libcron/CronSchedule.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include "CronData.h"
#include <chrono>
#include "externals/date/date.h"
#include "DateTime.h"
namespace libcron
{
class CronSchedule
{
public:
explicit CronSchedule(CronData data)
: data(std::move(data))
{
}
std::chrono::system_clock::time_point calculate_from(const std::chrono::system_clock::time_point& from);
// https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes#obtaining-ymd-hms-components-from-a-time_point
static DateTime to_calendar_time(std::chrono::system_clock::time_point time)
{
auto daypoint = date::floor<date::days>(time);
auto ymd = date::year_month_day(daypoint); // calendar date
auto tod = date::make_time(time - daypoint); // Yields time_of_day type
// Obtain individual components as integers
DateTime dt{
int(ymd.year()),
unsigned(ymd.month()),
unsigned(ymd.day()),
static_cast<uint8_t>(tod.hours().count()),
static_cast<uint8_t>(tod.minutes().count()),
static_cast<uint8_t>(tod.seconds().count())};
return dt;
}
private:
CronData data;
};
}

16
libcron/DateTime.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <cstdint>
namespace libcron
{
struct DateTime
{
int year = 0;
unsigned month = 0;
unsigned day = 0;
uint8_t hour = 0;
uint8_t min = 0;
uint8_t sec = 0;
};
}

View File

@ -2,25 +2,30 @@
#include <functional>
#include "CronData.h"
#include "CronSchedule.h"
namespace libcron
{
class Task
{
public:
public:
Task(CronData time, std::function<void()> task)
: time(std::move(time)), task(std::move(task))
{
}
Task(CronSchedule schedule, std::function<void()> task)
: schedule(std::move(schedule))//, task(std::move(task))
{
}
bool operator<(const Task& other) const
{
return false;
}
Task(const Task&) = default;
private:
CronData time{};
std::function<void()> task;
Task& operator=(const Task&) = default;
bool operator<(const Task& other) const
{
return false;
}
private:
CronSchedule schedule;
//std::function<void()> task;
};
}

View File

@ -7,6 +7,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wpedantic -fsanitize=address -las
include_directories(
externals/Catch2/single_include/
..
../libcron/externals/date
)
add_executable(

View File

@ -1,11 +1,13 @@
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include <catch.hpp>
#include <date.h>
#include <libcron/Cron.h>
#include <libcron/CronData.h>
using namespace libcron;
using namespace date;
using namespace std::chrono;
template<typename T>
bool has_value_range(const std::set<T>& set, uint8_t low, uint8_t high)
@ -231,18 +233,30 @@ SCENARIO("Calculating next runtime")
{
auto c = CronData::create("0 0 * * * *");
REQUIRE(c.is_valid());
CronSchedule sched(c);
WHEN("Start time is midnight")
{
// std::chrono::system_clock::time_point run_time = c.calculate_from(midnight);
// THEN("Next runtime is 01:00")
// {
// auto t = std::chrono::system_clock::to_time_t(run_time);
sys_days midnight = 2010_y/1/1;
std::chrono::system_clock::time_point run_time = sched.calculate_from(midnight);
THEN("Next runtime is 01:00 of the same date")
{
auto t = CronSchedule::to_calendar_time(run_time);
REQUIRE(t.year == 2010);
REQUIRE(t.month == 1);
REQUIRE(t.day == 1);
REQUIRE(t.hour == 1);
REQUIRE(t.min == 0);
REQUIRE(t.sec == 0);
// auto t = std::chrono::system_clock::to_time_t(run_time);
// REQUIRE(t.get_seconds() == 0);
// REQUIRE(t.minute == 0);
// REQUIRE(t.hour == 1);
// REQUIRE(t.)
// }
}
}