OpenRGB/dependencies/hueplusplus-1.2.0/include/hueplusplus/TimePattern.h
2025-02-14 23:16:53 -06:00

436 lines
No EOL
17 KiB
C++

/**
\file TimePattern.h
Copyright Notice\n
Copyright (C) 2020 Jan Rogall - developer\n
This file is part of hueplusplus.
hueplusplus is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
hueplusplus is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with hueplusplus. If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef INCLUDE_HUEPLUSPLUS_TIME_PATTERN
#define INCLUDE_HUEPLUSPLUS_TIME_PATTERN
#include <chrono>
#include <string>
#include <cstddef>
namespace hueplusplus
{
//! \brief Namespace for time/date related classes and functions
namespace time
{
//! \brief Converts a time_point to a timestamp string
//! \param time Time to convert
//! \returns Date and time in the format
//! <code>YYYY-MM-DD</code><strong>T</strong><code>hh:mm:ss</code>.
//!
//! Returns the time in the local time zone.
//! \throws HueException when time could not be converted
std::string timepointToTimestamp(std::chrono::system_clock::time_point time);
//! \brief Converts a timestamp to a time_point
//! \param timestamp Timestamp from the local time zone in the format
//! <code>YYYY-MM-DD</code><strong>T</strong><code>hh:mm:ss</code>
//! \returns time_point of the local system clock
//! \throws std::invalid_argument when integer conversion fails
//! \throws HueException when time cannot be represented as time_point
std::chrono::system_clock::time_point parseTimestamp(const std::string& timestamp);
//! \brief Converts an UTC timestamp to a time_point
//! \param timestamp UTC Timestamp the format
//! <code>YYYY-MM-DD</code><strong>T</strong><code>hh:mm:ss</code>
//! \returns time_point of the local system clock
//! \throws std::invalid_argument when integer conversion fails
//! \throws HueException when time cannot be represented as time_point
std::chrono::system_clock::time_point parseUTCTimestamp(const std::string& timestamp);
//! \brief Converts duration to a time string
//! \param duration Duration or time of day to format. Must be less than 24 hours
//! \returns Duration string in the format <code>hh:mm:ss</code>
//! \throws HueException when \c duration longer than 24 hours.
std::string durationTo_hh_mm_ss(std::chrono::system_clock::duration duration);
//! \brief Converts time string to a duration
//! \param hourMinSec Time/duration in the format <code>hh:mm:ss</code>
//! \returns Duration (hours, minutes and seconds) from the string
//! \throws std::invalid_argument when integer conversion fails
std::chrono::system_clock::duration parseDuration(const std::string& hourMinSec);
//! \brief One-time, absolute time point
class AbsoluteTime
{
using clock = std::chrono::system_clock;
public:
//! \brief Create absolute time point
//! \param baseTime Absolute time point
explicit AbsoluteTime(clock::time_point baseTime);
//! \brief Get base time point
//!
//! Can be used for calculation with other system_clock time_points
clock::time_point getBaseTime() const;
//! \brief Get formatted string as expected by Hue API
//! \returns Timestamp in the format
//! <code>YYYY-MM-DD</code><strong>T</strong><code>hh:mm:ss</code> in local timezone
std::string toString() const;
//! \brief Parse AbsoluteTime from formatted string in local timezone
//! \param s Timestamp in the same format as returned by \ref toString()
//! \returns AbsoluteTime with base time and variation from \c s
static AbsoluteTime parse(const std::string& s);
//! \brief Parse AbsoluteTime from formatted UTC string
//! \param s Timestamp in the same format as returned by \ref toString()
//! \returns AbsoluteTime with base time and variation from \c s
static AbsoluteTime parseUTC(const std::string& s);
private:
clock::time_point base;
};
//! One-time, absolute time point with possible random variation
//!
//! Can be either used to represent a specific date and time,
//! or a date and time with a random variation.
class AbsoluteVariedTime : public AbsoluteTime
{
using clock = std::chrono::system_clock;
public:
//! \brief Create absolute time point
//! \param baseTime Absolute time point
//! \param variation Random variation, optional. When not zero, the time is randomly chosen between
//! <code>baseTime - variation</code> and <code>baseTime + variation</code>
explicit AbsoluteVariedTime(clock::time_point baseTime, clock::duration variation = std::chrono::seconds(0));
//! \brief Get random variation or zero
//!
//! The time can vary up to this amount in both directions.
clock::duration getRandomVariation() const;
//! \brief Get formatted string as expected by Hue API
//! \returns when variation is 0: Timestamp in the format
//! <code>YYYY-MM-DD</code><strong>T</strong><code>hh:mm:ss</code>
//! \returns when there is variation: Timestamp in the format
//! <code>YYYY-MM-DD</code><strong>T</strong><code>hh:mm:ss</code><strong>A</strong><code>hh:mm:ss</code>
//! with base time first, variation second
std::string toString() const;
//! \brief Parse AbsoluteTime from formatted string in local timezone
//! \param s Timestamp in the same format as returned by \ref toString()
//! \returns AbsoluteVariedTime with base time and variation from \c s
static AbsoluteVariedTime parse(const std::string& s);
private:
clock::duration variation;
};
//! \brief Any number of days of the week
//!
//! Can be used to represent weekly repetitions only on certain days.
class Weekdays
{
public:
//! \brief Create with no days
Weekdays() : bitmask(0) { }
//! \brief Create with the day \c num
//! \param num Day of the week, from monday (0) to sunday (6)
explicit Weekdays(int num) : bitmask(1 << num) { }
//! \brief Check if no days are set
bool isNone() const;
//! \brief Check if all days are set
bool isAll() const;
//! \brief Check if Monday is contained
bool isMonday() const;
//! \brief Check if Tuesday is contained
bool isTuesday() const;
//! \brief Check if Wednesday is contained
bool isWednesday() const;
//! \brief Check if Thursday is contained
bool isThursday() const;
//! \brief Check if Friday is contained
bool isFriday() const;
//! \brief Check if Saturday is contained
bool isSaturday() const;
//! \brief Check if Sunday is contained
bool isSunday() const;
//! \brief Create set union with other Weekdays
//! \param other Second set of days to combine with
//! \returns A set of days containing all days of either \c this or \c other
Weekdays unionWith(Weekdays other) const;
//! \brief Create set union with other Weekdays
//! \see unionWith
Weekdays operator|(Weekdays other) const { return unionWith(other); }
//! \brief Create a formatted, numeric string
//! \returns A three digit code for the days as a bitmask
std::string toString() const;
//! \brief Creates an empty Weekdays
static Weekdays none();
//! \brief Creates set of all days
static Weekdays all();
//! \brief Creates Monday
static Weekdays monday();
//! \brief Creates Tuesday
static Weekdays tuesday();
//! \brief Creates Wednesday
static Weekdays wednesday();
//! \brief Creates Thursday
static Weekdays thursday();
//! \brief Creates Friday
static Weekdays friday();
//! \brief Creates Saturday
static Weekdays saturday();
//! \brief Creates Sunday
static Weekdays sunday();
//! \brief Parse from three digit code
//! \param s Bitmask of days as a string
//! \returns Parsed set of weekdays
static Weekdays parse(const std::string& s);
//! \brief Check whether all days are equal
bool operator==(const Weekdays& other) const { return bitmask == other.bitmask; }
//! \brief Check whether not all days are equal
bool operator!=(const Weekdays& other) const { return bitmask != other.bitmask; }
private:
int bitmask;
};
//! \brief Time repeated weekly to daily, with possible random variation.
//!
//! Can be used to represent a time on one or multiple days per week.
//! It can also have a random variation of up to 12 hours.
class RecurringTime
{
using clock = std::chrono::system_clock;
public:
//! \brief Create recurring time
//! \param daytime Time of day, duration from the start of the day.
//! \param days Days to repeat on, should not be Weekdays::none()
//! \param variation Random variation, optional. Must be less than 12 hours. When not zero, the time is randomly
//! chosen between <code>daytime - variation</code> and <code>daytime + variation</code>
explicit RecurringTime(clock::duration daytime, Weekdays days, clock::duration variation = std::chrono::seconds(0));
//! \brief Get time of day
clock::duration getDaytime() const;
//! \brief Get random variation
//!
//! The time can vary up to this amount in both directions.
clock::duration getRandomVariation() const;
//! \brief Get days on which the repetition will happen
Weekdays getWeekdays() const;
//! \brief Get formatted string as expected by Hue API
//! \returns with no variation:
//! <strong>W</strong><code>bbb</code><strong>/T</strong><code>hh:mm:ss</code>
//! \returns with variation:
//! <strong>W</strong><code>bbb</code><strong>/T</strong><code>hh:mm:ss</code><strong>A</strong><code>hh:mm:ss</code>,
//! where daytime is first and variation is second.
std::string toString() const;
private:
clock::duration time;
clock::duration variation;
Weekdays days;
};
//! \brief Time interval repeated daily to weekly.
//!
//! Can be used to represent an interval of time on one or multiple days per week.
//! The maximum interval length is 23 hours.
class TimeInterval
{
using clock = std::chrono::system_clock;
public:
//! \brief Create time interval
//! \param start Start time, duration from the start of the day
//! \param end End time, duration from the start of the day
//! \param days Active days, optional. Defaults to daily repetition.
TimeInterval(clock::duration start, clock::duration end, Weekdays days = Weekdays::all());
//! \brief Get start time of the interval
clock::duration getStartTime() const;
//! \brief Get end time of the interval
clock::duration getEndTime() const;
//! \brief Get active days
Weekdays getWeekdays() const;
//! \brief Get formatted string as expected by Hue API
//! \returns with daily repetition:
//! <strong>T</strong><code>hh:mm:ss</code><strong>/T</strong><code>hh:mm:ss</code>,
//! with start time first and end time second.
//! \returns with repetition that is not daily:
//! <strong>W</strong><code>bbb</code><strong>/T</strong><code>hh:mm:ss</code><strong>/T</strong><code>hh:mm:ss</code>
std::string toString() const;
private:
clock::duration start;
clock::duration end;
Weekdays days;
};
//! \brief Timer that is started and triggers after specified delay
//!
//! The timer can have a random variation in the expiry time.
//! It can be one-off, repeated a set number of times or repeated indefinitely.
class Timer
{
using clock = std::chrono::system_clock;
public:
// \brief Used to represent infinite repetitions
static constexpr int infiniteExecutions = 0;
//! \brief Create one-off timer
//! \param duration Expiry time of the timer, max 24 hours.
//! \param variation Random variation of expiry time, optional.
Timer(clock::duration duration, clock::duration variation = std::chrono::seconds(0));
//! \brief Create a repeated timer.
//! \param duration Expiry time of the timer, max 24 hours.
//! \param numExecutions Number of executions, 1 or higher, or \ref infiniteExecutions to always repeat.
//! \param variation Random variation of expiry time, optional.
Timer(clock::duration duration, int numExecutions, clock::duration variation = std::chrono::seconds(0));
//! \brief Returns true when the timer is executed more than once
bool isRecurring() const;
//! \brief Get number of executions
//! \returns Number of executions, or \ref infiniteExecutions
int getNumberOfExecutions() const;
//! \brief Get expiry time
clock::duration getExpiryTime() const;
//! \brief Get random variation of expiry time
//!
//! The expiry time can vary up to this value in both directions.
clock::duration getRandomVariation() const;
//! \brief Get formatted string as expected by Hue API
//! \returns one-off timer: <strong>PT</strong><code>hh:mm:ss</code>
//! \returns one-off timer with variation:
//! <strong>PT</strong><code>hh:mm:ss</code><strong>A</strong><code>hh:mm:ss</code>,
//! with expiry time first and variation second.
//! \returns recurring timer: <strong>R/PT</strong><code>hh:mm:ss</code>
//! \returns recurring timer with n repetitions:
//! <strong>R</strong><code>nn</code><strong>/PT</strong><code>hh:mm:ss</code>
//! \returns recurring timer with random variation:
//! <strong>R</strong><code>nn</code><strong>/PT</strong><code>hh:mm:ss</code><strong>A</strong><code>hh:mm:ss</code>
//! \returns infinite recurring timer with random variation:
//! <strong>R</strong><strong>/PT</strong><code>hh:mm:ss</code><strong>A</strong><code>hh:mm:ss</code>
std::string toString() const;
private:
clock::duration expires;
clock::duration variation;
int numExecutions;
};
//! \brief Holds different time representations
//!
//! Holds either AbsoluteTime, RecurringTime, TimeInterval, Timer or an undefined state.
//! TimePattern is used to specify the occurrance of Schedule%s.
class TimePattern
{
public:
//! \brief Currently active type
enum class Type
{
undefined, //!< \brief No active type
absolute, //!< \brief Active type is AbsoluteVariedTime
recurring, //!< \brief Active type is RecurringTime
interval, //!< \brief Active type is TimeInterval
timer //!< \brief Active type is Timer
};
//! \brief Create empty TimePattern
TimePattern();
//! \brief Destructor for union.
~TimePattern();
//! \brief Create TimePattern from AbsoluteVariedTime
explicit TimePattern(const AbsoluteVariedTime& absolute);
//! \brief Create TimePattern from RecurringTime
explicit TimePattern(const RecurringTime& recurring);
//! \brief Create TimePattern from TimeInterval
explicit TimePattern(const TimeInterval& interval);
//! \brief Create TimePattern from Timer
explicit TimePattern(const Timer& timer);
//! \brief Copy constructor for union
TimePattern(const TimePattern& other);
//! \brief Copy assignment for union
TimePattern& operator=(const TimePattern& other);
//! \brief Get currently active type
//! \note Only the currently active type may be accessed,
//! anything else is undefined behavior.
Type getType() const;
//! \brief Get contained absolute time
//! \pre getType() == Type::absolute
AbsoluteVariedTime asAbsolute() const;
//! \brief Get contained recurring time
//! \pre getType() == Type::recurring
RecurringTime asRecurring() const;
//! \brief Get contained time interval
//! \pre getType() == Type::interval
TimeInterval asInterval() const;
//! \brief Get contained timer
//! \pre getType() == Type::timer
Timer asTimer() const;
//! \brief Get formatted string of the contained value as expected by Hue API
//! \returns Empty string when type is undefined, otherwise toString() of the active type.
//! \see AbsoluteTime::toString, RecurringTime::toString, TimeInterval::toString, Timer::toString
std::string toString() const;
//! \brief Parses TimePattern from formatted string as returned by Hue API
//! \param s Empty string, "none", or in one of the formats the contained types
//! return in their toString() method.
//! \returns TimePattern with the matching type that is given in \c s
//! \see AbsoluteTime::toString, RecurringTime::toString, TimeInterval::toString, Timer::toString
//! \throws HueException when the format does not match or a parsing error occurs
//! \throws std::invalid_argument when an integer conversion fails
static TimePattern parse(const std::string& s);
private:
//! \brief Calls destructor of active union member
void destroy();
private:
Type type;
union
{
std::nullptr_t undefined;
AbsoluteVariedTime absolute;
RecurringTime recurring;
TimeInterval interval;
Timer timer;
};
};
} // namespace time
} // namespace hueplusplus
#endif