11use crate :: { Error , Expr } ;
2- use jiff:: { Timestamp , ToSpan } ;
2+ use jiff:: { SignedDuration , Timestamp } ;
3+
4+ const DAY : SignedDuration = SignedDuration :: from_hours ( 24 ) ;
5+ const SHYOFADAY : SignedDuration = DAY . checked_sub ( SignedDuration :: from_nanos ( 1 ) ) . unwrap ( ) ;
6+
7+ fn strip_quotes ( s : String ) -> String {
8+ if ( s. starts_with ( '"' ) && s. ends_with ( '"' ) ) || ( s. starts_with ( '\'' ) && s. ends_with ( '\'' ) ) {
9+ s[ 1 ..s. len ( ) - 1 ] . to_string ( )
10+ } else {
11+ s
12+ }
13+ }
314
415/// Struct to hold a range of timestamps.
516#[ derive( Debug , Clone , PartialEq ) ]
@@ -13,21 +24,24 @@ impl TryFrom<Expr> for DateRange {
1324 fn try_from ( v : Expr ) -> Result < DateRange , Error > {
1425 match v {
1526 Expr :: Interval { interval } => {
16- let start_str: String = interval[ 0 ] . to_text ( ) ?;
17- let end_str: String = interval[ 1 ] . to_text ( ) ?;
27+ let start_str: String = strip_quotes ( interval[ 0 ] . to_text ( ) ?) ;
28+ let end_str: String = strip_quotes ( interval[ 1 ] . to_text ( ) ?) ;
1829 let start: Timestamp = start_str. parse ( ) . unwrap ( ) ;
1930 let end: Timestamp = end_str. parse ( ) . unwrap ( ) ;
2031 Ok ( DateRange { start, end } )
2132 }
2233 Expr :: Timestamp { timestamp } => {
23- let start_str: String = timestamp. to_text ( ) ?;
34+ let start_str: String = strip_quotes ( timestamp. to_text ( ) ?) ;
2435 let start: Timestamp = start_str. parse ( ) . unwrap ( ) ;
2536 Ok ( DateRange { start, end : start } )
2637 }
2738 Expr :: Date { date } => {
28- let start_str: String = date. to_text ( ) ?;
39+ let mut start_str: String = strip_quotes ( date. to_text ( ) ?) ;
40+ if start_str. len ( ) <= 11 {
41+ start_str = format ! ( "{start_str} 00Z" ) ;
42+ }
2943 let start: Timestamp = start_str. parse ( ) . unwrap ( ) ;
30- let end: Timestamp = start + 1 . day ( ) - 1 . nanosecond ( ) ;
44+ let end: Timestamp = start + SHYOFADAY ;
3145 Ok ( DateRange { start, end } )
3246 }
3347 Expr :: Literal ( v) => {
@@ -81,3 +95,17 @@ pub fn temporal_op(left_expr: Expr, right_expr: Expr, op: &str) -> Result<Expr,
8195 _ => Err ( Error :: OperationError ( ) ) ,
8296 }
8397}
98+
99+ #[ cfg( test) ]
100+ mod tests {
101+ use super :: DateRange ;
102+ use crate :: Expr ;
103+ use serde_json:: json;
104+
105+ #[ test]
106+ fn timestamp_math ( ) {
107+ // https://github.com/developmentseed/cql2-rs/issues/66
108+ let expr: Expr = serde_json:: from_value ( json ! ( { "date" : "2020-02-18" } ) ) . unwrap ( ) ;
109+ let _: DateRange = expr. try_into ( ) . unwrap ( ) ;
110+ }
111+ }
0 commit comments