From 6ade91e11bb39394eff18371455f39fffcb72452 Mon Sep 17 00:00:00 2001 From: jude Date: Tue, 16 Sep 2025 21:00:58 +0100 Subject: [PATCH] Add cron parser for start time of a reminder --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + src/commands/autocomplete.rs | 9 ++++++++- src/models/reminder/mod.rs | 7 +++++-- src/time_parser.rs | 6 ++++++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa292b3..7384026 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -524,6 +524,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "cron-parser" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa5650eabdaa360e2c240c2a5f544f10185b439cd76d748e44e3f28128a016b" +dependencies = [ + "chrono", +] + [[package]] name = "crossbeam-channel" version = "0.5.13" @@ -2619,6 +2628,7 @@ dependencies = [ "base64 0.22.1", "chrono", "chrono-tz", + "cron-parser", "csv", "dotenv", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index bff6246..9e07817 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ serenity = { version = "0.12", default-features = false, features = ["builder", oauth2 = "4" csv = "1.2" sd-notify = "0.4.1" +cron-parser = "0.10" [dependencies.extract_derive] path = "extract_derive" diff --git a/src/commands/autocomplete.rs b/src/commands/autocomplete.rs index bfffffe..a60e4ef 100644 --- a/src/commands/autocomplete.rs +++ b/src/commands/autocomplete.rs @@ -3,6 +3,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use chrono_tz::TZ_VARIANTS; use poise::serenity_prelude::AutocompleteChoice; +use crate::time_parser::cron_next_timestamp; use crate::{models::CtxData, time_parser::natural_parser, Context}; pub async fn timezone_autocomplete(ctx: Context<'_>, partial: &str) -> Vec { @@ -42,7 +43,13 @@ pub async fn time_hint_autocomplete(ctx: Context<'_>, partial: &str) -> Vec Some(ts), + None => natural_parser(partial, &timezone.to_string()).await, + }; + + match timestamp { Some(timestamp) => match SystemTime::now().duration_since(UNIX_EPOCH) { Ok(now) => { let diff = timestamp - now.as_secs() as i64; diff --git a/src/models/reminder/mod.rs b/src/models/reminder/mod.rs index ba5dedd..2b0157c 100644 --- a/src/models/reminder/mod.rs +++ b/src/models/reminder/mod.rs @@ -16,7 +16,7 @@ use crate::{ }, CtxData, }, - time_parser::natural_parser, + time_parser::{cron_next_timestamp, natural_parser}, utils::{check_guild_subscription, check_subscription}, Context, Database, Error, }; @@ -486,7 +486,10 @@ pub async fn create_reminder( let user_data = ctx.author_data().await.unwrap(); let timezone = timezone.unwrap_or(ctx.timezone().await); - let time = natural_parser(&time, &timezone.to_string()).await; + let time = match cron_next_timestamp(&time, timezone) { + Some(ts) => Some(ts), + None => natural_parser(&time, &timezone.to_string()).await, + }; match time { Some(time) => { diff --git a/src/time_parser.rs b/src/time_parser.rs index cc4c881..c7fe36a 100644 --- a/src/time_parser.rs +++ b/src/time_parser.rs @@ -6,6 +6,8 @@ use std::{ use chrono::{DateTime, Datelike, Timelike, Utc}; use chrono_tz::Tz; +use cron_parser::parse; +use std::str::FromStr; use tokio::process::Command; use crate::consts::{LOCAL_TIMEZONE, PYTHON_LOCATION}; @@ -219,3 +221,7 @@ pub async fn natural_parser(time: &str, timezone: &str) -> Option { }) .and_then(|inner| if inner < 0 { None } else { Some(inner) }) } + +pub fn cron_next_timestamp(expr: &str, timezone: Tz) -> Option { + parse(expr, &Utc::now().with_timezone(&timezone)).ok().map(|next| next.timestamp() as i64) +}