Skip to content

Commit 7b2954d

Browse files
authored
Merge pull request #71 from baoyachi/chinese_unit
Supports parsing of Chinese time unit names
2 parents 0b8a9ca + 7d3f0a2 commit 7b2954d

File tree

5 files changed

+202
-5
lines changed

5 files changed

+202
-5
lines changed

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "duration-str"
3-
version = "0.16.1"
3+
version = "0.17.0"
44
authors = ["baoyachi <[email protected]>"]
55
edition = "2021"
66
description = "duration string parser"
@@ -17,6 +17,7 @@ default = ["chrono", "serde", "time", "calc"]
1717
lowercase = []
1818
no_calc = []
1919
calc = []
20+
cn_unit = []
2021

2122
[dependencies]
2223
thiserror = "2.0.0"
@@ -25,7 +26,7 @@ time = { version = "0.3.17", optional = true, default-features = false }
2526

2627
serde = { version = "1.0.147", features = ["derive"], optional = true }
2728
rust_decimal = { version = "1.29.1", default-features = false }
28-
winnow = "0.7.3"
29+
winnow = "0.7.4"
2930

3031
[dev-dependencies]
3132
serde_json = { version = "1.0.87" }

README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
## Features:
1818

1919
* 🚀 Strong compatibility, accommodating leading or trailing whitespaces in strings.
20+
* 🌏 Supports parsing of Chinese time unit names (requires the `cn_unit` feature)
2021
* 👍️ Offers [Playground](https://baoyachi.github.io/duration-str/) support for online debugging.
2122
* ⭐ Integrated with the [serde](https://docs.rs/serde) library.
2223
* 🎉 Supports parsing of various `Duration` types:
@@ -105,6 +106,60 @@ fn main() {
105106

106107
let duration = parse("1m * 1m").unwrap();
107108
assert_eq!(duration, Duration::new(3600, 0));
109+
110+
111+
// The following code requires the `cn_unit` feature.
112+
// Add it to your `Cargo.toml` like this:
113+
// duration-str = { version = "{latest version}", features = ["cn_unit"] }
114+
115+
let duration = parse("1年").unwrap();
116+
assert_eq!(duration, Duration::new(31536000, 0));
117+
118+
let duration = parse("1月").unwrap();
119+
assert_eq!(duration, Duration::new(2592000, 0));
120+
121+
let duration = parse("1周").unwrap();
122+
assert_eq!(duration, Duration::new(604800, 0));
123+
124+
let duration = parse("1日").unwrap();
125+
assert_eq!(duration, Duration::new(86400, 0));
126+
127+
let duration = parse("1天").unwrap();
128+
assert_eq!(duration, Duration::new(86400, 0));
129+
130+
let duration = parse("1时").unwrap();
131+
assert_eq!(duration, Duration::new(3600, 0));
132+
133+
let duration = parse("1分").unwrap();
134+
assert_eq!(duration, Duration::new(60, 0));
135+
136+
let duration = parse("1秒").unwrap();
137+
assert_eq!(duration, Duration::new(1, 0));
138+
139+
let duration = parse("1毫秒").unwrap();
140+
assert_eq!(duration, Duration::new(0, 1 * 1000 * 1000));
141+
142+
let duration = parse("1微秒").unwrap();
143+
assert_eq!(duration, Duration::new(0, 1 * 1000));
144+
145+
let duration = parse("1纳秒").unwrap();
146+
assert_eq!(duration, Duration::new(0, 1));
147+
148+
let duration = parse("1年 2日").unwrap();
149+
assert_eq!(duration, Duration::new(31708800, 0));
150+
151+
let duration = parse("1分31秒").unwrap();
152+
assert_eq!(duration, Duration::new(91, 0));
153+
154+
let duration = parse("1分+31秒").unwrap();
155+
assert_eq!(duration, Duration::new(91, 0));
156+
157+
let duration = parse("1分+31秒+2毫秒+3纳秒").unwrap();
158+
assert_eq!(duration, Duration::new(91, 2 * 1000 * 1000 + 3));
159+
160+
let duration = parse(" 1分+ 31秒 + 2毫秒+ 3纳秒 ").unwrap();
161+
assert_eq!(duration, Duration::new(91, 2 * 1000 * 1000 + 3));
162+
108163
}
109164
```
110165

playground/wasm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ crate-type = ["cdylib", "rlib"]
99

1010

1111
[dependencies]
12-
duration-str = { path = "../../"}
12+
duration-str = { path = "../../", features = ["cn_unit"] }
1313
serde-wasm-bindgen = "0.5"
1414
serde_json = "1.0.108"
1515
wasm-bindgen = "0.2.92"

src/parser.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,58 @@ mod tests {
191191
assert_eq!(duration, Duration::new(144, 0))
192192
}
193193

194+
#[cfg(feature = "cn_unit")]
195+
#[test]
196+
fn test_parse_unit_cn() {
197+
let duration = parse("1年").unwrap();
198+
assert_eq!(duration, Duration::new(31536000, 0));
199+
200+
let duration = parse("1月").unwrap();
201+
assert_eq!(duration, Duration::new(2592000, 0));
202+
203+
let duration = parse("1周").unwrap();
204+
assert_eq!(duration, Duration::new(604800, 0));
205+
206+
let duration = parse("1日").unwrap();
207+
assert_eq!(duration, Duration::new(86400, 0));
208+
209+
let duration = parse("1天").unwrap();
210+
assert_eq!(duration, Duration::new(86400, 0));
211+
212+
let duration = parse("1时").unwrap();
213+
assert_eq!(duration, Duration::new(3600, 0));
214+
215+
let duration = parse("1分").unwrap();
216+
assert_eq!(duration, Duration::new(60, 0));
217+
218+
let duration = parse("1秒").unwrap();
219+
assert_eq!(duration, Duration::new(1, 0));
220+
221+
let duration = parse("1毫秒").unwrap();
222+
assert_eq!(duration, Duration::new(0, 1 * 1000 * 1000));
223+
224+
let duration = parse("1微秒").unwrap();
225+
assert_eq!(duration, Duration::new(0, 1 * 1000));
226+
227+
let duration = parse("1纳秒").unwrap();
228+
assert_eq!(duration, Duration::new(0, 1));
229+
230+
let duration = parse("1年 2日").unwrap();
231+
assert_eq!(duration, Duration::new(31708800, 0));
232+
233+
let duration = parse("1分31秒").unwrap();
234+
assert_eq!(duration, Duration::new(91, 0));
235+
236+
let duration = parse("1分+31秒").unwrap();
237+
assert_eq!(duration, Duration::new(91, 0));
238+
239+
let duration = parse("1分+31秒+2毫秒+3纳秒").unwrap();
240+
assert_eq!(duration, Duration::new(91, 2 * 1000 * 1000 + 3));
241+
242+
let duration = parse(" 1分+ 31秒 + 2毫秒+ 3纳秒 ").unwrap();
243+
assert_eq!(duration, Duration::new(91, 2 * 1000 * 1000 + 3));
244+
}
245+
194246
#[test]
195247
fn test_duration_err() {
196248
assert_eq!(

src/unit.rs

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ impl Display for TimeUnit {
4747
}
4848

4949
impl TimeUnit {
50+
#[inline]
51+
#[cfg(feature = "cn_unit")]
52+
fn is_cn_unit(c: char) -> bool {
53+
[
54+
'年', '月', '周', '日', '天', '时', '分', '秒', '毫', '微', '纳',
55+
]
56+
.contains(&c)
57+
}
58+
5059
pub(crate) fn duration(&self, time_str: impl AsRef<str>) -> DResult<u64> {
5160
let time = time_str
5261
.as_ref()
@@ -93,7 +102,28 @@ impl FromStr for TimeUnit {
93102
"µs" | "µsec" | "µsecond" | "us" | "usec" | "usecond" | "microsecond"
94103
| "microseconds" => Ok(TimeUnit::MicroSecond),
95104
"ns" | "nsec" | "nanosecond" | "nanoseconds" => Ok(TimeUnit::NanoSecond),
96-
_ => Err(DError::ParseError(Self::expect_err(s))),
105+
106+
#[cfg(feature = "cn_unit")]
107+
"年" => Ok(TimeUnit::Year),
108+
#[cfg(feature = "cn_unit")]
109+
"月" => Ok(TimeUnit::Month),
110+
#[cfg(feature = "cn_unit")]
111+
"周" => Ok(TimeUnit::Week),
112+
#[cfg(feature = "cn_unit")]
113+
"日" | "天" => Ok(TimeUnit::Day),
114+
#[cfg(feature = "cn_unit")]
115+
"时" => Ok(TimeUnit::Hour),
116+
#[cfg(feature = "cn_unit")]
117+
"分" => Ok(TimeUnit::Minute),
118+
#[cfg(feature = "cn_unit")]
119+
"秒" => Ok(TimeUnit::Second),
120+
#[cfg(feature = "cn_unit")]
121+
"毫秒" => Ok(TimeUnit::MilliSecond),
122+
#[cfg(feature = "cn_unit")]
123+
"微秒" => Ok(TimeUnit::MicroSecond),
124+
#[cfg(feature = "cn_unit")]
125+
"纳秒" => Ok(TimeUnit::NanoSecond),
126+
_ => Err(DError::ParseError(Self::expect_err(case))),
97127
}
98128
}
99129
}
@@ -105,7 +135,17 @@ impl_expect_err!(
105135
);
106136

107137
pub(crate) fn unit_abbr1(input: &mut &str) -> WResult<TimeUnit> {
108-
take_while(1.., |c: char| c.is_alpha() || c == 'µ')
138+
let set = |c: char| c.is_alpha() || c == 'µ';
139+
let set = {
140+
#[cfg(feature = "cn_unit")]
141+
{
142+
move |c: char| set(c) || TimeUnit::is_cn_unit(c)
143+
}
144+
#[cfg(not(feature = "cn_unit"))]
145+
set
146+
};
147+
148+
take_while(1.., set)
109149
.parse_to()
110150
.context(StrContext::Expected(StrContextValue::Description(
111151
TimeUnit::get_expect_val(),
@@ -182,6 +222,55 @@ mod tests {
182222
);
183223
}
184224

225+
#[cfg(feature = "cn_unit")]
226+
#[test]
227+
fn test_time_cn_unit_abbr() {
228+
assert_eq!(
229+
unit_abbr1.parse_peek(&Partial::new("年")),
230+
Ok(("", TimeUnit::Year))
231+
);
232+
assert_eq!(
233+
unit_abbr1.parse_peek(&Partial::new("月")),
234+
Ok(("", TimeUnit::Month))
235+
);
236+
assert_eq!(
237+
unit_abbr1.parse_peek(&Partial::new("周")),
238+
Ok(("", TimeUnit::Week))
239+
);
240+
assert_eq!(
241+
unit_abbr1.parse_peek(&Partial::new("日")),
242+
Ok(("", TimeUnit::Day))
243+
);
244+
assert_eq!(
245+
unit_abbr1.parse_peek(&Partial::new("天")),
246+
Ok(("", TimeUnit::Day))
247+
);
248+
assert_eq!(
249+
unit_abbr1.parse_peek(&Partial::new("时")),
250+
Ok(("", TimeUnit::Hour))
251+
);
252+
assert_eq!(
253+
unit_abbr1.parse_peek(&Partial::new("分")),
254+
Ok(("", TimeUnit::Minute))
255+
);
256+
assert_eq!(
257+
unit_abbr1.parse_peek(&Partial::new("秒")),
258+
Ok(("", TimeUnit::Second))
259+
);
260+
assert_eq!(
261+
unit_abbr1.parse_peek(&Partial::new("毫秒")),
262+
Ok(("", TimeUnit::MilliSecond))
263+
);
264+
assert_eq!(
265+
unit_abbr1.parse_peek(&Partial::new("微秒")),
266+
Ok(("", TimeUnit::MicroSecond))
267+
);
268+
assert_eq!(
269+
unit_abbr1.parse_peek(&Partial::new("纳秒")),
270+
Ok(("", TimeUnit::NanoSecond))
271+
);
272+
}
273+
185274
#[test]
186275
fn test_time_unit() {
187276
let (input, format) = unit_abbr1.parse_peek("m123").unwrap();

0 commit comments

Comments
 (0)