Skip to content

Commit 4fc189f

Browse files
committed
feat: add jiff and optimize date type sizes
1 parent 25f9e48 commit 4fc189f

File tree

5 files changed

+114
-42
lines changed

5 files changed

+114
-42
lines changed

Cargo.lock

Lines changed: 60 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ regex = "1.10.4"
1313
chrono = { version="0.4.38", default-features=false, features=["std", "alloc", "clock"] }
1414
winnow = "0.7.10"
1515
num-traits = "0.2.19"
16+
jiff = { version = "0.2.15", default-features = false, features = ["std"] }
1617

1718
[dev-dependencies]
1819
rstest = "0.26"

src/items/builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ impl DateTimeBuilder {
196196
if let Some(date::Date { year, month, day }) = self.date {
197197
dt = new_date(
198198
year.map(|x| x as i32).unwrap_or(dt.year()),
199-
month,
200-
day,
199+
month as u32,
200+
day as u32,
201201
dt.hour(),
202202
dt.minute(),
203203
dt.second(),

src/items/date.rs

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,21 @@ use super::{
4141
};
4242

4343
#[derive(PartialEq, Eq, Clone, Debug, Default)]
44-
pub struct Date {
45-
pub day: u32,
46-
pub month: u32,
47-
pub year: Option<u32>,
44+
pub(crate) struct Date {
45+
pub(crate) day: u8,
46+
pub(crate) month: u8,
47+
pub(crate) year: Option<u16>,
4848
}
4949

50-
impl TryFrom<(&str, u32, u32)> for Date {
50+
impl TryFrom<(&str, u8, u8)> for Date {
5151
type Error = &'static str;
5252

5353
/// Create a `Date` from a tuple of `(year, month, day)`.
5454
///
5555
/// Note: The `year` is represented as a `&str` to handle a specific GNU
5656
/// compatibility quirk. See the comment in [`year`](super::year) for more
5757
/// details.
58-
fn try_from(value: (&str, u32, u32)) -> Result<Self, Self::Error> {
58+
fn try_from(value: (&str, u8, u8)) -> Result<Self, Self::Error> {
5959
let (year_str, month, day) = value;
6060
let year = year_from_str(year_str)?;
6161

@@ -80,11 +80,11 @@ impl TryFrom<(&str, u32, u32)> for Date {
8080
}
8181
}
8282

83-
impl TryFrom<(u32, u32)> for Date {
83+
impl TryFrom<(u8, u8)> for Date {
8484
type Error = &'static str;
8585

8686
/// Create a `Date` from a tuple of `(month, day)`.
87-
fn try_from((month, day): (u32, u32)) -> Result<Self, Self::Error> {
87+
fn try_from((month, day): (u8, u8)) -> Result<Self, Self::Error> {
8888
if !(1..=12).contains(&month) {
8989
return Err("month must be between 1 and 12");
9090
}
@@ -104,14 +104,27 @@ impl TryFrom<(u32, u32)> for Date {
104104
}
105105
}
106106

107-
pub fn parse(input: &mut &str) -> ModalResult<Date> {
107+
impl TryFrom<Date> for jiff::civil::Date {
108+
type Error = &'static str;
109+
110+
fn try_from(date: Date) -> Result<Self, Self::Error> {
111+
jiff::civil::Date::new(
112+
date.year.unwrap_or(0) as i16,
113+
date.month as i8,
114+
date.day as i8,
115+
)
116+
.map_err(|_| "date is not valid")
117+
}
118+
}
119+
120+
pub(super) fn parse(input: &mut &str) -> ModalResult<Date> {
108121
alt((iso1, iso2, us, literal1, literal2)).parse_next(input)
109122
}
110123

111124
/// Parse `[year]-[month]-[day]`
112125
///
113126
/// This is also used by [`combined`](super::combined).
114-
pub fn iso1(input: &mut &str) -> ModalResult<Date> {
127+
pub(super) fn iso1(input: &mut &str) -> ModalResult<Date> {
115128
let (year, _, month, _, day) =
116129
(year_str, s('-'), s(dec_uint), s('-'), s(dec_uint)).parse_next(input)?;
117130

@@ -123,19 +136,13 @@ pub fn iso1(input: &mut &str) -> ModalResult<Date> {
123136
/// Parse `[year][month][day]`
124137
///
125138
/// This is also used by [`combined`](super::combined).
126-
pub fn iso2(input: &mut &str) -> ModalResult<Date> {
139+
pub(super) fn iso2(input: &mut &str) -> ModalResult<Date> {
127140
let date_str = take_while(5.., AsChar::is_dec_digit).parse_next(input)?;
128141
let len = date_str.len();
129142

130143
let year = &date_str[..len - 4];
131-
132-
let month = date_str[len - 4..len - 2]
133-
.parse::<u32>()
134-
.map_err(|_| ErrMode::Cut(ctx_err("month must be a valid number")))?;
135-
136-
let day = date_str[len - 2..]
137-
.parse::<u32>()
138-
.map_err(|_| ErrMode::Cut(ctx_err("day must be a valid number")))?;
144+
let month = month_from_str(&date_str[len - 4..len - 2])?;
145+
let day = day_from_str(&date_str[len - 2..])?;
139146

140147
(year, month, day)
141148
.try_into()
@@ -158,27 +165,21 @@ fn us(input: &mut &str) -> ModalResult<Date> {
158165
//
159166
// GNU quirk: interpret as [year]/[month]/[day] if the first part is at
160167
// least 4 characters long.
161-
let day = s2
162-
.parse::<u32>()
163-
.map_err(|_| ErrMode::Cut(ctx_err("day must be a valid number")))?;
168+
let day = day_from_str(s2)?;
164169
(s1, n, day)
165170
.try_into()
166171
.map_err(|e| ErrMode::Cut(ctx_err(e)))
167172
}
168173
Some(s2) => {
169174
// [month]/[day]/[year]
170-
let month = s1
171-
.parse::<u32>()
172-
.map_err(|_| ErrMode::Cut(ctx_err("month must be a valid number")))?;
175+
let month = month_from_str(s1)?;
173176
(s2, month, n)
174177
.try_into()
175178
.map_err(|e| ErrMode::Cut(ctx_err(e)))
176179
}
177180
None => {
178181
// [month]/[day]
179-
let month = s1
180-
.parse::<u32>()
181-
.map_err(|_| ErrMode::Cut(ctx_err("month must be a valid number")))?;
182+
let month = month_from_str(s1)?;
182183
(month, n).try_into().map_err(|e| ErrMode::Cut(ctx_err(e)))
183184
}
184185
}
@@ -239,7 +240,7 @@ fn literal2(input: &mut &str) -> ModalResult<Date> {
239240
}
240241

241242
/// Parse the name of a month (case-insensitive)
242-
fn literal_month(input: &mut &str) -> ModalResult<u32> {
243+
fn literal_month(input: &mut &str) -> ModalResult<u8> {
243244
s(alpha1)
244245
.verify_map(|s: &str| {
245246
Some(match s {
@@ -261,6 +262,16 @@ fn literal_month(input: &mut &str) -> ModalResult<u32> {
261262
.parse_next(input)
262263
}
263264

265+
fn month_from_str(s: &str) -> ModalResult<u8> {
266+
s.parse::<u8>()
267+
.map_err(|_| ErrMode::Cut(ctx_err("month must be a valid u8 number")))
268+
}
269+
270+
fn day_from_str(s: &str) -> ModalResult<u8> {
271+
s.parse::<u8>()
272+
.map_err(|_| ErrMode::Cut(ctx_err("day must be a valid u8 number")))
273+
}
274+
264275
#[cfg(test)]
265276
mod tests {
266277
use super::{parse, Date};

src/items/year.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ use winnow::{stream::AsChar, token::take_while, ModalResult, Parser};
1515
use super::primitive::s;
1616

1717
// TODO: Leverage `TryFrom` trait.
18-
pub(super) fn year_from_str(year_str: &str) -> Result<u32, &'static str> {
18+
pub(super) fn year_from_str(year_str: &str) -> Result<u16, &'static str> {
1919
let mut year = year_str
20-
.parse::<u32>()
21-
.map_err(|_| "year must be a valid number")?;
20+
.parse::<u16>()
21+
.map_err(|_| "year must be a valid u16 number")?;
2222

2323
// If year is 68 or smaller, then 2000 is added to it; otherwise, if year
2424
// is less than 100, then 1900 is added to it.
@@ -57,16 +57,16 @@ mod tests {
5757
#[test]
5858
fn test_year() {
5959
// 2-characters are converted to 19XX/20XX
60-
assert_eq!(year_from_str("10").unwrap(), 2010u32);
61-
assert_eq!(year_from_str("68").unwrap(), 2068u32);
62-
assert_eq!(year_from_str("69").unwrap(), 1969u32);
63-
assert_eq!(year_from_str("99").unwrap(), 1999u32);
60+
assert_eq!(year_from_str("10").unwrap(), 2010u16);
61+
assert_eq!(year_from_str("68").unwrap(), 2068u16);
62+
assert_eq!(year_from_str("69").unwrap(), 1969u16);
63+
assert_eq!(year_from_str("99").unwrap(), 1999u16);
6464

6565
// 3,4-characters are converted verbatim
66-
assert_eq!(year_from_str("468").unwrap(), 468u32);
67-
assert_eq!(year_from_str("469").unwrap(), 469u32);
68-
assert_eq!(year_from_str("1568").unwrap(), 1568u32);
69-
assert_eq!(year_from_str("1569").unwrap(), 1569u32);
66+
assert_eq!(year_from_str("468").unwrap(), 468u16);
67+
assert_eq!(year_from_str("469").unwrap(), 469u16);
68+
assert_eq!(year_from_str("1568").unwrap(), 1568u16);
69+
assert_eq!(year_from_str("1569").unwrap(), 1569u16);
7070

7171
// years greater than 9999 are not accepted
7272
assert!(year_from_str("10000").is_err());

0 commit comments

Comments
 (0)