Skip to content

Commit 850097d

Browse files
Pierre ChevalierPierre Chevalier
Pierre Chevalier
authored and
Pierre Chevalier
committed
feat: Expose parsing for Time
`gix_date::Time` can be parsed in two ways: * From raw bytes (in the data format Git adheres too) * From the date format used in gix config Add utility constructors for these two cases. When parsing from raw bytes, also support a format like `<sign><HH><MM><SS>` since this is a situation that happens in the wild and that Git can handle.
1 parent 65ffe81 commit 850097d

File tree

3 files changed

+44
-3
lines changed

3 files changed

+44
-3
lines changed

gix-date/src/lib.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ pub mod time;
1515

1616
///
1717
pub mod parse;
18+
use bstr::{BStr, ByteSlice};
1819
pub use parse::function::parse;
20+
use parse::function::parse_raw;
21+
use parse::Error;
22+
use std::time::SystemTime;
1923

2024
/// A timestamp with timezone.
2125
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
@@ -29,6 +33,19 @@ pub struct Time {
2933
pub sign: time::Sign,
3034
}
3135

36+
impl Time {
37+
/// Parse date in config format into a Time
38+
pub fn from_config(i: &BStr) -> Result<Self, Error> {
39+
let s = i.as_bstr().to_str().expect("Input must be ascii");
40+
parse(s, Some(SystemTime::now()))
41+
}
42+
/// Parse raw bytes into a Time
43+
pub fn from_bytes(i: &BStr) -> Result<Self, Error> {
44+
let s = i.as_bstr().to_str().expect("Input must be ascii");
45+
parse_raw(s).ok_or(Error::InvalidDateString { input: s.into() })
46+
}
47+
}
48+
3249
/// The amount of seconds since unix epoch.
3350
///
3451
/// Note that negative dates represent times before the unix epoch.

gix-date/src/parse.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ pub(crate) mod function {
6060
})
6161
}
6262

63-
fn parse_raw(input: &str) -> Option<Time> {
63+
pub(crate) fn parse_raw(input: &str) -> Option<Time> {
6464
let mut split = input.split_whitespace();
6565
let seconds: SecondsSinceUnixEpoch = split.next()?.parse().ok()?;
6666
let offset = split.next()?;
67-
if offset.len() != 5 || split.next().is_some() {
67+
if (offset.len() != 5) && (offset.len() != 7) || split.next().is_some() {
6868
return None;
6969
}
7070
let sign = match offset.get(..1)? {
@@ -74,7 +74,12 @@ pub(crate) mod function {
7474
}?;
7575
let hours: i32 = offset.get(1..3)?.parse().ok()?;
7676
let minutes: i32 = offset.get(3..5)?.parse().ok()?;
77-
let mut offset_in_seconds = hours * 3600 + minutes * 60;
77+
let offset_seconds: i32 = if offset.len() == 7 {
78+
offset.get(5..7)?.parse().ok()?
79+
} else {
80+
0
81+
};
82+
let mut offset_in_seconds = hours * 3600 + minutes * 60 + offset_seconds;
7883
if sign == Sign::Minus {
7984
offset_in_seconds *= -1;
8085
}

gix-date/tests/time/parse.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,24 @@ fn raw() {
7676
},
7777
);
7878

79+
assert_eq!(
80+
gix_date::parse("1313584730 +051800", None).unwrap(),
81+
Time {
82+
seconds: 1313584730,
83+
offset: 19080,
84+
sign: Sign::Plus,
85+
},
86+
);
87+
88+
assert_eq!(
89+
gix_date::parse("1313584730 +051842", None).unwrap(),
90+
Time {
91+
seconds: 1313584730,
92+
offset: 19122,
93+
sign: Sign::Plus,
94+
},
95+
);
96+
7997
let expected = Time {
8098
seconds: 1660874655,
8199
offset: -28800,
@@ -88,6 +106,7 @@ fn raw() {
88106
" 1660874655 -0800 ",
89107
" 1660874655 -0800 ",
90108
"1660874655\t-0800",
109+
"1660874655\t-080000",
91110
] {
92111
assert_eq!(gix_date::parse(date_str, None).unwrap(), expected);
93112
}

0 commit comments

Comments
 (0)