mirror of
https://github.com/tstack/lnav
synced 2024-11-01 21:40:34 +00:00
[reltime] some more relative time fixes
This commit is contained in:
parent
aa7ac37cdc
commit
dbcfdda363
@ -30,6 +30,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "base/time_util.hh"
|
||||
#include "pcrepp/pcrepp.hh"
|
||||
@ -114,6 +115,7 @@ relative_time::from_str(const char *str, size_t len)
|
||||
rt_field_type last_field_type = RTF__MAX;
|
||||
relative_time retval;
|
||||
parse_error pe_out;
|
||||
std::unordered_set<token_t> seen_tokens;
|
||||
|
||||
pe_out.pe_column = -1;
|
||||
pe_out.pe_msg.clear();
|
||||
@ -123,10 +125,50 @@ relative_time::from_str(const char *str, size_t len)
|
||||
|
||||
if (pi.pi_next_offset >= pi.pi_length) {
|
||||
if (number_set) {
|
||||
if (number > 1970 && number < 2050) {
|
||||
retval.rt_field[RTF_YEARS] = number - 1900;
|
||||
retval.rt_absolute_field_end = RTF__MAX;
|
||||
|
||||
switch (base_token) {
|
||||
case RTT_BEFORE: {
|
||||
auto epoch = retval.to_timeval();
|
||||
retval.rt_duration =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::seconds(epoch.tv_sec)) +
|
||||
std::chrono::microseconds(epoch.tv_usec);
|
||||
retval.rt_field[RTF_YEARS] = 70;
|
||||
break;
|
||||
}
|
||||
case RTT_AFTER:
|
||||
retval.rt_duration = std::chrono::duration_cast<
|
||||
std::chrono::microseconds>(
|
||||
std::chrono::hours(24 * 365 * 200));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Ok(retval);
|
||||
}
|
||||
|
||||
pe_out.pe_msg = "Number given without a time unit";
|
||||
return Err(pe_out);
|
||||
}
|
||||
|
||||
if (base_token != RTT_INVALID) {
|
||||
switch (base_token) {
|
||||
case RTT_BEFORE:
|
||||
pe_out.pe_msg = "'before' requires a point in time (e.g. before 10am)";
|
||||
break;
|
||||
case RTT_AFTER:
|
||||
pe_out.pe_msg = "'after' requires a point in time (e.g. after 10am)";
|
||||
break;
|
||||
default:
|
||||
ensure(false);
|
||||
break;
|
||||
}
|
||||
return Err(pe_out);
|
||||
}
|
||||
|
||||
retval.rollover();
|
||||
return Ok(retval);
|
||||
}
|
||||
@ -159,6 +201,16 @@ relative_time::from_str(const char *str, size_t len)
|
||||
case RTT_YESTERDAY:
|
||||
case RTT_TODAY:
|
||||
case RTT_NOW: {
|
||||
if (seen_tokens.count(token) > 0) {
|
||||
pe_out.pe_msg =
|
||||
"Current time reference has already been used";
|
||||
return Err(pe_out);
|
||||
}
|
||||
|
||||
seen_tokens.insert(RTT_YESTERDAY);
|
||||
seen_tokens.insert(RTT_TODAY);
|
||||
seen_tokens.insert(RTT_NOW);
|
||||
|
||||
struct timeval tv;
|
||||
struct exttm tm;
|
||||
|
||||
@ -199,6 +251,12 @@ relative_time::from_str(const char *str, size_t len)
|
||||
break;
|
||||
case RTT_AM:
|
||||
case RTT_PM:
|
||||
if (seen_tokens.count(token) > 0) {
|
||||
pe_out.pe_msg = "Time has already been set";
|
||||
return Err(pe_out);
|
||||
}
|
||||
seen_tokens.insert(RTT_AM);
|
||||
seen_tokens.insert(RTT_PM);
|
||||
if (number_set) {
|
||||
retval.rt_field[RTF_HOURS] = number;
|
||||
retval.rt_field[RTF_MINUTES] = 0;
|
||||
@ -504,6 +562,7 @@ relative_time::from_str(const char *str, size_t len)
|
||||
}
|
||||
|
||||
number_was_set = false;
|
||||
seen_tokens.insert(token);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
@ -779,15 +838,15 @@ nonstd::optional<exttm> relative_time::window_start(
|
||||
if (this->rt_field[RTF_YEARS].value > tm.et_tm.tm_year) {
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
retval.et_tm.tm_year = this->rt_field[RTF_YEARS].value - 1900;
|
||||
retval.et_tm.tm_year = this->rt_field[RTF_YEARS].value;
|
||||
clear = true;
|
||||
}
|
||||
|
||||
if (this->rt_field[RTF_MONTHS].is_set) {
|
||||
if (this->rt_field[RTF_MONTHS].value - 1 > tm.et_tm.tm_mon) {
|
||||
if (this->rt_field[RTF_MONTHS].value > tm.et_tm.tm_mon) {
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
retval.et_tm.tm_mon = this->rt_field[RTF_MONTHS].value - 1;
|
||||
retval.et_tm.tm_mon = this->rt_field[RTF_MONTHS].value;
|
||||
clear = true;
|
||||
} else if (clear) {
|
||||
retval.et_tm.tm_mon = 0;
|
||||
@ -863,3 +922,37 @@ nonstd::optional<exttm> relative_time::window_start(
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int64_t relative_time::to_microseconds() const
|
||||
{
|
||||
int64_t retval;
|
||||
|
||||
if (this->is_absolute()) {
|
||||
struct exttm etm;
|
||||
|
||||
memset(&etm, 0, sizeof(etm));
|
||||
etm.et_tm.tm_year = this->rt_field[RTF_YEARS].value;
|
||||
etm.et_tm.tm_mon = this->rt_field[RTF_MONTHS].value;
|
||||
if (this->rt_field[RTF_DAYS].is_set) {
|
||||
etm.et_tm.tm_mday = this->rt_field[RTF_DAYS].value;
|
||||
} else {
|
||||
etm.et_tm.tm_mday = 1;
|
||||
}
|
||||
etm.et_tm.tm_min = this->rt_field[RTF_MINUTES].value;
|
||||
etm.et_tm.tm_sec = this->rt_field[RTF_SECONDS].value;
|
||||
|
||||
auto epoch_secs = std::chrono::seconds(tm2sec(&etm.et_tm));
|
||||
retval = std::chrono::duration_cast<std::chrono::microseconds>(epoch_secs).count();
|
||||
retval += this->rt_field[RTF_MICROSECONDS].value;
|
||||
} else {
|
||||
retval = this->rt_field[RTF_YEARS].value * 12;
|
||||
retval = (retval + this->rt_field[RTF_MONTHS].value) * 30;
|
||||
retval = (retval + this->rt_field[RTF_DAYS].value) * 24;
|
||||
retval = (retval + this->rt_field[RTF_HOURS].value) * 60;
|
||||
retval = (retval + this->rt_field[RTF_MINUTES].value) * 60;
|
||||
retval = (retval + this->rt_field[RTF_SECONDS].value) * 1000 * 1000;
|
||||
retval = (retval + this->rt_field[RTF_MICROSECONDS].value);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -209,19 +209,7 @@ public:
|
||||
|
||||
nonstd::optional<exttm> window_start(const struct exttm &tm) const;
|
||||
|
||||
int64_t to_microseconds() const {
|
||||
int64_t retval;
|
||||
|
||||
retval = this->rt_field[RTF_YEARS].value * 12;
|
||||
retval = (retval + this->rt_field[RTF_MONTHS].value) * 30;
|
||||
retval = (retval + this->rt_field[RTF_DAYS].value) * 24;
|
||||
retval = (retval + this->rt_field[RTF_HOURS].value) * 60;
|
||||
retval = (retval + this->rt_field[RTF_MINUTES].value) * 60;
|
||||
retval = (retval + this->rt_field[RTF_SECONDS].value) * 1000 * 1000;
|
||||
retval = (retval + this->rt_field[RTF_MICROSECONDS].value);
|
||||
|
||||
return retval;
|
||||
};
|
||||
int64_t to_microseconds() const;
|
||||
|
||||
void to_timeval(struct timeval &tv_out) const {
|
||||
int64_t us = this->to_microseconds();
|
||||
|
@ -75,10 +75,15 @@ static struct {
|
||||
const char *reltime;
|
||||
const char *expected_error;
|
||||
} BAD_TEST_DATA[] = {
|
||||
{ "10am am", "Time has already been set" },
|
||||
{ "yesterday today", "Current time reference has already been used" },
|
||||
{ "10am 10am", "Time has already been set" },
|
||||
{ "ago", "Expecting a time unit" },
|
||||
{ "minute", "Expecting a number before time unit" },
|
||||
{ "1 2", "No time unit given for the previous number" },
|
||||
{ "blah", "Unrecognized input"},
|
||||
{ "blah", "Unrecognized input" },
|
||||
{ "before", "'before' requires a point in time (e.g. before 10am)" },
|
||||
{ "after", "'after' requires a point in time (e.g. after 10am)" },
|
||||
{ "before after", "Before/after ranges are not supported yet" },
|
||||
|
||||
{ nullptr, nullptr }
|
||||
@ -93,6 +98,32 @@ TEST_CASE("reltime")
|
||||
struct exttm tm, tm2;
|
||||
time_t new_time;
|
||||
|
||||
{
|
||||
auto rt_res = relative_time::from_str("before 2014");
|
||||
|
||||
CHECK(rt_res.isOk());
|
||||
auto rt = rt_res.unwrap();
|
||||
|
||||
time_t t_in = 1438948860;
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
tm.et_tm = *gmtime(&t_in);
|
||||
auto win_opt = rt.window_start(tm);
|
||||
CHECK(!win_opt.has_value());
|
||||
}
|
||||
|
||||
{
|
||||
auto rt_res = relative_time::from_str("after 2014");
|
||||
|
||||
CHECK(rt_res.isOk());
|
||||
auto rt = rt_res.unwrap();
|
||||
|
||||
time_t t_in = 1438948860;
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
tm.et_tm = *gmtime(&t_in);
|
||||
auto win_opt = rt.window_start(tm);
|
||||
CHECK(win_opt.has_value());
|
||||
}
|
||||
|
||||
{
|
||||
auto rt_res = relative_time::from_str("after fri");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user