diff --git a/Cargo.lock b/Cargo.lock index dc880c1..aa292b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2614,7 +2614,7 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reminder-rs" -version = "1.7.38" +version = "1.7.39" dependencies = [ "base64 0.22.1", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 2899c49..bff6246 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "reminder-rs" -version = "1.7.38" +version = "1.7.39" authors = ["Jude Southworth "] edition = "2021" license = "AGPL-3.0 only" diff --git a/src/postman/sender.rs b/src/postman/sender.rs index 531b777..d08b4c0 100644 --- a/src/postman/sender.rs +++ b/src/postman/sender.rs @@ -34,8 +34,10 @@ use crate::{ lazy_static! { pub static ref TIMEFROM_REGEX: Regex = Regex::new(r#"<\d+):(?P.+)?>>"#).unwrap(); - pub static ref TIMENOW_REGEX: Regex = - Regex::new(r#"<(?:\w|/|_)+):(?P.+)?>>"#).unwrap(); + pub static ref TIMENOW_REGEX: Regex = Regex::new( + r#"<[+-])(?P\d+))?:(?P(?:\w|/|_)+?):(?P.+?)?>>"# + ) + .unwrap(); pub static ref LOG_TO_DATABASE: bool = env::var("LOG_TO_DATABASE").map_or(true, |v| v == "1"); } @@ -64,7 +66,7 @@ fn fmt_displacement(format: &str, seconds: u64) -> String { } pub fn substitute(string: &str) -> String { - let new = TIMEFROM_REGEX.replace(string, |caps: &Captures| { + let new = TIMEFROM_REGEX.replace_all(string, |caps: &Captures| { let final_time = caps.name("time").map(|m| m.as_str().parse::().ok()).flatten(); let format = caps.name("format").map(|m| m.as_str()); @@ -92,12 +94,26 @@ pub fn substitute(string: &str) -> String { }); TIMENOW_REGEX - .replace(&new, |caps: &Captures| { + .replace_all(&new, |caps: &Captures| { let timezone = caps.name("timezone").map(|m| m.as_str().parse::().ok()).flatten(); let format = caps.name("format").map(|m| m.as_str()); + let sign = caps.name("sign").map(|m| m.as_str()); + let offset = caps.name("offset").map(|m| m.as_str().parse::().ok()).flatten(); if let (Some(timezone), Some(format)) = (timezone, format) { - let now = Utc::now().with_timezone(&timezone); + let mut now = Utc::now().with_timezone(&timezone); + if let (Some(sign), Some(offset)) = (sign, offset) { + now = now + .checked_add_signed(TimeDelta::seconds( + offset * { + match sign { + "-" => -1, + _ => 1, + } + }, + )) + .unwrap_or(now) + } now.format(format).to_string() } else { diff --git a/templates/support/create_reminder.html.tera b/templates/support/create_reminder.html.tera index 0412d97..94a03a1 100644 --- a/templates/support/create_reminder.html.tera +++ b/templates/support/create_reminder.html.tera @@ -37,4 +37,40 @@ +
+
+
+

Custom formatting rules

+

+ Reminder content can be customized using formatting rules. +

+

timefrom

+

+ The timefrom formatting rule will display a formatted difference + between the time the reminder sends and a specified time. +
+ For example, if the current time is 1755800000 (UNIX time), the format string + <<timefrom:1755803600>> would display "1 hour" +

+

timenow

+

+ The timenow formatting rule displays the current time or an offset + from the current time in a given timezone in a custom format. +
+ For example, if the current time is 1755800000 (UNIX time), the format string + <<timenow:UTC:%H:%M:%S>> would display "18:13:20" +
+ Optionally, an offset can be provided to display a time from your current time. + For example, if the current time is 1755800000 (UNIX time), the format string + <<timenow+120:UTC:%H:%M:%S>> would display "18:15:20", + or <<timenow-120:UTC:%H:%M:%S>> would display "18:11:20" +
+ You can use this feature alongside Discord's timestamp formatting. The following + will show the text "in 2 minutes" for all users as a Discord timestamp: + <t:<<timenow+120:UTC:%s>>:R> +

+
+
+
+ {% endblock %}