From: Dietmar Maurer <dietmar@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [proxmox-backup] CalendarEvent: add calendar_event_match and fix compute_next_event
Date: Fri, 5 Nov 2021 10:58:34 +0100 [thread overview]
Message-ID: <20211105095834.2879703-1-dietmar@proxmox.com> (raw)
Signed-off-by: Dietmar Maurer <dietmar@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
next reply other threads:[~2021-11-05 9:59 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-11-05 9:58 Dietmar Maurer [this message]
2021-11-05 11:03 Dietmar Maurer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211105095834.2879703-1-dietmar@proxmox.com \
--to=dietmar@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox