Skip to content

Commit e7a8a52

Browse files
yuankunzhangcakebaker
authored andcommitted
feat: support leading zeros in timezone_colonless()
1 parent 0674254 commit e7a8a52

File tree

2 files changed

+19
-40
lines changed

2 files changed

+19
-40
lines changed

src/items/time.rs

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ use std::fmt::Display;
4141

4242
use chrono::FixedOffset;
4343
use winnow::{
44-
ascii::digit1,
4544
combinator::{alt, opt, peek, preceded},
4645
error::{ContextError, ErrMode, StrContext, StrContextValue},
4746
seq,
@@ -178,18 +177,18 @@ pub fn iso(input: &mut &str) -> ModalResult<Time> {
178177
///
179178
/// The hours are restricted to 12 or lower in this format
180179
fn am_pm_time(input: &mut &str) -> ModalResult<Time> {
181-
let (h, m, s, meridiem) = seq!(
180+
let (h, m, s, meridiem) = (
182181
hour12,
183182
opt(preceded(colon, minute)),
184183
opt(preceded(colon, second)),
185184
alt((
186185
s("am").value(Meridiem::Am),
187186
s("a.m.").value(Meridiem::Am),
188187
s("pm").value(Meridiem::Pm),
189-
s("p.m.").value(Meridiem::Pm)
188+
s("p.m.").value(Meridiem::Pm),
190189
)),
191190
)
192-
.parse_next(input)?;
191+
.parse_next(input)?;
193192

194193
if h == 0 {
195194
let mut ctx_err = ContextError::new();
@@ -288,14 +287,7 @@ fn timezone_num(input: &mut &str) -> ModalResult<Offset> {
288287
/// Parse a timezone offset with a colon separating hours and minutes
289288
fn timezone_colon(input: &mut &str) -> ModalResult<(u32, u32)> {
290289
seq!(
291-
s(take_while(1..=2, AsChar::is_dec_digit)).try_map(|x: &str| {
292-
// parse will fail on empty input
293-
if x.is_empty() {
294-
Ok(0)
295-
} else {
296-
x.parse()
297-
}
298-
}),
290+
s(take_while(1..=2, AsChar::is_dec_digit)).try_map(|x: &str| x.parse()),
299291
_: colon,
300292
s(take_while(1..=2, AsChar::is_dec_digit)).try_map(|x: &str| x.parse()),
301293
)
@@ -304,26 +296,21 @@ fn timezone_colon(input: &mut &str) -> ModalResult<(u32, u32)> {
304296

305297
/// Parse a timezone offset without colon
306298
fn timezone_colonless(input: &mut &str) -> ModalResult<(u32, u32)> {
307-
if let Ok(x) = peek(s(digit1::<&str, ContextError>)).parse_next(input) {
308-
if x.len() > 4 {
309-
let mut ctx_err = ContextError::new();
310-
ctx_err.push(StrContext::Expected(StrContextValue::Description(
311-
"timezone offset cannot be more than 4 digits",
312-
)));
313-
return Err(ErrMode::Cut(ctx_err));
314-
}
315-
}
316-
317-
// TODO: GNU date supports number strings with leading zeroes, e.g.,
318-
// `UTC+000001100` is valid.
319-
s(take_while(0..=4, AsChar::is_dec_digit))
320-
.verify_map(|x: &str| {
321-
Some(match x.len() {
299+
s(take_while(0.., AsChar::is_dec_digit))
300+
.verify_map(|s: &str| {
301+
// GNU date supports number strings with leading zeroes, e.g.,
302+
// `UTC+000001100` is valid.
303+
let s = if s.len() > 4 {
304+
s.trim_start_matches('0')
305+
} else {
306+
s
307+
};
308+
Some(match s.len() {
322309
0 => (0, 0),
323-
1 | 2 => (x.parse().ok()?, 0),
310+
1 | 2 => (s.parse().ok()?, 0),
324311
// The minutes are the last two characters here, for some reason.
325-
3 => (x[..1].parse().ok()?, x[1..].parse().ok()?),
326-
4 => (x[..2].parse().ok()?, x[2..].parse().ok()?),
312+
3 => (s[..1].parse().ok()?, s[1..].parse().ok()?),
313+
4 => (s[..2].parse().ok()?, s[2..].parse().ok()?),
327314
_ => return None,
328315
})
329316
})
@@ -852,6 +839,8 @@ mod tests {
852839

853840
assert_eq!("(0, 0)", aux(&mut "0000"));
854841
assert_eq!("(12, 34)", aux(&mut "1234"));
842+
assert_eq!("(12, 34)", aux(&mut "00001234"));
843+
assert!(timezone_colonless(&mut "12345").is_err());
855844
}
856845

857846
#[test]

src/lib.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,6 @@ mod tests {
222222
use chrono::{Local, NaiveDate};
223223

224224
use crate::parse_datetime;
225-
use crate::ParseDateTimeError;
226225

227226
#[test]
228227
fn test_positive_offsets() {
@@ -252,15 +251,6 @@ mod tests {
252251
}
253252
}
254253

255-
#[test]
256-
fn invalid_offset_format() {
257-
let offset = "UTC+01005";
258-
assert_eq!(
259-
parse_datetime(offset),
260-
Err(ParseDateTimeError::InvalidInput)
261-
);
262-
}
263-
264254
#[test]
265255
fn test_datetime_with_offset() {
266256
let actual = parse_datetime("1997-01-19 08:17:48 +2").unwrap();

0 commit comments

Comments
 (0)