Skip to content

Commit 82ea54a

Browse files
committed
Make parse_dateime::parse_datetime::from_str accept relative time
1 parent efee20b commit 82ea54a

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

src/parse_datetime.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use chrono::{DateTime, FixedOffset, Local, LocalResult, NaiveDateTime, TimeZone}
55

66
use crate::ParseDurationError;
77

8+
use crate::from_str as parse_relative_time;
9+
810
/// Formats that parse input can take.
911
/// Taken from `touch` coreutils
1012
mod format {
@@ -46,6 +48,8 @@ mod format {
4648
///
4749
/// * ISO formats
4850
/// * timezone offsets, e.g., "UTC-0100"
51+
/// * unix timestamps, e.g., "@12"
52+
/// * relative time to now, e.g. "+1 hour"
4953
///
5054
/// # Returns
5155
///
@@ -123,6 +127,15 @@ pub fn from_str<S: AsRef<str> + Clone>(s: S) -> Result<DateTime<FixedOffset>, Pa
123127
}
124128
}
125129

130+
// Parse relative time.
131+
if let Ok(relative_time) = parse_relative_time(s.as_ref()) {
132+
let current_time = DateTime::<FixedOffset>::from(Local::now());
133+
134+
if let Some(date_time) = current_time.checked_add_signed(relative_time) {
135+
return Ok(date_time);
136+
}
137+
}
138+
126139
// Default parse and failure
127140
s.as_ref()
128141
.parse()
@@ -243,6 +256,46 @@ mod tests {
243256
}
244257
}
245258

259+
#[cfg(test)]
260+
mod relative_time {
261+
use chrono::Local;
262+
263+
use crate::{parse_datetime::from_str, ParseDurationError};
264+
265+
#[test]
266+
fn test_positive_offsets() {
267+
let relative_times = vec![
268+
"today",
269+
"yesterday",
270+
"1 minute",
271+
"3 hours",
272+
"1 year 3 months",
273+
];
274+
275+
for relative_time in relative_times {
276+
assert_eq!(from_str(relative_time).is_ok(), true);
277+
}
278+
}
279+
280+
#[test]
281+
fn test_partial_offset() {
282+
let offsets = vec!["UTC+00:15", "UTC+0015", "Z+00:15", "Z+0015"];
283+
let expected = format!("{}{}", Local::now().format("%Y%m%d"), "0000+0015");
284+
for offset in offsets {
285+
let actual = from_str(offset).unwrap();
286+
assert_eq!(expected, format!("{}", actual.format("%Y%m%d%H%M%z")));
287+
}
288+
}
289+
290+
#[test]
291+
fn invalid_offset_format() {
292+
let invalid_offsets = vec!["+0700", "UTC+2", "Z-1", "UTC+01005"];
293+
for offset in invalid_offsets {
294+
assert_eq!(from_str(offset), Err(ParseDurationError::InvalidInput));
295+
}
296+
}
297+
}
298+
246299
/// Used to test example code presented in the README.
247300
mod readme_test {
248301
use crate::parse_datetime::from_str;

0 commit comments

Comments
 (0)