1
1
use crate :: time:: format:: { DEFAULT , ISO8601 , ISO8601_STRICT , RFC2822 , SHORT } ;
2
2
use crate :: time:: Sign ;
3
3
use crate :: Time ;
4
+ use std:: num:: ParseIntError ;
4
5
use std:: str:: FromStr ;
5
6
use time:: { Date , OffsetDateTime } ;
6
7
8
+ #[ derive( thiserror:: Error , Debug ) ]
9
+ #[ allow( missing_docs) ]
10
+ pub enum Error {
11
+ #[ error( "Date string can not be parsed" ) ]
12
+ InvalidDateString ,
13
+ #[ error( "Timezone offset can not be parsed" ) ]
14
+ InvalidTzOffset ,
15
+ #[ error( "Relative period can not be parsed" ) ]
16
+ InvalidPeriod ,
17
+ #[ error( "Integer string can not be parsed" ) ]
18
+ InvalidInteger ( #[ from] ParseIntError ) ,
19
+ }
20
+
7
21
#[ allow( missing_docs) ]
8
22
pub fn parse ( input : & str ) -> Option < Time > {
9
23
// TODO: actual implementation, this is just to not constantly fail
@@ -27,24 +41,24 @@ pub fn parse(input: &str) -> Option<Time> {
27
41
} else if let Ok ( val) = parse_raw ( input) {
28
42
// Format::Raw
29
43
Some ( val)
30
- } else if let Some ( val) = relative:: parse ( input) {
44
+ } else if let Ok ( val) = relative:: parse ( input) {
31
45
Some ( Time :: new ( val. unix_timestamp ( ) as u32 , val. offset ( ) . whole_seconds ( ) ) )
32
46
} else {
33
47
None
34
48
} ;
35
49
}
36
50
}
37
51
38
- fn parse_raw ( input : & str ) -> Result < Time , ( ) > {
52
+ fn parse_raw ( input : & str ) -> Result < Time , Error > {
39
53
let mut split = input. split_whitespace ( ) ;
40
- let seconds_since_unix_epoch: u32 = split. next ( ) . ok_or ( ( ) ) ?. parse ( ) . map_err ( |_| ( ) ) ?;
41
- let offset = split. next ( ) . ok_or ( ( ) ) ?;
54
+ let seconds_since_unix_epoch: u32 = split. next ( ) . ok_or ( Error :: InvalidDateString ) ?. parse ( ) ?;
55
+ let offset = split. next ( ) . ok_or ( Error :: InvalidDateString ) ?;
42
56
if offset. len ( ) != 5 {
43
- return Err ( ( ) ) ;
57
+ return Err ( Error :: InvalidTzOffset ) ;
44
58
}
45
59
let sign = if & offset[ ..1 ] == "-" { Sign :: Plus } else { Sign :: Minus } ;
46
- let hours: i32 = offset[ 1 ..3 ] . parse ( ) . map_err ( |_| ( ) ) ?;
47
- let minutes: i32 = offset[ 3 ..5 ] . parse ( ) . map_err ( |_| ( ) ) ?;
60
+ let hours: i32 = offset[ 1 ..3 ] . parse ( ) ?;
61
+ let minutes: i32 = offset[ 3 ..5 ] . parse ( ) ?;
48
62
let offset_in_seconds = hours * 3600 + minutes * 60 ;
49
63
let time = Time {
50
64
seconds_since_unix_epoch,
@@ -55,29 +69,32 @@ fn parse_raw(input: &str) -> Result<Time, ()> {
55
69
}
56
70
57
71
mod relative {
72
+ use crate :: parse:: Error ;
58
73
use std:: str:: FromStr ;
59
74
use time:: { Duration , OffsetDateTime } ;
60
75
61
- pub ( crate ) fn parse ( input : & str ) -> Option < OffsetDateTime > {
76
+ pub ( crate ) fn parse ( input : & str ) -> Result < OffsetDateTime , Error > {
62
77
let mut split = input. split_whitespace ( ) ;
63
- let multiplier = i64:: from_str ( split. next ( ) ? ) . ok ( ) ?;
64
- let period = period_to_seconds ( split. next ( ) ?) ?;
65
- if split. next ( ) ? != "ago" {
66
- return None ;
78
+ let multiplier = i64:: from_str ( split. next ( ) . ok_or ( Error :: InvalidDateString ) ? ) ?;
79
+ let period = period_to_seconds ( split. next ( ) . ok_or ( Error :: InvalidDateString ) ?) ?;
80
+ if split. next ( ) . ok_or ( Error :: InvalidDateString ) ? != "ago" {
81
+ return Err ( Error :: InvalidDateString ) ;
67
82
}
68
- Some ( OffsetDateTime :: now_utc ( ) . checked_sub ( Duration :: seconds ( multiplier * period) ) ?)
83
+ Ok ( OffsetDateTime :: now_utc ( )
84
+ . checked_sub ( Duration :: seconds ( multiplier * period) )
85
+ . ok_or ( Error :: InvalidDateString ) ?)
69
86
}
70
87
71
- fn period_to_seconds ( period : & str ) -> Option < i64 > {
88
+ fn period_to_seconds ( period : & str ) -> Result < i64 , Error > {
72
89
let period = period. strip_suffix ( "s" ) . unwrap_or ( period) ;
73
90
return match period {
74
- "second" => Some ( 1 ) ,
75
- "minute" => Some ( 60 ) ,
76
- "hour" => Some ( 60 * 60 ) ,
77
- "day" => Some ( 24 * 60 * 60 ) ,
78
- "week" => Some ( 7 * 24 * 60 * 60 ) ,
91
+ "second" => Ok ( 1 ) ,
92
+ "minute" => Ok ( 60 ) ,
93
+ "hour" => Ok ( 60 * 60 ) ,
94
+ "day" => Ok ( 24 * 60 * 60 ) ,
95
+ "week" => Ok ( 7 * 24 * 60 * 60 ) ,
79
96
// TODO months & years
80
- _ => None ,
97
+ _ => Err ( Error :: InvalidPeriod ) ,
81
98
} ;
82
99
}
83
100
}
0 commit comments