Added UTC handling for Windows

This commit is contained in:
Per Malmberg 2018-03-22 22:38:55 +01:00
parent 5395c75061
commit c441da4287
7 changed files with 80 additions and 27 deletions

View File

@ -2,7 +2,12 @@ cmake_minimum_required(VERSION 3.6)
project(libcron) project(libcron)
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
if( MSVC )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
endif()
include_directories(${CMAKE_CURRENT_LIST_DIR}/externals/date/include) include_directories(${CMAKE_CURRENT_LIST_DIR}/externals/date/include)
@ -16,7 +21,8 @@ add_library(${PROJECT_NAME}
CronSchedule.h CronSchedule.h
DateTime.h DateTime.h
Task.cpp Task.cpp
CronClock.h) CronClock.h
CronClock.cpp)
set_target_properties(${PROJECT_NAME} PROPERTIES set_target_properties(${PROJECT_NAME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${OUTPUT_LOCATION}" ARCHIVE_OUTPUT_DIRECTORY "${OUTPUT_LOCATION}"

View File

@ -45,6 +45,8 @@ namespace libcron
return clock; return clock;
} }
void get_time_until_expiry_for_tasks(std::vector<std::tuple<std::string, std::chrono::system_clock::duration>>& status) const;
friend std::ostream& operator<<<>(std::ostream& stream, const Cron<ClockType>& c); friend std::ostream& operator<<<>(std::ostream& stream, const Cron<ClockType>& c);
private: private:
@ -78,7 +80,6 @@ namespace libcron
bool res = cron.is_valid(); bool res = cron.is_valid();
if (res) if (res)
{ {
Task t{std::move(name), CronSchedule{cron}, std::move(work)}; Task t{std::move(name), CronSchedule{cron}, std::move(work)};
if (t.calculate_next(clock.now())) if (t.calculate_next(clock.now()))
{ {
@ -106,7 +107,7 @@ namespace libcron
} }
template<typename ClockType> template<typename ClockType>
size_t Cron<ClockType>::tick(system_clock::time_point now) size_t Cron<ClockType>::tick(std::chrono::system_clock::time_point now)
{ {
size_t res = 0; size_t res = 0;
@ -160,6 +161,19 @@ namespace libcron
return res; return res;
} }
template<typename ClockType>
void Cron<ClockType>::get_time_until_expiry_for_tasks(std::vector<std::tuple<std::string, std::chrono::system_clock::duration>>& status) const
{
auto now = clock.now();
status.clear();
std::for_each(tasks.get_tasks().cbegin(), tasks.get_tasks().cend(),
[&status, &now](const Task& t)
{
status.emplace_back(t.get_name(), t.time_until_expiry(now));
});
}
template<typename ClockType> template<typename ClockType>
std::ostream& operator<<(std::ostream& stream, const Cron<ClockType>& c) std::ostream& operator<<(std::ostream& stream, const Cron<ClockType>& c)
{ {

39
libcron/CronClock.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "CronClock.h"
#ifdef WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#endif
using namespace std::chrono;
namespace libcron
{
std::chrono::seconds LocalClock::utc_offset(std::chrono::system_clock::time_point now) const
{
#ifdef WIN32
(void)now;
TIME_ZONE_INFORMATION tz_info{};
seconds offset{ 0 };
auto res = GetTimeZoneInformation(&tz_info);
if (res != TIME_ZONE_ID_INVALID)
{
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
// UTC = local time + bias => local_time = utc - bias, so UTC offset is -bias
offset = minutes{ -tz_info.Bias };
}
#else
auto t = system_clock::to_time_t(now);
tm tm{};
localtime_r(&t, &tm);
seconds offset{ tm.tm_gmtoff };
#endif
return offset;
}
}

View File

@ -2,9 +2,6 @@
#include <chrono> #include <chrono>
using namespace std::chrono;
using namespace date;
namespace libcron namespace libcron
{ {
class ICronClock class ICronClock
@ -25,6 +22,7 @@ namespace libcron
std::chrono::seconds utc_offset(std::chrono::system_clock::time_point) const override std::chrono::seconds utc_offset(std::chrono::system_clock::time_point) const override
{ {
using namespace std::chrono;
return 0s; return 0s;
} }
}; };
@ -35,20 +33,10 @@ namespace libcron
public: public:
std::chrono::system_clock::time_point now() const override std::chrono::system_clock::time_point now() const override
{ {
auto now = system_clock::now(); auto now = std::chrono::system_clock::now();
return now + utc_offset(now); return now + utc_offset(now);
} }
std::chrono::seconds utc_offset(std::chrono::system_clock::time_point now) const override std::chrono::seconds utc_offset(std::chrono::system_clock::time_point now) const override;
{
auto t = system_clock::to_time_t(now);
tm tm{};
#ifdef __WIN32
localtime_s(&tm, &t);
#else
localtime_r(&t, &tm);
#endif
return seconds{tm.tm_gmtoff};
}
}; };
} }

View File

@ -1,4 +1,5 @@
#include "CronSchedule.h" #include "CronSchedule.h"
#include <tuple>
using namespace std::chrono; using namespace std::chrono;
using namespace date; using namespace date;

View File

@ -2,7 +2,12 @@ cmake_minimum_required(VERSION 3.6)
project(cron_test) project(cron_test)
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wpedantic -Wextra")
if( MSVC )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
endif()
include_directories( include_directories(
${CMAKE_CURRENT_LIST_DIR}/externals/Catch2/single_include/ ${CMAKE_CURRENT_LIST_DIR}/externals/Catch2/single_include/

View File

@ -5,6 +5,7 @@
using namespace libcron; using namespace libcron;
using namespace std::chrono; using namespace std::chrono;
using namespace date;
std::string create_schedule_expiring_in(std::chrono::system_clock::time_point now, hours h, minutes m, seconds s) std::string create_schedule_expiring_in(std::chrono::system_clock::time_point now, hours h, minutes m, seconds s)
{ {
@ -221,7 +222,7 @@ class TestClock
SCENARIO("Clock changes") SCENARIO("Clock changes")
{ {
GIVEN("A Cron instance with a single task expiring in 4h") GIVEN("A Cron instance with a single task expiring every hour")
{ {
Cron<TestClock> c{}; Cron<TestClock> c{};
auto& clock = c.get_clock(); auto& clock = c.get_clock();
@ -239,11 +240,11 @@ SCENARIO("Clock changes")
WHEN("Clock changes <3h forward") WHEN("Clock changes <3h forward")
{ {
THEN("Task expires accordingly") THEN("Task expires accordingly")
{ {
REQUIRE(c.tick() == 1); REQUIRE(c.tick() == 1);
clock.add(minutes{30}); // 00:30 clock.add(minutes{ 30 }); // 00:30
REQUIRE(c.tick() == 0); REQUIRE(c.tick() == 0);
clock.add(minutes{30}); // 01:00 clock.add(minutes{30}); // 01:00
REQUIRE(c.tick() == 1); REQUIRE(c.tick() == 1);
REQUIRE(c.tick() == 0); REQUIRE(c.tick() == 0);
@ -294,6 +295,5 @@ SCENARIO("Clock changes")
REQUIRE(c.tick() == 1); REQUIRE(c.tick() == 1);
} }
} }
} }
} }