renamed 32bit durations, added ESP32 implementations in separate .cpp file

This commit is contained in:
2021-02-24 17:11:42 +01:00
parent 5ec358b30e
commit d3547a3323
7 changed files with 121 additions and 65 deletions

View File

@ -4,6 +4,7 @@ set(headers
set(sources set(sources
src/espchrono.cpp src/espchrono.cpp
src/espchrono_espimpl.cpp
) )
idf_component_register(INCLUDE_DIRS src SRCS ${headers} ${sources} REQUIRES freertos esp_system cpputils date espcpputils) idf_component_register(INCLUDE_DIRS src SRCS ${headers} ${sources} REQUIRES freertos esp_system cpputils date espcpputils)

View File

@ -66,6 +66,11 @@ bool daylightSavingTime(local_clock::time_point _timeStamp)
return (_tempDateTime.date.day() < 8_d && _tempDateTime.dayOfWeek == 1 && _tempDateTime.hour < 2); return (_tempDateTime.date.day() < 8_d && _tempDateTime.dayOfWeek == 1 && _tempDateTime.hour < 2);
} // end else } // end else
} }
} // namespace
auto local_clock::now() noexcept -> time_point
{
return utcToLocal(utc_clock::now());
} }
local_clock::time_point utcToLocal(utc_clock::time_point utc, time_zone timezone) local_clock::time_point utcToLocal(utc_clock::time_point utc, time_zone timezone)
@ -97,8 +102,13 @@ utc_clock::time_point localToUtc(local_clock::time_point local)
return utc; return utc;
} }
local_clock::time_point utcToLocal(utc_clock::time_point ts)
{
return utcToLocal(ts, local_clock::timezone());
}
namespace { namespace {
DateTime toDateTime(seconds ts) DateTime toDateTime(seconds32 ts)
{ {
auto _time = ts.count(); auto _time = ts.count();
@ -188,7 +198,7 @@ std::optional<DateTime> parseDateTime(std::string_view str)
}; };
} }
std::optional<seconds> parseDaypoint(std::string_view str) std::optional<seconds32> parseDaypoint(std::string_view str)
{ {
int8_t hour, minute, second{}; int8_t hour, minute, second{};
@ -199,7 +209,7 @@ std::optional<seconds> parseDaypoint(std::string_view str)
if (hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) if (hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59)
return std::nullopt; return std::nullopt;
return hours{hour} + minutes{minute} + seconds{second}; return hours32{hour} + minutes32{minute} + seconds32{second};
} }
std::string toString(const DateTime &dateTime) std::string toString(const DateTime &dateTime)
@ -217,7 +227,7 @@ std::string toString(const LocalDateTime &dateTime)
{ {
char buf[34]; char buf[34];
date::hh_mm_ss helper{dateTime.timezone.offset + hours{dateTime.dst ? 1 : 0}}; date::hh_mm_ss helper{dateTime.timezone.offset + hours32{dateTime.dst ? 1 : 0}};
std::sprintf(buf, "%04i-%02u-%02uT%02hhu:%02hhu:%02hhu %s%02hhu:%02hhu", std::sprintf(buf, "%04i-%02u-%02uT%02hhu:%02hhu:%02hhu %s%02hhu:%02hhu",
int{dateTime.date.year()}, unsigned{dateTime.date.month()}, unsigned{dateTime.date.day()}, int{dateTime.date.year()}, unsigned{dateTime.date.month()}, unsigned{dateTime.date.day()},
@ -227,7 +237,7 @@ std::string toString(const LocalDateTime &dateTime)
return std::string{buf}; return std::string{buf};
} }
std::string toDaypointString(seconds seconds) std::string toDaypointString(seconds32 seconds)
{ {
date::hh_mm_ss helper(seconds); date::hh_mm_ss helper(seconds);
char buf[10]; char buf[10];
@ -235,15 +245,15 @@ std::string toDaypointString(seconds seconds)
return std::string{buf}; return std::string{buf};
} }
milliseconds ago(millis_clock::time_point a) std::chrono::milliseconds ago(millis_clock::time_point a)
{ {
return millis_clock::now() - a; return millis_clock::now() - a;
} }
std::string toString(milliseconds val) { return std::to_string(val.count()) + "ms"; } std::string toString(milliseconds32 val) { return std::to_string(val.count()) + "ms"; }
std::string toString(seconds val) { return std::to_string(val.count()) + "s"; } std::string toString(seconds32 val) { return std::to_string(val.count()) + "s"; }
std::string toString(minutes val) { return std::to_string(val.count()) + "min"; } std::string toString(minutes32 val) { return std::to_string(val.count()) + "min"; }
std::string toString(hours val) { return std::to_string(val.count()) + "h"; } std::string toString(hours32 val) { return std::to_string(val.count()) + "h"; }
IMPLEMENT_TYPESAFE_ENUM(DayLightSavingMode, : uint8_t, DayLightSavingModeValues) IMPLEMENT_TYPESAFE_ENUM(DayLightSavingMode, : uint8_t, DayLightSavingModeValues)

View File

@ -17,14 +17,14 @@
namespace espchrono { namespace espchrono {
using milliseconds = std::chrono::duration<long, std::milli>; using milliseconds32 = std::chrono::duration<int32_t, std::milli>;
using seconds = std::chrono::duration<long>; using seconds32 = std::chrono::duration<int32_t>;
using minutes = std::chrono::duration<long, std::ratio<60>>; using minutes32 = std::chrono::duration<int32_t, std::ratio<60>>;
using hours = std::chrono::duration<long, std::ratio<3600>>; using hours32 = std::chrono::duration<int32_t, std::ratio<3600>>;
struct utc_clock struct utc_clock
{ {
typedef seconds duration; typedef seconds32 duration;
typedef duration::rep rep; typedef duration::rep rep;
typedef duration::period period; typedef duration::period period;
typedef std::chrono::time_point<utc_clock, duration> time_point; typedef std::chrono::time_point<utc_clock, duration> time_point;
@ -45,7 +45,7 @@ DECLARE_TYPESAFE_ENUM(DayLightSavingMode, : uint8_t, DayLightSavingModeValues)
struct time_zone struct time_zone
{ {
minutes offset{}; minutes32 offset{};
DayLightSavingMode dayLightSavingMode{}; DayLightSavingMode dayLightSavingMode{};
bool operator== (const time_zone &other) const bool operator== (const time_zone &other) const
@ -100,7 +100,7 @@ public:
struct local_clock struct local_clock
{ {
typedef seconds duration; typedef seconds32 duration;
typedef duration::rep rep; typedef duration::rep rep;
typedef duration::period period; typedef duration::period period;
typedef local_time_point<local_clock, duration> time_point; typedef local_time_point<local_clock, duration> time_point;
@ -111,6 +111,8 @@ struct local_clock
static constexpr bool is_steady = false; static constexpr bool is_steady = false;
static time_point now() noexcept; static time_point now() noexcept;
static time_zone timezone() noexcept;
}; };
struct millis_clock struct millis_clock
@ -162,6 +164,8 @@ struct LocalDateTime : public DateTime
local_clock::time_point utcToLocal(utc_clock::time_point timeStamp, time_zone timezone); local_clock::time_point utcToLocal(utc_clock::time_point timeStamp, time_zone timezone);
utc_clock::time_point localToUtc(local_clock::time_point local); utc_clock::time_point localToUtc(local_clock::time_point local);
local_clock::time_point utcToLocal(utc_clock::time_point ts);
DateTime toDateTime(utc_clock::time_point ts); DateTime toDateTime(utc_clock::time_point ts);
LocalDateTime toDateTime(local_clock::time_point ts); LocalDateTime toDateTime(local_clock::time_point ts);
@ -169,18 +173,18 @@ LocalDateTime toDateTime(local_clock::time_point ts);
std::optional<DateTime> parseDateTime(std::string_view str); std::optional<DateTime> parseDateTime(std::string_view str);
//! Returns null if string cannot be parsed //! Returns null if string cannot be parsed
std::optional<seconds> parseDaypoint(std::string_view str); std::optional<seconds32> parseDaypoint(std::string_view str);
std::string toString(const DateTime &dateTime); std::string toString(const DateTime &dateTime);
std::string toString(const LocalDateTime &dateTime); std::string toString(const LocalDateTime &dateTime);
std::string toDaypointString(seconds seconds); std::string toDaypointString(seconds32 seconds);
milliseconds ago(millis_clock::time_point a); std::chrono::milliseconds ago(millis_clock::time_point a);
std::string toString(milliseconds val); std::string toString(milliseconds32 val);
std::string toString(seconds val); std::string toString(seconds32 val);
std::string toString(minutes val); std::string toString(minutes32 val);
std::string toString(hours val); std::string toString(hours32 val);
} // namespace espchrono } // namespace espchrono

27
src/espchrono_espimpl.cpp Normal file
View File

@ -0,0 +1,27 @@
// local includes
#include "espchrono.h"
// system includes
#include <time.h>
// esp-idf inlcludes
#include <esp_timer.h>
using namespace std::chrono_literals;
// actual implementations used on the ESP32
namespace espchrono {
auto utc_clock::now() noexcept -> time_point
{
timeval tv;
gettimeofday(&tv, NULL);
seconds32 seconds{tv.tv_sec};
return time_point{seconds};
}
auto millis_clock::now() noexcept -> time_point
{
return time_point{std::chrono::floor<duration>(std::chrono::microseconds{esp_timer_get_time()})};
}
} // namespace espchrono

View File

@ -5,7 +5,8 @@ using namespace date;
const espchrono::time_zone testTimeZone{.offset=60min, .dayLightSavingMode=espchrono::DayLightSavingMode::EuropeanSummerTime}; const espchrono::time_zone testTimeZone{.offset=60min, .dayLightSavingMode=espchrono::DayLightSavingMode::EuropeanSummerTime};
espchrono::millis_clock::time_point wallClock{}; espchrono::millis_clock::time_point mockedMillisClock{};
espchrono::utc_clock::time_point mockedUtcClock{};
namespace QTest { namespace QTest {
template<> template<>
@ -33,13 +34,13 @@ char *toString(const espchrono::local_clock::time_point &ts)
} }
template<> template<>
char *toString(const espchrono::seconds &val) char *toString(const espchrono::seconds32 &val)
{ {
return ::QTest::toString(espchrono::toDaypointString(val)); return ::QTest::toString(espchrono::toDaypointString(val));
} }
template<> template<>
char *toString(const std::optional<espchrono::seconds> &val) char *toString(const std::optional<espchrono::seconds32> &val)
{ {
return val ? ::QTest::toString(*val) : ::QTest::toString("(invalid)"); return val ? ::QTest::toString(*val) : ::QTest::toString("(invalid)");
} }
@ -48,5 +49,13 @@ char *toString(const std::optional<espchrono::seconds> &val)
// stub implementation to make unit tests happy // stub implementation to make unit tests happy
auto espchrono::millis_clock::now() noexcept -> time_point auto espchrono::millis_clock::now() noexcept -> time_point
{ {
return wallClock; return mockedMillisClock;
}
auto espchrono::utc_clock::now() noexcept -> time_point
{
return mockedUtcClock;
}
auto espchrono::local_clock::timezone() noexcept -> time_zone
{
return testTimeZone;
} }

View File

@ -11,23 +11,28 @@
#include "espchrono.h" #include "espchrono.h"
#include "cpputilstestutils.h" #include "cpputilstestutils.h"
Q_DECLARE_METATYPE(espchrono::milliseconds) Q_DECLARE_METATYPE(std::chrono::milliseconds)
Q_DECLARE_METATYPE(espchrono::seconds) Q_DECLARE_METATYPE(std::chrono::seconds)
Q_DECLARE_METATYPE(espchrono::minutes) Q_DECLARE_METATYPE(std::chrono::minutes)
Q_DECLARE_METATYPE(espchrono::hours) Q_DECLARE_METATYPE(std::chrono::hours)
Q_DECLARE_METATYPE(espchrono::milliseconds32)
Q_DECLARE_METATYPE(espchrono::seconds32)
Q_DECLARE_METATYPE(espchrono::minutes32)
Q_DECLARE_METATYPE(espchrono::hours32)
Q_DECLARE_METATYPE(espchrono::utc_clock::time_point) Q_DECLARE_METATYPE(espchrono::utc_clock::time_point)
Q_DECLARE_METATYPE(espchrono::local_clock::time_point) Q_DECLARE_METATYPE(espchrono::local_clock::time_point)
Q_DECLARE_METATYPE(espchrono::DateTime) Q_DECLARE_METATYPE(espchrono::DateTime)
Q_DECLARE_METATYPE(espchrono::LocalDateTime) Q_DECLARE_METATYPE(espchrono::LocalDateTime)
Q_DECLARE_METATYPE(std::optional<espchrono::seconds>) Q_DECLARE_METATYPE(std::optional<espchrono::seconds32>)
extern const espchrono::time_zone testTimeZone; extern const espchrono::time_zone testTimeZone;
extern espchrono::millis_clock::time_point wallClock; extern espchrono::millis_clock::time_point mockedMillisClock;
extern espchrono::utc_clock::time_point mockedUtcClock;
namespace { namespace {
template<typename T> template<typename T>
espchrono::local_clock::time_point makeLocal(T day, espchrono::minutes time) espchrono::local_clock::time_point makeLocal(T day, espchrono::minutes32 time)
{ {
espchrono::local_clock::time_point localTime{date::sys_days{day}.time_since_epoch(), testTimeZone, false}; espchrono::local_clock::time_point localTime{date::sys_days{day}.time_since_epoch(), testTimeZone, false};
localTime += time; localTime += time;
@ -35,7 +40,7 @@ espchrono::local_clock::time_point makeLocal(T day, espchrono::minutes time)
} }
template<typename T> template<typename T>
espchrono::utc_clock::time_point makeUtcFromLocal(T day, espchrono::minutes time) espchrono::utc_clock::time_point makeUtcFromLocal(T day, espchrono::minutes32 time)
{ {
const auto localTime = makeLocal(day, time); const auto localTime = makeLocal(day, time);
return espchrono::localToUtc(localTime); return espchrono::localToUtc(localTime);
@ -56,8 +61,8 @@ template<>
char *toString(const espchrono::local_clock::time_point &ts); char *toString(const espchrono::local_clock::time_point &ts);
template<> template<>
char *toString(const espchrono::seconds &val); char *toString(const espchrono::seconds32 &val);
template<> template<>
char *toString(const std::optional<espchrono::seconds> &val); char *toString(const std::optional<espchrono::seconds32> &val);
} // namespace QTest } // namespace QTest

View File

@ -139,20 +139,20 @@ private slots:
QTest::addColumn<espchrono::utc_clock::time_point>("time_point"); QTest::addColumn<espchrono::utc_clock::time_point>("time_point");
QTest::addColumn<espchrono::DateTime>("expected"); QTest::addColumn<espchrono::DateTime>("expected");
QTest::addRow("random") << espchrono::utc_clock::time_point{espchrono::seconds{123456}} << espchrono::DateTime{ QTest::addRow("random") << espchrono::utc_clock::time_point{123456s} << espchrono::DateTime{
2_d/January/1970, 2_d/January/1970,
.hour=10, .minute=17, .second=36, .hour=10, .minute=17, .second=36,
.dayOfWeek=espchrono::DateTime::DayOfWeek::Friday .dayOfWeek=espchrono::DateTime::DayOfWeek::Friday
}; };
QTest::addRow("leap_year") << espchrono::utc_clock::time_point{espchrono::seconds{1582934400}} QTest::addRow("leap_year") << espchrono::utc_clock::time_point{1582934400s}
<< espchrono::DateTime{ << espchrono::DateTime{
29_d/February/2020, 29_d/February/2020,
.hour=0, .minute=0, .second=0, .hour=0, .minute=0, .second=0,
.dayOfWeek=espchrono::DateTime::DayOfWeek::Saturday .dayOfWeek=espchrono::DateTime::DayOfWeek::Saturday
}; };
QTest::addRow("normal_year") << espchrono::utc_clock::time_point{espchrono::seconds{1614556800}} QTest::addRow("normal_year") << espchrono::utc_clock::time_point{1614556800s}
<< espchrono::DateTime{ << espchrono::DateTime{
1_d/March/2021, 1_d/March/2021,
.hour=0, .minute=0, .second=0, .hour=0, .minute=0, .second=0,
@ -173,7 +173,7 @@ private slots:
QTest::addColumn<espchrono::local_clock::time_point>("time_point"); QTest::addColumn<espchrono::local_clock::time_point>("time_point");
QTest::addColumn<espchrono::LocalDateTime>("expected"); QTest::addColumn<espchrono::LocalDateTime>("expected");
QTest::addRow("no_dst") << espchrono::local_clock::time_point(espchrono::seconds{123456}, testTimeZone, false) QTest::addRow("no_dst") << espchrono::local_clock::time_point(123456s, testTimeZone, false)
<< espchrono::LocalDateTime{ << espchrono::LocalDateTime{
espchrono::DateTime{ espchrono::DateTime{
2_d/January/1970, 2_d/January/1970,
@ -183,7 +183,7 @@ private slots:
.timezone = testTimeZone, .timezone = testTimeZone,
.dst = false .dst = false
}; };
QTest::addRow("with_dst") << espchrono::local_clock::time_point(espchrono::seconds{123456}, testTimeZone, true) QTest::addRow("with_dst") << espchrono::local_clock::time_point(123456s, testTimeZone, true)
<< espchrono::LocalDateTime{ << espchrono::LocalDateTime{
espchrono::DateTime{ espchrono::DateTime{
2_d/January/1970, 2_d/January/1970,
@ -205,22 +205,22 @@ private slots:
void test_toDaypointString_data() void test_toDaypointString_data()
{ {
QTest::addColumn<espchrono::seconds>("input"); QTest::addColumn<espchrono::seconds32>("input");
QTest::addColumn<std::string>("expected"); QTest::addColumn<std::string>("expected");
QTest::addRow("00:00:00") << espchrono::seconds{} << "00:00:00"s; QTest::addRow("00:00:00") << espchrono::seconds32{} << "00:00:00"s;
QTest::addRow("05:00:00") << espchrono::seconds{5h} << "05:00:00"s; QTest::addRow("05:00:00") << espchrono::seconds32{5h} << "05:00:00"s;
QTest::addRow("05:04:00") << espchrono::seconds{5h+4min} << "05:04:00"s; QTest::addRow("05:04:00") << espchrono::seconds32{5h+4min} << "05:04:00"s;
QTest::addRow("05:04:03") << espchrono::seconds{5h+4min+3s} << "05:04:03"s; QTest::addRow("05:04:03") << espchrono::seconds32{5h+4min+3s} << "05:04:03"s;
QTest::addRow("05:00:03") << espchrono::seconds{5h+3s} << "05:00:03"s; QTest::addRow("05:00:03") << espchrono::seconds32{5h+3s} << "05:00:03"s;
QTest::addRow("23:59:59") << espchrono::seconds{23h+59min+59s} << "23:59:59"s; QTest::addRow("23:59:59") << espchrono::seconds32{23h+59min+59s} << "23:59:59"s;
QTest::addRow("-23:59:59") << espchrono::seconds{-23h-59min-59s} << "-23:59:59"s; QTest::addRow("-23:59:59") << espchrono::seconds32{-23h-59min-59s} << "-23:59:59"s;
QTest::addRow("-00:59:59") << espchrono::seconds{-59min-59s} << "-00:59:59"s; QTest::addRow("-00:59:59") << espchrono::seconds32{-59min-59s} << "-00:59:59"s;
} }
void test_toDaypointString() void test_toDaypointString()
{ {
QFETCH(espchrono::seconds, input); QFETCH(espchrono::seconds32, input);
QFETCH(std::string, expected); QFETCH(std::string, expected);
FIXEDCOMPARE(espchrono::toDaypointString(input), expected); FIXEDCOMPARE(espchrono::toDaypointString(input), expected);
} }
@ -228,22 +228,22 @@ private slots:
void test_parseDaypoint_data() void test_parseDaypoint_data()
{ {
QTest::addColumn<std::string>("input"); QTest::addColumn<std::string>("input");
QTest::addColumn<std::optional<espchrono::seconds>>("expected"); QTest::addColumn<std::optional<espchrono::seconds32>>("expected");
QTest::addRow("bullshit") << "bullshit"s << std::optional<espchrono::seconds>{}; QTest::addRow("bullshit") << "bullshit"s << std::optional<espchrono::seconds32>{};
QTest::addRow("missing_minute") << "00:"s << std::optional<espchrono::seconds>{}; QTest::addRow("missing_minute") << "00:"s << std::optional<espchrono::seconds32>{};
QTest::addRow("zero") << "00:00"s << std::optional<espchrono::seconds>{0s}; QTest::addRow("zero") << "00:00"s << std::optional<espchrono::seconds32>{0s};
QTest::addRow("zero3") << "00:00:00"s << std::optional<espchrono::seconds>{0s}; QTest::addRow("zero3") << "00:00:00"s << std::optional<espchrono::seconds32>{0s};
QTest::addRow("random") << "12:34:56"s << std::optional<espchrono::seconds>{12h+34min+56s}; QTest::addRow("random") << "12:34:56"s << std::optional<espchrono::seconds32>{12h+34min+56s};
QTest::addRow("random2") << "12:34"s << std::optional<espchrono::seconds>{12h+34min}; QTest::addRow("random2") << "12:34"s << std::optional<espchrono::seconds32>{12h+34min};
// QTest::addRow("negative") << "-12:34:56"s << std::optional<espchrono::seconds>{-12h-34min-56s}; // QTest::addRow("negative") << "-12:34:56"s << std::optional<espchrono::seconds32>{-12h-34min-56s};
// QTest::addRow("negative_leading_zero") << "-00:34:56"s << std::optional<espchrono::seconds>{-34min-56s}; // QTest::addRow("negative_leading_zero") << "-00:34:56"s << std::optional<espchrono::seconds32>{-34min-56s};
} }
void test_parseDaypoint() void test_parseDaypoint()
{ {
QFETCH(std::string, input); QFETCH(std::string, input);
QFETCH(std::optional<espchrono::seconds>, expected); QFETCH(std::optional<espchrono::seconds32>, expected);
FIXEDCOMPARE(espchrono::parseDaypoint(input), expected); FIXEDCOMPARE(espchrono::parseDaypoint(input), expected);
} }
@ -286,7 +286,7 @@ private slots:
void test_compareLocalTimepoints() void test_compareLocalTimepoints()
{ {
espchrono::local_clock::time_point a { espchrono::local_clock::time_point a {
espchrono::seconds{10}, 10s,
espchrono::time_zone{ espchrono::time_zone{
.offset = 1h, .offset = 1h,
.dayLightSavingMode = espchrono::DayLightSavingMode::EuropeanSummerTime .dayLightSavingMode = espchrono::DayLightSavingMode::EuropeanSummerTime
@ -294,7 +294,7 @@ private slots:
false false
}; };
espchrono::local_clock::time_point b { espchrono::local_clock::time_point b {
espchrono::seconds{10}, 10s,
espchrono::time_zone{ espchrono::time_zone{
.offset = 1h, .offset = 1h,
.dayLightSavingMode = espchrono::DayLightSavingMode::EuropeanSummerTime .dayLightSavingMode = espchrono::DayLightSavingMode::EuropeanSummerTime