Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): Add "relative dates" #185

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion core/datepatterns.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ weekday monthname day[ hour24:min[:sec]] fullyear
year monthname day[ hour12:min[:sec] meridiem[ offset]][ adbc]
year monthname day[ hour24:min[:sec][ offset]][ adbc]

# Today dates
# Relative dates
today
today:adddays
today:-subdays
today[:[adddays][-subdays]] hour12:min[:sec] meridiem[ offset]
today[:[adddays][-subdays]] hour24:min[:sec][ offset]
hour12:min[:sec] meridiem[ offset]
hour24:min[:sec][ offset]

today:'W'addweeks
today:'W'subweeks
today[:'W'[addweeks][-subweeks]] hour12:min[:sec] meridiem[ offset]
today[:'W'[addweeks][-subweeks]] hour24:min[:sec][ offset]
hour12:min[:sec] meridiem[ offset]
hour24:min[:sec][ offset]
77 changes: 76 additions & 1 deletion core/src/parsing/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::ast::{DatePattern, DateToken};
use crate::loader::Context;
use crate::types::{BaseUnit, BigInt, BigRat, Dimensionality, GenericDateTime, Number, Numeric};
use chrono::format::Parsed;
use chrono::{DateTime, Duration, FixedOffset, Local, TimeZone, Weekday};
use chrono::{DateTime, Datelike, Days, Duration, FixedOffset, Local, TimeZone, Weekday};
use chrono_tz::Tz;
use std::iter::Peekable;
use std::str::FromStr;
Expand Down Expand Up @@ -303,6 +303,81 @@ where
}
x => Err(format!("Expected weekday, got {}", ts(x))),
},
"today" => match tok {
Some(DateToken::Literal(ref s)) if s == "today" => {
let date = Local::now().date_naive();
*out = Parsed::new();
out.year = Some(date.year());
out.month = Some(date.month());
out.day = Some(date.day());
Ok(())
},
x => Err(format!("Expected `today`, got {}", ts(x))),
},
"adddays" => numeric_match(tok.as_ref(), "adddays", 0, 0..=i32::MAX).and_then(|days| {
let date = out.to_naive_date().expect("The parser should parse only correct dates and handle invalid cases by itself, chrono should not error here");
let add = Days::new(days as u64);
match date.checked_add_days(add) {
Some(date) => {
*out = Parsed::new();
out.year = Some(date.year());
out.month = Some(date.month());
out.day = Some(date.day());
Ok(())
},
None => {
Err(format!("Expected valid date, out of bounds"))
}
}
}),
"subdays" => numeric_match(tok.as_ref(), "subdays", 0, 0..=i32::MAX).and_then(|days| {
let date = out.to_naive_date().expect("The parser should parse only correct dates and handle invalid cases by itself, chrono should not error here");
let sub = Days::new(days as u64);
match date.checked_sub_days(sub) {
Some(date) => {
*out = Parsed::new();
out.year = Some(date.year());
out.month = Some(date.month());
out.day = Some(date.day());
Ok(())
},
None => {
Err(format!("Expected valid date, out of bounds"))
}
}
}),
"addweeks" => numeric_match(tok.as_ref(), "addweeks", 0, 0..=(i32::MAX / 7)).and_then(|weeks| {
let date = out.to_naive_date().expect("The parser should parse only correct dates and handle invalid cases by itself, chrono should not error here");
let add = Days::new(7 * weeks as u64);
match date.checked_add_days(add) {
Some(date) => {
*out = Parsed::new();
out.year = Some(date.year());
out.month = Some(date.month());
out.day = Some(date.day());
Ok(())
},
None => {
Err(format!("Expected valid date, out of bounds"))
}
}
}),
"subweeks" => numeric_match(tok.as_ref(), "subweeks", 0, 0..=(i32::MAX / 7)).and_then(|weeks| {
let date = out.to_naive_date().expect("The parser should parse only correct dates and handle invalid cases by itself, chrono should not error here");
let sub = Days::new(7 * weeks as u64);
match date.checked_sub_days(sub) {
Some(date) => {
*out = Parsed::new();
out.year = Some(date.year());
out.month = Some(date.month());
out.day = Some(date.day());
Ok(())
},
None => {
Err(format!("Expected valid date, out of bounds"))
}
}
}),
x => Err(format!("Unknown match pattern `{}`", x)),
},
Some(&DatePattern::Optional(ref pats)) => {
Expand Down
20 changes: 20 additions & 0 deletions docs/rink-dates.5.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,26 @@ The valid keywords are:
Makes English weekday names, case insensitive. Recognizes 3-letter
names (like mon, tue, wed) and full names.

**today**::
Specifies a relative date. Resets the date to the current date in the
local timezone, with time at 00:00.

**adddays**::
Matches a number of days. Can be any number of digits. Adds that amount
of days to the date relative to **today**.

**subdays**::
Matches a number of days. Can be any number of digits. Subtracts that
amount of days from the date relative to **today**.

**addweeks**::
Matches a number of weeks. Can be any number of digits. Adds that
amount of weeks to the date relative to **today**.

**subweeks**::
Matches a number of weeks. Can be any number of digits. Subtracts that
amount of weeks from the date relative to **today**.

**`-`**::
Matches a literal `-` character.

Expand Down
Loading