summaryrefslogtreecommitdiffstats
path: root/src/relative_time.hh
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/relative_time.hh263
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