Skip to content

Commit 8f21026

Browse files
committed
Handle missing year in date time parser (#4811)
1 parent 5cb78af commit 8f21026

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

quickwit/quickwit-datetime/src/date_time_format.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use time::error::Format;
2828
use time::format_description::well_known::{Iso8601, Rfc2822, Rfc3339};
2929
use time::format_description::FormatItem;
3030
use time::parsing::Parsed;
31-
use time::{OffsetDateTime, PrimitiveDateTime};
31+
use time::{Month, OffsetDateTime, PrimitiveDateTime};
3232
use time_fmt::parse::time_format_item::parse_to_format_item;
3333

3434
use crate::TantivyDateTime;
@@ -84,6 +84,11 @@ impl StrptimeParser {
8484
parsed.set_minute(0u8);
8585
parsed.set_second(0u8);
8686
}
87+
if parsed.year().is_none() {
88+
let now = OffsetDateTime::now_utc();
89+
let year = infer_year(parsed.month(), now.month(), now.year());
90+
parsed.set_year(year);
91+
}
8792
let date_time = parsed.try_into()?;
8893
Ok(date_time)
8994
}
@@ -318,9 +323,26 @@ impl<'de> Deserialize<'de> for DateTimeOutputFormat {
318323
}
319324
}
320325

326+
/// Infers the year of a parsed date time. It assumes that events appear more often delayed than in
327+
/// the future and, as a result, skews towards the past year.
328+
pub(super) fn infer_year(
329+
parsed_month_opt: Option<Month>,
330+
this_month: Month,
331+
this_year: i32,
332+
) -> i32 {
333+
let Some(parsed_month) = parsed_month_opt else {
334+
return this_year;
335+
};
336+
if parsed_month as u8 > this_month as u8 + 3 {
337+
return this_year - 1;
338+
}
339+
this_year
340+
}
341+
321342
#[cfg(test)]
322343
mod tests {
323344
use time::macros::datetime;
345+
use time::Month;
324346

325347
use super::*;
326348

@@ -453,4 +475,28 @@ mod tests {
453475
"datetime string `2021-01-01TABC` does not match strptime format `%Y-%m-%d`"
454476
);
455477
}
478+
479+
#[test]
480+
fn test_infer_year() {
481+
let inferred_year = infer_year(None, Month::January, 2024);
482+
assert_eq!(inferred_year, 2024);
483+
484+
let inferred_year = infer_year(Some(Month::December), Month::January, 2024);
485+
assert_eq!(inferred_year, 2023);
486+
487+
let inferred_year = infer_year(Some(Month::January), Month::January, 2024);
488+
assert_eq!(inferred_year, 2024);
489+
490+
let inferred_year = infer_year(Some(Month::February), Month::January, 2024);
491+
assert_eq!(inferred_year, 2024);
492+
493+
let inferred_year = infer_year(Some(Month::March), Month::January, 2024);
494+
assert_eq!(inferred_year, 2024);
495+
496+
let inferred_year = infer_year(Some(Month::April), Month::January, 2024);
497+
assert_eq!(inferred_year, 2024);
498+
499+
let inferred_year = infer_year(Some(Month::May), Month::January, 2024);
500+
assert_eq!(inferred_year, 2023);
501+
}
456502
}

quickwit/quickwit-datetime/src/date_time_parsing.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,10 @@ mod tests {
182182
use std::str::FromStr;
183183

184184
use time::macros::datetime;
185+
use time::Month;
185186

186187
use super::*;
188+
use crate::date_time_format::infer_year;
187189
use crate::StrptimeParser;
188190

189191
#[test]
@@ -247,6 +249,12 @@ mod tests {
247249
"2024-01-31 18:40:19.950188123",
248250
datetime!(2024-01-31 18:40:19.950188123 UTC),
249251
),
252+
("%b %d %H:%M:%S", "Mar 6 17:40:02", {
253+
let dt = datetime!(1900-03-06 17:40:02 UTC);
254+
let now = OffsetDateTime::now_utc();
255+
let year = infer_year(Some(Month::March), now.month(), now.year());
256+
dt.replace_year(year).unwrap()
257+
}),
250258
];
251259
for (fmt, date_time_str, expected) in test_data {
252260
let parser = StrptimeParser::from_str(fmt).unwrap();

0 commit comments

Comments
 (0)