diff options
Diffstat (limited to 'src/relative_time.hh')
-rw-r--r-- | src/relative_time.hh | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/src/relative_time.hh b/src/relative_time.hh new file mode 100644 index 0000000..7334217 --- /dev/null +++ b/src/relative_time.hh @@ -0,0 +1,263 @@ +/** + * Copyright (c) 2015, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LNAV_RELATIVE_TIME_HH +#define LNAV_RELATIVE_TIME_HH + +#include <sys/time.h> + +#define __STDC_FORMAT_MACROS +#include <array> +#include <chrono> +#include <set> +#include <string> + +#include <inttypes.h> + +#include "base/intern_string.hh" +#include "base/result.h" +#include "ptimec.hh" + +class relative_time { +public: + enum token_t { + RTT_INVALID = -1, + + RTT_WHITE, + RTT_AM, + RTT_PM, + RTT_A, + RTT_AN, + RTT_AT, + RTT_TIME, + RTT_NUMBER, + + RTT_SUNDAY, + RTT_MONDAY, + RTT_TUESDAY, + RTT_WEDNESDAY, + RTT_THURSDAY, + RTT_FRIDAY, + RTT_SATURDAY, + + RTT_MICROS, + RTT_MILLIS, + RTT_SECONDS, + RTT_MINUTES, + RTT_HOURS, + RTT_DAYS, + RTT_WEEKS, + RTT_MONTHS, + RTT_YEARS, + RTT_TODAY, + RTT_YESTERDAY, + RTT_TOMORROW, + RTT_NOON, + RTT_AND, + RTT_THE, + RTT_AGO, + RTT_LATER, + RTT_BEFORE, + RTT_AFTER, + RTT_NOW, + RTT_HERE, + RTT_NEXT, + RTT_PREVIOUS, + + RTT__MAX + }; + + enum rt_field_type { + RTF_MICROSECONDS, + RTF_SECONDS, + RTF_MINUTES, + RTF_HOURS, + RTF_DAYS, + RTF_MONTHS, + RTF_YEARS, + + RTF__MAX + }; + + struct parse_error { + int pe_column; + std::string pe_msg; + }; + + static Result<relative_time, parse_error> from_str(string_fragment str); + + static relative_time from_timeval(const struct timeval& tv); + + static relative_time from_usecs(std::chrono::microseconds usecs); + + relative_time() { this->clear(); } + + void clear() + { + this->rt_field.fill({}); + this->rt_next = false; + this->rt_previous = false; + this->rt_absolute_field_end = 0; + } + + void negate() + { + if (this->is_absolute()) { + if (this->rt_next) { + this->rt_next = false; + this->rt_previous = true; + } else if (this->rt_previous) { + this->rt_next = true; + this->rt_previous = false; + } + return; + } + for (int lpc = 0; lpc < RTF__MAX; lpc++) { + if (this->rt_field[lpc].value != 0) { + this->rt_field[lpc].value = -this->rt_field[lpc].value; + } + } + } + + bool is_negative() const + { + if (this->rt_previous) { + return true; + } + for (const auto& rtf : this->rt_field) { + if (rtf.value < 0) { + return true; + } + } + return false; + } + + bool is_absolute() const + { + return !this->rt_included_days.empty() + || this->rt_absolute_field_end > 0; + } + + bool is_absolute(rt_field_type rft) const + { + return rft < this->rt_absolute_field_end; + } + + bool is_relative() const + { + return !this->is_absolute() || this->rt_next || this->rt_previous; + } + + bool empty() const + { + if (!this->rt_included_days.empty()) { + return false; + } + for (const auto& rtf : this->rt_field) { + if (rtf.is_set) { + return false; + } + } + return true; + } + + struct exttm adjust_now() const + { + struct exttm tm; + time_t now; + + time(&now); + tm.et_tm = *gmtime(&now); + return this->adjust(tm); + } + + struct exttm adjust(const struct timeval& tv) const + { + struct exttm tm; + + tm.et_tm = *gmtime(&tv.tv_sec); + tm.et_nsec = tv.tv_usec * 1000; + return this->adjust(tm); + } + + struct exttm adjust(const struct exttm& tm) const; + + nonstd::optional<exttm> window_start(const struct exttm& tm) const; + + int64_t to_microseconds() const; + + void to_timeval(struct timeval& tv_out) const + { + int64_t us = this->to_microseconds(); + + tv_out.tv_sec = us / (1000 * 1000); + tv_out.tv_usec = us % (1000 * 1000); + } + + struct timeval to_timeval() const + { + int64_t us = this->to_microseconds(); + struct timeval retval; + + retval.tv_sec = us / (1000 * 1000); + retval.tv_usec = us % (1000 * 1000); + return retval; + } + + std::string to_string() const; + + void rollover(); + + static const char FIELD_CHARS[RTF__MAX]; + + struct _rt_field { + _rt_field(int64_t value) : value(value), is_set(true) {} + + _rt_field() : value(0), is_set(false) {} + + void clear() + { + this->value = 0; + this->is_set = false; + } + + int64_t value; + bool is_set; + }; + + std::array<_rt_field, RTF__MAX> rt_field; + std::set<token_t> rt_included_days; + std::chrono::microseconds rt_duration{0}; + + bool rt_next; + bool rt_previous; + int rt_absolute_field_end; +}; + +#endif // LNAV_RELATIVE_TIME_HH |