From a35c00b0e48ca33f81789969a11059d759a3ebf4 Mon Sep 17 00:00:00 2001
From: Fuad Ismail <fuad1502@gmail.com>
Date: Wed, 11 Dec 2024 14:48:45 +0700
Subject: [PATCH] dmesg: implement since/until filter.

---
 src/uu/dmesg/src/dmesg.rs          | 31 +++++++++++++++++++++++++++++-
 src/uu/dmesg/src/time_formatter.rs |  6 ++++++
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/src/uu/dmesg/src/dmesg.rs b/src/uu/dmesg/src/dmesg.rs
index 5065325..e8917e9 100644
--- a/src/uu/dmesg/src/dmesg.rs
+++ b/src/uu/dmesg/src/dmesg.rs
@@ -3,6 +3,7 @@
 // For the full copyright and license information, please view the LICENSE
 // file that was distributed with this source code.
 
+use chrono::{DateTime, FixedOffset};
 use clap::{crate_version, Arg, ArgAction, Command};
 use regex::Regex;
 use std::{
@@ -265,7 +266,9 @@ impl Dmesg<'_> {
         Ok(self
             .try_iter()?
             .filter(Self::is_record_in_set(&self.facility_filters))
-            .filter(Self::is_record_in_set(&self.level_filters)))
+            .filter(Self::is_record_in_set(&self.level_filters))
+            .filter(Self::is_record_since(&self.since_filter))
+            .filter(Self::is_record_until(&self.until_filter)))
     }
 
     fn try_iter(&self) -> UResult<RecordIterator> {
@@ -289,6 +292,32 @@ impl Dmesg<'_> {
             _ => true,
         }
     }
+
+    fn is_record_since(
+        since: &Option<DateTime<FixedOffset>>,
+    ) -> impl Fn(&UResult<Record>) -> bool + '_ {
+        move |record: &UResult<Record>| match (record, since) {
+            (Ok(record), Some(since)) => {
+                let time =
+                    time_formatter::datetime_from_microseconds_since_boot(record.timestamp_us);
+                time >= *since
+            }
+            _ => true,
+        }
+    }
+
+    fn is_record_until(
+        until: &Option<DateTime<FixedOffset>>,
+    ) -> impl Fn(&UResult<Record>) -> bool + '_ {
+        move |record: &UResult<Record>| match (record, until) {
+            (Ok(record), Some(until)) => {
+                let time =
+                    time_formatter::datetime_from_microseconds_since_boot(record.timestamp_us);
+                time <= *until
+            }
+            _ => true,
+        }
+    }
 }
 
 enum OutputFormat {
diff --git a/src/uu/dmesg/src/time_formatter.rs b/src/uu/dmesg/src/time_formatter.rs
index 198431f..24a0be1 100644
--- a/src/uu/dmesg/src/time_formatter.rs
+++ b/src/uu/dmesg/src/time_formatter.rs
@@ -116,6 +116,12 @@ impl DeltaFormatter {
     }
 }
 
+pub fn datetime_from_microseconds_since_boot(microseconds: i64) -> DateTime<FixedOffset> {
+    boot_time()
+        .checked_add_signed(TimeDelta::microseconds(microseconds))
+        .unwrap()
+}
+
 static BOOT_TIME: OnceLock<DateTime<FixedOffset>> = OnceLock::new();
 
 #[cfg(feature = "fixed-boot-time")]