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 "config.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "base/time_util.hh"
|
#include "base/time_util.hh"
|
||||||
#include "pcrepp/pcrepp.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;
|
rt_field_type last_field_type = RTF__MAX;
|
||||||
relative_time retval;
|
relative_time retval;
|
||||||
parse_error pe_out;
|
parse_error pe_out;
|
||||||
|
std::unordered_set<token_t> seen_tokens;
|
||||||
|
|
||||||
pe_out.pe_column = -1;
|
pe_out.pe_column = -1;
|
||||||
pe_out.pe_msg.clear();
|
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 (pi.pi_next_offset >= pi.pi_length) {
|
||||||
if (number_set) {
|
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";
|
pe_out.pe_msg = "Number given without a time unit";
|
||||||
return Err(pe_out);
|
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();
|
retval.rollover();
|
||||||
return Ok(retval);
|
return Ok(retval);
|
||||||
}
|
}
|
||||||
@ -159,6 +201,16 @@ relative_time::from_str(const char *str, size_t len)
|
|||||||
case RTT_YESTERDAY:
|
case RTT_YESTERDAY:
|
||||||
case RTT_TODAY:
|
case RTT_TODAY:
|
||||||
case RTT_NOW: {
|
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 timeval tv;
|
||||||
struct exttm tm;
|
struct exttm tm;
|
||||||
|
|
||||||
@ -199,6 +251,12 @@ relative_time::from_str(const char *str, size_t len)
|
|||||||
break;
|
break;
|
||||||
case RTT_AM:
|
case RTT_AM:
|
||||||
case RTT_PM:
|
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) {
|
if (number_set) {
|
||||||
retval.rt_field[RTF_HOURS] = number;
|
retval.rt_field[RTF_HOURS] = number;
|
||||||
retval.rt_field[RTF_MINUTES] = 0;
|
retval.rt_field[RTF_MINUTES] = 0;
|
||||||
@ -504,6 +562,7 @@ relative_time::from_str(const char *str, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
number_was_set = false;
|
number_was_set = false;
|
||||||
|
seen_tokens.insert(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
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) {
|
if (this->rt_field[RTF_YEARS].value > tm.et_tm.tm_year) {
|
||||||
return nonstd::nullopt;
|
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;
|
clear = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->rt_field[RTF_MONTHS].is_set) {
|
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;
|
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;
|
clear = true;
|
||||||
} else if (clear) {
|
} else if (clear) {
|
||||||
retval.et_tm.tm_mon = 0;
|
retval.et_tm.tm_mon = 0;
|
||||||
@ -863,3 +922,37 @@ nonstd::optional<exttm> relative_time::window_start(
|
|||||||
|
|
||||||
return retval;
|
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;
|
nonstd::optional<exttm> window_start(const struct exttm &tm) const;
|
||||||
|
|
||||||
int64_t to_microseconds() 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
void to_timeval(struct timeval &tv_out) const {
|
void to_timeval(struct timeval &tv_out) const {
|
||||||
int64_t us = this->to_microseconds();
|
int64_t us = this->to_microseconds();
|
||||||
|
@ -75,10 +75,15 @@ static struct {
|
|||||||
const char *reltime;
|
const char *reltime;
|
||||||
const char *expected_error;
|
const char *expected_error;
|
||||||
} BAD_TEST_DATA[] = {
|
} 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" },
|
{ "ago", "Expecting a time unit" },
|
||||||
{ "minute", "Expecting a number before time unit" },
|
{ "minute", "Expecting a number before time unit" },
|
||||||
{ "1 2", "No time unit given for the previous number" },
|
{ "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" },
|
{ "before after", "Before/after ranges are not supported yet" },
|
||||||
|
|
||||||
{ nullptr, nullptr }
|
{ nullptr, nullptr }
|
||||||
@ -93,6 +98,32 @@ TEST_CASE("reltime")
|
|||||||
struct exttm tm, tm2;
|
struct exttm tm, tm2;
|
||||||
time_t new_time;
|
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");
|
auto rt_res = relative_time::from_str("after fri");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user