[pbs-devel] [proxmox-backup] CalendarEvent: add calendar_event_match and fix compute_next_event

Dietmar Maurer dietmar at proxmox.com
Fri Nov 5 10:58:34 CET 2021


Signed-off-by: Dietmar Maurer <dietmar at proxmox.com>
---
 proxmox-systemd/src/parse_time.rs |   4 +-
 proxmox-systemd/src/time.rs       | 129 +++++++++++++++++++++++++++++-
 2 files changed, 130 insertions(+), 3 deletions(-)

diff --git a/proxmox-systemd/src/parse_time.rs b/proxmox-systemd/src/parse_time.rs
index ba9449b1..9a2ecd77 100644
--- a/proxmox-systemd/src/parse_time.rs
+++ b/proxmox-systemd/src/parse_time.rs
@@ -211,7 +211,7 @@ fn parse_date_time_comp_list(start: u32, max: usize) -> impl Fn(&str) -> IResult
                     return Ok((n, vec![DateTimeValue::Repeated(start, repeat)]));
                 }
             }
-            return Ok((rest, Vec::new()));
+            return Ok((rest, vec![DateTimeValue::Range(start, max as u32)]));
         }
 
         separated_nonempty_list(tag(","), parse_date_time_comp(max))(i)
@@ -229,7 +229,7 @@ fn parse_time_spec(i: &str) -> IResult<&str, TimeSpec> {
     if let Some(second) = opt_second {
         Ok((i, TimeSpec { hour, minute, second }))
     } else {
-        Ok((i, TimeSpec { hour, minute, second: vec![DateTimeValue::Single(0)] }))
+        Ok((i, TimeSpec { hour, minute, second: Vec::new() }))
     }
 }
 
diff --git a/proxmox-systemd/src/time.rs b/proxmox-systemd/src/time.rs
index b81e970e..acba4763 100644
--- a/proxmox-systemd/src/time.rs
+++ b/proxmox-systemd/src/time.rs
@@ -234,6 +234,69 @@ pub fn verify_calendar_event(i: &str) -> Result<(), Error> {
     Ok(())
 }
 
+pub fn calendar_event_match(
+    event: &CalendarEvent,
+    epoch: i64,
+    utc: bool,
+) -> Result<bool, Error> {
+
+    let t = TmEditor::with_epoch(epoch, utc)?;
+
+    if !event.year.is_empty() {
+        let year: u32 = t.year().try_into()?;
+        if !DateTimeValue::list_contains(&event.year, year) {
+            return Ok(false);
+        }
+    }
+
+    if !event.month.is_empty() {
+        let month: u32 = t.month().try_into()?;
+        if !DateTimeValue::list_contains(&event.month, month) {
+            return Ok(false);
+        }
+    }
+
+    if !event.day.is_empty() {
+        let day: u32 = t.day().try_into()?;
+        if !DateTimeValue::list_contains(&event.day, day) {
+            return Ok(false);
+        }
+    }
+
+    let all_days = event.days.is_empty() || event.days.is_all();
+
+    if !all_days {
+        let day_num: u32 = t.day_num().try_into()?;
+        let day = WeekDays::from_bits(1<<day_num).unwrap();
+        if !event.days.contains(day) {
+            return Ok(false);
+        }
+    }
+
+    if !event.hour.is_empty() {
+        let hour = t.hour().try_into()?;
+        if !DateTimeValue::list_contains(&event.hour, hour) {
+            return Ok(false);
+        }
+    }
+
+    if !event.minute.is_empty() {
+        let minute = t.min().try_into()?;
+        if !DateTimeValue::list_contains(&event.minute, minute) {
+            return Ok(false);
+        }
+    }
+
+    if !event.second.is_empty() {
+        let second = t.sec().try_into()?;
+        if !DateTimeValue::list_contains(&event.second, second) {
+            return Ok(false);
+        }
+    }
+
+    Ok(true)
+}
+
 pub fn compute_next_event(
     event: &CalendarEvent,
     last: i64,
@@ -339,6 +402,29 @@ pub fn compute_next_event(
                     t.set_time(t.hour() + 1, 0, 0)?;
                 }
                 continue;
+            } else {
+                // Match, but
+                if event.second.is_empty() && t.sec() != 0 {
+                    if let Some(n) = DateTimeValue::find_next(&event.minute, minute) {
+                        // test next minute
+                        t.set_min_sec(n.try_into()?, 0)?;
+                    } else {
+                        // test next hour
+                        if !event.hour.is_empty() {
+                            let hour = t.hour().try_into()?;
+                            if let Some(n) = DateTimeValue::find_next(&event.hour, hour) {
+                                // test next hour
+                                t.set_time(n.try_into()?, 0, 0)?;
+                            } else {
+                                // test next day
+                                t.add_days(1)?;
+                            }
+                        } else {
+                            t.set_time(t.hour() + 1, 0, 0)?;
+                        }
+                    }
+                    continue;
+                }
             }
         }
 
@@ -383,6 +469,47 @@ mod test {
         (mday*3600*24 + hour*3600 + min*60) as i64
     }
 
+    #[test]
+    fn test_date_time_value_contains() -> Result<(), Error> {
+
+        let dtv =  DateTimeValue::Repeated(5, 2);
+
+        assert!(!dtv.contains(0));
+        assert!(!dtv.contains(1));
+        assert!(!dtv.contains(2));
+        assert!(!dtv.contains(3));
+        assert!(!dtv.contains(4));
+        assert!(dtv.contains(5));
+        assert!(!dtv.contains(6));
+        assert!(dtv.contains(7));
+        assert!(!dtv.contains(8));
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_event_match() -> Result<(), Error> {
+
+        const THURSDAY_00_00: i64 = make_test_time(0, 0, 0);
+        const SATURDAY_09_00: i64 = make_test_time(2, 9, 0);
+        const SUNDAY_09_00: i64 = make_test_time(3, 9, 0);
+
+        let event = parse_calendar_event("mon..fri 8..16:*")?;
+
+        const HOUR: i64 = 3600;
+
+        assert!(!calendar_event_match(&event, THURSDAY_00_00, true)?);
+        assert!(!calendar_event_match(&event, THURSDAY_00_00 + 7*HOUR, true)?);
+        assert!(calendar_event_match(&event, THURSDAY_00_00 + 8*HOUR, true)?);
+        assert!(calendar_event_match(&event, THURSDAY_00_00 + 15*HOUR, true)?);
+        assert!(calendar_event_match(&event, THURSDAY_00_00 + 16*HOUR, true)?);
+        assert!(!calendar_event_match(&event, THURSDAY_00_00 + 17*HOUR, true)?);
+        assert!(!calendar_event_match(&event, SATURDAY_09_00, true)?);
+        assert!(!calendar_event_match(&event, SUNDAY_09_00, true)?);
+
+        Ok(())
+    }
+
     #[test]
     fn test_compute_next_event() -> Result<(), Error> {
 
@@ -405,7 +532,7 @@ mod test {
                         );
                     }
                 }
-                Ok(None) => bail!("next {:?} failed to find a timestamp", event),
+                Ok(None) => bail!("next {} {:?} failed to find a timestamp", v, event),
                 Err(err) => bail!("compute next for '{}' failed - {}", v, err),
             }
 
-- 
2.30.2





More information about the pbs-devel mailing list