1- use pg_interval:: PgInterval ;
1+ use pg_interval:: Interval ;
2+ use super :: parse_error:: ParseError ;
3+ use interval_norm:: IntervalNorm ;
24
3- impl PgInterval {
4- pub fn from_iso < T : Into < String > > ( iso_str : T ) -> PgInterval {
5- lazy_static ! {
6- static ref RE : Regex = Regex :: new( "P(?:(-?\d +?Y)?(-?\d +?M)?(-?\d +?D)?(?:T(-?\d +?H)?(-?\d +?M)?(-?\d +(?:[\. ,]\d {0,6})?S)?)?)$" ) . unwrap( ) ;
7- }
8- for interval in RE . captures_iter ( iso_str. into ( ) ) {
9- let year = caps. get ( 1 ) . unwrap_or ( "0" ) . as_str ( ) ;
10- let month = caps. get ( 2 ) . unwrap_or ( "0" ) . as_str ( ) ;
11- let day = caps. get ( 3 ) . unwrap_or ( "0" ) . as_str ( ) ;
12- let hours = caps. get ( 4 ) . unwrap_or ( "0" ) . as_str ( ) ;
13- let minutes = caps. get ( 5 ) . unwrap_or ( "0" ) . as_str ( ) ;
14- let seconds = caps. get ( 6 ) . unwrap_or ( "0.0" ) . as_str ( ) ;
5+ static DAYS_PER_MONTH : i32 = 30 ;
6+ static MONTHS_PER_YEAR : i32 = 12 ;
7+ static SECONDS_PER_MIN : i32 = 60 ;
8+ static HOURS_PER_DAY : i32 = 24 ;
9+ static MINUTES_PER_HOUR : i32 = 60 ;
10+ static MICROS_PER_SECOND : i32 = 1_000_000 ;
11+
12+
13+ enum ParserCode {
14+ BADFORMAT ,
15+ GOOD ,
16+ DELIMFOUND
17+ }
1518
19+ impl Interval {
20+ pub fn from_iso < ' a > ( iso_str : & ' a str ) -> Result < Interval , ParseError > {
21+ let mut date_part = true ;
22+ let delim = vec ! ( 'Y' , 'M' , 'D' , 'H' , 'S' ) ;
23+ let mut number = "" . to_owned ( ) ;
24+ let mut interval_norm = IntervalNorm :: default ( ) ;
25+ if iso_str. rfind ( 'P' ) . map_or ( false , |v| v == 1 ) {
26+ Err ( ParseError :: from_invalid_interval ( "Invalid format must start with P." ) )
27+ } else if iso_str. len ( ) < 2 {
28+ Err ( ParseError :: from_invalid_interval ( "Invalid format length is less than 2." ) )
29+ } else {
30+ for x in iso_str. chars ( ) {
31+ if x == 'P' {
32+ continue ;
33+ }
34+ if x == 'T' {
35+ date_part = false ;
36+ continue ;
37+ }
38+ let code = consume_number ( & x, & mut number, & delim) ;
39+ match code {
40+ ParserCode :: BADFORMAT => {
41+ return Err ( ParseError :: from_invalid_interval ( "Invalid format." ) ) ;
42+ } ,
43+ ParserCode :: GOOD => {
44+ continue ;
45+ } ,
46+ ParserCode :: DELIMFOUND => {
47+ let val = parse_number ( & mut number) ?;
48+ match x {
49+ 'Y' => {
50+ let ( year, month) = scale_date ( val, MONTHS_PER_YEAR ) ;
51+ interval_norm. years += year;
52+ interval_norm. months += month;
53+ } ,
54+ 'M' => {
55+ if date_part {
56+ let ( month, day) = scale_date ( val, DAYS_PER_MONTH ) ;
57+ interval_norm. months += month;
58+ interval_norm. days += day;
59+ } else {
60+ let ( minutes, seconds) = scale_time ( val, SECONDS_PER_MIN ) ;
61+ interval_norm. minutes += minutes;
62+ interval_norm. seconds += seconds;
63+ }
64+ } ,
65+ 'D' => {
66+ let ( days, hours) = scale_date ( val, HOURS_PER_DAY ) ;
67+ interval_norm. days += days;
68+ interval_norm. hours += hours as i64 ;
69+ } ,
70+ 'H' => {
71+ let ( hours, minutes) = scale_time ( val, MINUTES_PER_HOUR ) ;
72+ interval_norm. hours += hours;
73+ interval_norm. minutes += minutes;
74+ } ,
75+ 'S' => {
76+ let ( seconds, microseconds) = scale_time ( val, MICROS_PER_SECOND ) ;
77+ interval_norm. seconds += seconds;
78+ interval_norm. microseconds += microseconds;
79+ } ,
80+ _ => {
81+ return Err ( ParseError :: from_invalid_interval ( "Invalid format unknown delimiter." ) ) ;
82+ }
83+ }
84+ }
85+ }
1686 }
87+ interval_norm. try_into_interval ( )
88+ }
89+ }
90+ }
91+
92+ fn consume_number < ' a > (
93+ val : & ' a char ,
94+ number : & ' a mut String ,
95+ delim : & ' a Vec < char > ) -> ParserCode {
96+ if val. is_digit ( 10 ) {
97+ number. push ( * val) ;
98+ ParserCode :: GOOD
99+ } else if number. len ( ) == 0 && * val == '-' {
100+ number. push ( * val) ;
101+ ParserCode :: GOOD
102+ } else if number. len ( ) != 0 && * val == '.' {
103+ number. push ( * val) ;
104+ ParserCode :: GOOD
105+ } else if delim. contains ( & val) {
106+ ParserCode :: DELIMFOUND
107+ } else {
108+ ParserCode :: BADFORMAT
109+ }
110+ }
111+
112+ fn parse_number < ' a > ( number : & ' a mut String ) -> Result < f64 , ParseError > {
113+ let parse_num = number. parse :: < f64 > ( ) ?;
114+ if parse_num > i32:: max_value ( ) as f64 {
115+ Err ( ParseError :: from_invalid_interval ( "Exceeded max value" ) )
116+ } else {
117+ * number = "" . to_owned ( ) ;
118+ Ok ( parse_num)
119+ }
120+ }
121+
122+ fn scale_date ( val : f64 , scale : i32 ) -> ( i32 , i32 ) {
123+ if val. fract ( ) == 0.0 {
124+ return ( val. trunc ( ) as i32 , 0 )
125+ } else {
126+ // matches postgres implementation of just truncating.
127+ let sub_value = ( val. fract ( ) * scale as f64 ) as i32 ;
128+ ( val. trunc ( ) as i32 , sub_value)
129+ }
130+ }
131+
132+ fn scale_time ( val : f64 , scale : i32 ) -> ( i64 , i64 ) {
133+ if val. fract ( ) == 0.0 {
134+ return ( val. trunc ( ) as i64 , 0 )
135+ } else {
136+ // matches postgres implementation of just truncating.
137+ let sub_value = ( val. fract ( ) * scale as f64 ) as i64 ;
138+ ( val. trunc ( ) as i64 , sub_value)
139+ }
140+ }
141+
142+
143+ #[ cfg( test) ]
144+ mod tests {
145+ use pg_interval:: Interval ;
146+
147+ #[ test]
148+ fn test_iso_1 ( ) {
149+ let interval = Interval :: from_iso ( "P1Y" ) . unwrap ( ) ;
150+ let interval_exp = Interval :: new ( 12 , 0 , 0 ) ;
151+ assert_eq ! ( interval, interval_exp) ;
152+ }
153+
154+ /*
155+ #[test]
156+ fn test_8601_2() {
157+ let interval = Interval::new(13, 0, 0);
158+ let output = interval.to_iso_8601();
159+ assert_eq!(String::from("P1Y1M"), output);
160+ }
161+
162+ #[test]
163+ fn test_8601_3() {
164+ let interval = Interval::new(13, 1, 0);
165+ let output = interval.to_iso_8601();
166+ assert_eq!(String::from("P1Y1M1D"), output);
167+ }
168+
169+ #[test]
170+ fn test_8601_4() {
171+ let interval = Interval::new(13, 1, 3600000000);
172+ let output = interval.to_iso_8601();
173+ assert_eq!(String::from("P1Y1M1DT1H"), output);
174+ }
175+
176+ #[test]
177+ fn test_8601_5() {
178+ let interval = Interval::new(13, 1, 4200000000);
179+ let output = interval.to_iso_8601();
180+ assert_eq!(String::from("P1Y1M1DT1H10M"), output);
181+ }
182+
183+ #[test]
184+ fn test_8601_6() {
185+ let interval = Interval::new(13, 1, 4215000000);
186+ let output = interval.to_iso_8601();
187+ assert_eq!(String::from("P1Y1M1DT1H10M15S"), output);
17188 }
18- }
189+
190+ #[test]
191+ fn test_8601_7() {
192+ let interval = Interval::new(0, 0, 3600000000);
193+ let output = interval.to_iso_8601();
194+ assert_eq!(String::from("PT1H"), output);
195+ }
196+
197+ #[test]
198+ fn test_8601_8() {
199+ let interval = Interval::new(0, 0, 4200000000);
200+ let output = interval.to_iso_8601();
201+ assert_eq!(String::from("PT1H10M"), output);
202+ }
203+
204+ #[test]
205+ fn test_8601_9() {
206+ let interval = Interval::new(0, 0, 4215000000);
207+ let output = interval.to_iso_8601();
208+ assert_eq!(String::from("PT1H10M15S"), output);
209+ }
210+
211+ #[test]
212+ fn test_8601_10() {
213+ let interval = Interval::new(-12, 0, 0);
214+ let output = interval.to_iso_8601();
215+ assert_eq!(String::from("P-1Y"), output);
216+ }
217+
218+ #[test]
219+ fn test_8601_11() {
220+ let interval = Interval::new(-13, 0, 0);
221+ let output = interval.to_iso_8601();
222+ assert_eq!(String::from("P-1Y-1M"), output);
223+ }
224+
225+ #[test]
226+ fn test_8601_12() {
227+ let interval = Interval::new(-13, -1, 0);
228+ let output = interval.to_iso_8601();
229+ assert_eq!(String::from("P-1Y-1M-1D"), output);
230+ }
231+
232+ #[test]
233+ fn test_8601_13() {
234+ let interval = Interval::new(-13, -1, -3600000000);
235+ let output = interval.to_iso_8601();
236+ assert_eq!(String::from("P-1Y-1M-1DT-1H"), output);
237+ }
238+
239+ #[test]
240+ fn test_8601_14() {
241+ let interval = Interval::new(-13, -1, -4200000000);
242+ let output = interval.to_iso_8601();
243+ assert_eq!(String::from("P-1Y-1M-1DT-1H-10M"), output);
244+ }
245+
246+ #[test]
247+ fn test_8601_15() {
248+ let interval = Interval::new(-13, -1, -4215000000);
249+ let output = interval.to_iso_8601();
250+ assert_eq!(String::from("P-1Y-1M-1DT-1H-10M-15S"), output);
251+ }
252+
253+ #[test]
254+ fn test_8601_16() {
255+ let interval = Interval::new(0, 0, -3600000000);
256+ let output = interval.to_iso_8601();
257+ assert_eq!(String::from("PT-1H"), output);
258+ }
259+
260+ #[test]
261+ fn test_8601_17() {
262+ let interval = Interval::new(0, 0, -4200000000);
263+ let output = interval.to_iso_8601();
264+ assert_eq!(String::from("PT-1H-10M"), output);
265+ }
266+
267+ #[test]
268+ fn test_8601_18() {
269+ let interval = Interval::new(0, 0, -4215000000);
270+ let output = interval.to_iso_8601();
271+ assert_eq!(String::from("PT-1H-10M-15S"), output);
272+ } */
273+ }
0 commit comments