Skip to content

Commit 43b6c06

Browse files
committed
Draft.
1 parent 7b48297 commit 43b6c06

File tree

3 files changed

+76
-2
lines changed

3 files changed

+76
-2
lines changed

git-date/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ serde1 = ["serde", "bstr/serde1"]
1818
bstr = { version = "0.2.13", default-features = false, features = ["std"]}
1919
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]}
2020
itoa = "1.0.1"
21-
time = { version = "0.3.2", default-features = false, features = ["local-offset", "formatting", "macros"] }
21+
time = { version = "0.3.2", default-features = false, features = ["local-offset", "formatting", "macros", "parsing"] }
2222

2323
document-features = { version = "0.2.0", optional = true }
2424

git-date/src/parse.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,50 @@
1+
use crate::time::format::{RFC2822, SHORT};
12
use crate::Time;
3+
use time::{Date, OffsetDateTime};
24

35
#[allow(missing_docs)]
46
pub fn parse(input: &str) -> Option<Time> {
57
// TODO: actual implementation, this is just to not constantly fail
68
if input == "1979-02-26 18:30:00" {
79
Some(Time::new(42, 1800))
810
} else {
9-
None
11+
return if let Ok(val) = Date::parse(input, SHORT) {
12+
let val = val.with_hms(0, 0, 0).expect("date is in range").assume_utc();
13+
Some(Time::new(val.unix_timestamp() as u32, val.offset().whole_seconds()))
14+
} else if let Ok(val) = OffsetDateTime::parse(input, RFC2822) {
15+
Some(Time::new(val.unix_timestamp() as u32, val.offset().whole_seconds()))
16+
} else if let Some(val) = relative::parse(input) {
17+
Some(Time::new(val.unix_timestamp() as u32, val.offset().whole_seconds()))
18+
} else {
19+
None
20+
};
21+
}
22+
}
23+
24+
mod relative {
25+
use std::str::FromStr;
26+
use time::{Duration, OffsetDateTime};
27+
28+
pub(crate) fn parse(input: &str) -> Option<OffsetDateTime> {
29+
let split: Vec<&str> = input.split_whitespace().collect();
30+
if split.len() != 3 || *split.last().expect("slice has length 3") != "ago" {
31+
return None;
32+
}
33+
let multiplier = i64::from_str(split[0]).ok()?;
34+
let period = period_to_seconds(split[1])?;
35+
Some(OffsetDateTime::now_utc().checked_sub(Duration::seconds(multiplier * period))?)
36+
}
37+
38+
fn period_to_seconds(period: &str) -> Option<i64> {
39+
let period = period.strip_suffix("s").unwrap_or(period);
40+
return match period {
41+
"second" => Some(1),
42+
"minute" => Some(60),
43+
"hour" => Some(60 * 60),
44+
"day" => Some(24 * 60 * 60),
45+
"week" => Some(7 * 24 * 60 * 60),
46+
// TODO months & years
47+
_ => None,
48+
};
1049
}
1150
}

git-date/tests/time/parse.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use git_date::time::Sign;
22
use git_date::Time;
3+
use time::OffsetDateTime;
34

45
#[test]
56
fn special_time_is_ok_for_now() {
@@ -12,3 +13,37 @@ fn special_time_is_ok_for_now() {
1213
}
1314
);
1415
}
16+
17+
#[test]
18+
fn parse() {
19+
assert_eq!(
20+
git_date::parse("1979-02-26"),
21+
Some(Time {
22+
seconds_since_unix_epoch: 288835200,
23+
offset_in_seconds: 0,
24+
sign: Sign::Plus,
25+
}),
26+
"could not parse with SHORT format"
27+
);
28+
29+
assert_eq!(
30+
git_date::parse("Thu, 18 Aug 2022 12:45:06 +0800"),
31+
Some(Time {
32+
seconds_since_unix_epoch: 1660797906,
33+
offset_in_seconds: 28800,
34+
sign: Sign::Plus,
35+
}),
36+
"could not parse with RFC2822 format"
37+
);
38+
39+
let two_weeks_ago = git_date::parse("2 weeks ago").expect("valid time");
40+
assert_eq!(Sign::Plus, two_weeks_ago.sign);
41+
assert_eq!(0, two_weeks_ago.offset_in_seconds);
42+
assert_eq!(
43+
OffsetDateTime::from_unix_timestamp(two_weeks_ago.seconds_since_unix_epoch as i64)
44+
.expect("valid datetime")
45+
.iso_week(),
46+
OffsetDateTime::now_utc().iso_week() - 2,
47+
"weeks numbers differ"
48+
);
49+
}

0 commit comments

Comments
 (0)