28
28
29
29
use winnow:: {
30
30
ascii:: { alpha1, multispace1} ,
31
- combinator:: { alt, eof, opt, preceded, terminated, trace } ,
31
+ combinator:: { alt, eof, opt, preceded, terminated} ,
32
32
error:: ErrMode ,
33
33
stream:: AsChar ,
34
34
token:: take_while,
35
35
ModalResult , Parser ,
36
36
} ;
37
37
38
- use super :: primitive:: { ctx_err, dec_uint, s} ;
38
+ use super :: {
39
+ primitive:: { ctx_err, dec_uint, s} ,
40
+ year:: { year_from_str, year_str} ,
41
+ } ;
39
42
40
43
#[ derive( PartialEq , Eq , Clone , Debug , Default ) ]
41
44
pub struct Date {
@@ -50,40 +53,11 @@ impl TryFrom<(&str, u32, u32)> for Date {
50
53
/// Create a `Date` from a tuple of `(year, month, day)`.
51
54
///
52
55
/// Note: The `year` is represented as a `&str` to handle a specific GNU
53
- /// compatibility quirk. According to the GNU documentation: "if the year is
54
- /// 68 or smaller, then 2000 is added to it; otherwise, if year is less than
55
- /// 100, then 1900 is added to it." This adjustment only applies to
56
- /// two-digit year strings. For example, `"00"` is interpreted as `2000`,
57
- /// whereas `"0"`, `"000"`, or `"0000"` are interpreted as `0`.
56
+ /// compatibility quirk. See the comment in [`year`](super::year) for more
57
+ /// details.
58
58
fn try_from ( value : ( & str , u32 , u32 ) ) -> Result < Self , Self :: Error > {
59
59
let ( year_str, month, day) = value;
60
-
61
- let mut year = year_str
62
- . parse :: < u32 > ( )
63
- . map_err ( |_| "year must be a valid number" ) ?;
64
-
65
- // If year is 68 or smaller, then 2000 is added to it; otherwise, if year
66
- // is less than 100, then 1900 is added to it.
67
- //
68
- // GNU quirk: this only applies to two-digit years. For example,
69
- // "98-01-01" will be parsed as "1998-01-01", while "098-01-01" will be
70
- // parsed as "0098-01-01".
71
- if year_str. len ( ) == 2 {
72
- if year <= 68 {
73
- year += 2000
74
- } else {
75
- year += 1900
76
- }
77
- }
78
-
79
- // 2147485547 is the maximum value accepted by GNU, but chrono only
80
- // behaves like GNU for years in the range: [0, 9999], so we keep in the
81
- // range [0, 9999].
82
- //
83
- // See discussion in https://github.com/uutils/parse_datetime/issues/160.
84
- if year > 9999 {
85
- return Err ( "year must be no greater than 9999" ) ;
86
- }
60
+ let year = year_from_str ( year_str) ?;
87
61
88
62
if !( 1 ..=12 ) . contains ( & month) {
89
63
return Err ( "month must be between 1 and 12" ) ;
@@ -138,15 +112,8 @@ pub fn parse(input: &mut &str) -> ModalResult<Date> {
138
112
///
139
113
/// This is also used by [`combined`](super::combined).
140
114
pub fn iso1 ( input : & mut & str ) -> ModalResult < Date > {
141
- let ( year, _, month, _, day) = (
142
- // `year` must be a `&str`, see comment in `TryFrom` impl for `Date`.
143
- s ( take_while ( 1 .., AsChar :: is_dec_digit) ) ,
144
- s ( '-' ) ,
145
- s ( dec_uint) ,
146
- s ( '-' ) ,
147
- s ( dec_uint) ,
148
- )
149
- . parse_next ( input) ?;
115
+ let ( year, _, month, _, day) =
116
+ ( year_str, s ( '-' ) , s ( dec_uint) , s ( '-' ) , s ( dec_uint) ) . parse_next ( input) ?;
150
117
151
118
( year, month, day)
152
119
. try_into ( )
@@ -160,7 +127,6 @@ pub fn iso2(input: &mut &str) -> ModalResult<Date> {
160
127
let date_str = take_while ( 5 .., AsChar :: is_dec_digit) . parse_next ( input) ?;
161
128
let len = date_str. len ( ) ;
162
129
163
- // `year` must be a `&str`, see comment in `TryFrom` impl for `Date`.
164
130
let year = & date_str[ ..len - 4 ] ;
165
131
166
132
let month = date_str[ len - 4 ..len - 2 ]
@@ -226,7 +192,7 @@ fn literal1(input: &mut &str) -> ModalResult<Date> {
226
192
opt ( s ( '-' ) ) ,
227
193
s ( literal_month) ,
228
194
opt ( terminated (
229
- preceded ( opt ( s ( '-' ) ) , s ( take_while ( 1 .. , AsChar :: is_dec_digit ) ) ) ,
195
+ preceded ( opt ( s ( '-' ) ) , year_str ) ,
230
196
// The year must be followed by a space or end of input.
231
197
alt ( ( multispace1, eof) ) ,
232
198
) ) ,
@@ -254,7 +220,7 @@ fn literal2(input: &mut &str) -> ModalResult<Date> {
254
220
// space between the comma and the year. This is probably to
255
221
// distinguish with floats.
256
222
opt ( s ( terminated ( ',' , multispace1) ) ) ,
257
- s ( take_while ( 1 .. , AsChar :: is_dec_digit ) ) ,
223
+ year_str ,
258
224
) ,
259
225
// The year must be followed by a space or end of input.
260
226
alt ( ( multispace1, eof) ) ,
@@ -272,31 +238,6 @@ fn literal2(input: &mut &str) -> ModalResult<Date> {
272
238
}
273
239
}
274
240
275
- pub fn year ( input : & mut & str ) -> ModalResult < u32 > {
276
- // 2147485547 is the maximum value accepted
277
- // by GNU, but chrono only behaves like GNU
278
- // for years in the range: [0, 9999], so we
279
- // keep in the range [0, 9999]
280
- trace (
281
- "year" ,
282
- s (
283
- take_while ( 1 ..=4 , AsChar :: is_dec_digit) . map ( |number_str : & str | {
284
- let year = number_str. parse :: < u32 > ( ) . unwrap ( ) ;
285
- if number_str. len ( ) == 2 {
286
- if year <= 68 {
287
- year + 2000
288
- } else {
289
- year + 1900
290
- }
291
- } else {
292
- year
293
- }
294
- } ) ,
295
- ) ,
296
- )
297
- . parse_next ( input)
298
- }
299
-
300
241
/// Parse the name of a month (case-insensitive)
301
242
fn literal_month ( input : & mut & str ) -> ModalResult < u32 > {
302
243
s ( alpha1)
@@ -639,28 +580,4 @@ mod tests {
639
580
assert_eq ! ( parse( & mut s) . unwrap( ) , reference) ;
640
581
}
641
582
}
642
-
643
- #[ test]
644
- fn test_year ( ) {
645
- use super :: year;
646
-
647
- // the minimun input length is 2
648
- // assert!(year(&mut "0").is_err());
649
- // -> GNU accepts year 0
650
- // test $(date -d '1-1-1' '+%Y') -eq '0001'
651
-
652
- // test $(date -d '68-1-1' '+%Y') -eq '2068'
653
- // 2-characters are converted to 19XX/20XX
654
- assert_eq ! ( year( & mut "10" ) . unwrap( ) , 2010u32 ) ;
655
- assert_eq ! ( year( & mut "68" ) . unwrap( ) , 2068u32 ) ;
656
- assert_eq ! ( year( & mut "69" ) . unwrap( ) , 1969u32 ) ;
657
- assert_eq ! ( year( & mut "99" ) . unwrap( ) , 1999u32 ) ;
658
- // 3,4-characters are converted verbatim
659
- assert_eq ! ( year( & mut "468" ) . unwrap( ) , 468u32 ) ;
660
- assert_eq ! ( year( & mut "469" ) . unwrap( ) , 469u32 ) ;
661
- assert_eq ! ( year( & mut "1568" ) . unwrap( ) , 1568u32 ) ;
662
- assert_eq ! ( year( & mut "1569" ) . unwrap( ) , 1569u32 ) ;
663
- // consumes at most 4 characters from the input
664
- //assert_eq!(year(&mut "1234567").unwrap(), 1234u32);
665
- }
666
583
}
0 commit comments