@@ -10,6 +10,7 @@ use partiql_value::{
1010} ;
1111use regex:: { Regex , RegexBuilder } ;
1212use rust_decimal:: prelude:: FromPrimitive ;
13+ use rust_decimal:: RoundingStrategy ;
1314use std:: borrow:: { Borrow , Cow } ;
1415use std:: fmt:: Debug ;
1516
@@ -952,10 +953,10 @@ impl EvalExpr for EvalFnExtractYear {
952953 Null => Null ,
953954 Value :: DateTime ( dt) => match dt. as_ref ( ) {
954955 DateTime :: Date ( d) => Value :: from ( d. year ( ) ) ,
955- DateTime :: Timestamp ( tstamp) => Value :: from ( tstamp. year ( ) ) ,
956- DateTime :: TimestampWithTz ( tstamp) => Value :: from ( tstamp. year ( ) ) ,
957- DateTime :: Time ( _) => Missing ,
958- DateTime :: TimeWithTz ( _, _) => Missing ,
956+ DateTime :: Timestamp ( tstamp, _ ) => Value :: from ( tstamp. year ( ) ) ,
957+ DateTime :: TimestampWithTz ( tstamp, _ ) => Value :: from ( tstamp. year ( ) ) ,
958+ DateTime :: Time ( _, _ ) => Missing ,
959+ DateTime :: TimeWithTz ( _, _, _ ) => Missing ,
959960 } ,
960961 _ => Missing ,
961962 } ;
@@ -977,10 +978,10 @@ impl EvalExpr for EvalFnExtractMonth {
977978 Null => Null ,
978979 Value :: DateTime ( dt) => match dt. as_ref ( ) {
979980 DateTime :: Date ( d) => Value :: from ( d. month ( ) as u8 ) ,
980- DateTime :: Timestamp ( tstamp) => Value :: from ( tstamp. month ( ) as u8 ) ,
981- DateTime :: TimestampWithTz ( tstamp) => Value :: from ( tstamp. month ( ) as u8 ) ,
982- DateTime :: Time ( _) => Missing ,
983- DateTime :: TimeWithTz ( _, _) => Missing ,
981+ DateTime :: Timestamp ( tstamp, _ ) => Value :: from ( tstamp. month ( ) as u8 ) ,
982+ DateTime :: TimestampWithTz ( tstamp, _ ) => Value :: from ( tstamp. month ( ) as u8 ) ,
983+ DateTime :: Time ( _, _ ) => Missing ,
984+ DateTime :: TimeWithTz ( _, _, _ ) => Missing ,
984985 } ,
985986 _ => Missing ,
986987 } ;
@@ -1002,10 +1003,10 @@ impl EvalExpr for EvalFnExtractDay {
10021003 Null => Null ,
10031004 Value :: DateTime ( dt) => match dt. as_ref ( ) {
10041005 DateTime :: Date ( d) => Value :: from ( d. day ( ) ) ,
1005- DateTime :: Timestamp ( tstamp) => Value :: from ( tstamp. day ( ) ) ,
1006- DateTime :: TimestampWithTz ( tstamp) => Value :: from ( tstamp. day ( ) ) ,
1007- DateTime :: Time ( _) => Missing ,
1008- DateTime :: TimeWithTz ( _, _) => Missing ,
1006+ DateTime :: Timestamp ( tstamp, _ ) => Value :: from ( tstamp. day ( ) ) ,
1007+ DateTime :: TimestampWithTz ( tstamp, _ ) => Value :: from ( tstamp. day ( ) ) ,
1008+ DateTime :: Time ( _, _ ) => Missing ,
1009+ DateTime :: TimeWithTz ( _, _, _ ) => Missing ,
10091010 } ,
10101011 _ => Missing ,
10111012 } ;
@@ -1026,10 +1027,10 @@ impl EvalExpr for EvalFnExtractHour {
10261027 let result = match value. borrow ( ) {
10271028 Null => Null ,
10281029 Value :: DateTime ( dt) => match dt. as_ref ( ) {
1029- DateTime :: Time ( t) => Value :: from ( t. hour ( ) ) ,
1030- DateTime :: TimeWithTz ( t, _) => Value :: from ( t. hour ( ) ) ,
1031- DateTime :: Timestamp ( tstamp) => Value :: from ( tstamp. hour ( ) ) ,
1032- DateTime :: TimestampWithTz ( tstamp) => Value :: from ( tstamp. hour ( ) ) ,
1030+ DateTime :: Time ( t, _ ) => Value :: from ( t. hour ( ) ) ,
1031+ DateTime :: TimeWithTz ( t, _, _ ) => Value :: from ( t. hour ( ) ) ,
1032+ DateTime :: Timestamp ( tstamp, _ ) => Value :: from ( tstamp. hour ( ) ) ,
1033+ DateTime :: TimestampWithTz ( tstamp, _ ) => Value :: from ( tstamp. hour ( ) ) ,
10331034 DateTime :: Date ( _) => Missing ,
10341035 } ,
10351036 _ => Missing ,
@@ -1051,10 +1052,10 @@ impl EvalExpr for EvalFnExtractMinute {
10511052 let result = match value. borrow ( ) {
10521053 Null => Null ,
10531054 Value :: DateTime ( dt) => match dt. as_ref ( ) {
1054- DateTime :: Time ( t) => Value :: from ( t. minute ( ) ) ,
1055- DateTime :: TimeWithTz ( t, _) => Value :: from ( t. minute ( ) ) ,
1056- DateTime :: Timestamp ( tstamp) => Value :: from ( tstamp. minute ( ) ) ,
1057- DateTime :: TimestampWithTz ( tstamp) => Value :: from ( tstamp. minute ( ) ) ,
1055+ DateTime :: Time ( t, _ ) => Value :: from ( t. minute ( ) ) ,
1056+ DateTime :: TimeWithTz ( t, _, _ ) => Value :: from ( t. minute ( ) ) ,
1057+ DateTime :: Timestamp ( tstamp, _ ) => Value :: from ( tstamp. minute ( ) ) ,
1058+ DateTime :: TimestampWithTz ( tstamp, _ ) => Value :: from ( tstamp. minute ( ) ) ,
10581059 DateTime :: Date ( _) => Missing ,
10591060 } ,
10601061 _ => Missing ,
@@ -1069,10 +1070,17 @@ pub(crate) struct EvalFnExtractSecond {
10691070 pub ( crate ) value : Box < dyn EvalExpr > ,
10701071}
10711072
1072- fn total_seconds ( second : u8 , nanosecond : u32 ) -> Value {
1073+ fn total_seconds ( second : u8 , nanosecond : u32 , precision : Option < u32 > ) -> Value {
10731074 let result = rust_decimal:: Decimal :: from_f64 ( ( ( second as f64 * 1e9 ) + nanosecond as f64 ) / 1e9 )
10741075 . expect ( "time as decimal" ) ;
1075- Value :: from ( result)
1076+ match precision {
1077+ None => Value :: from ( result) ,
1078+ Some ( p) => {
1079+ // TODO: currently using `RoundingStrategy::MidpointAwayFromZero`, which follows what
1080+ // Kotlin does. Need to determine if this strategy is what we want or some configurability
1081+ Value :: from ( result. round_dp_with_strategy ( p, RoundingStrategy :: MidpointAwayFromZero ) )
1082+ }
1083+ }
10761084}
10771085
10781086impl EvalExpr for EvalFnExtractSecond {
@@ -1082,11 +1090,13 @@ impl EvalExpr for EvalFnExtractSecond {
10821090 let result = match value. borrow ( ) {
10831091 Null => Null ,
10841092 Value :: DateTime ( dt) => match dt. as_ref ( ) {
1085- DateTime :: Time ( t) => total_seconds ( t. second ( ) , t. nanosecond ( ) ) ,
1086- DateTime :: TimeWithTz ( t, _) => total_seconds ( t. second ( ) , t. nanosecond ( ) ) ,
1087- DateTime :: Timestamp ( tstamp) => total_seconds ( tstamp. second ( ) , tstamp. nanosecond ( ) ) ,
1088- DateTime :: TimestampWithTz ( tstamp) => {
1089- total_seconds ( tstamp. second ( ) , tstamp. nanosecond ( ) )
1093+ DateTime :: Time ( t, p) => total_seconds ( t. second ( ) , t. nanosecond ( ) , * p) ,
1094+ DateTime :: TimeWithTz ( t, p, _) => total_seconds ( t. second ( ) , t. nanosecond ( ) , * p) ,
1095+ DateTime :: Timestamp ( tstamp, p) => {
1096+ total_seconds ( tstamp. second ( ) , tstamp. nanosecond ( ) , * p)
1097+ }
1098+ DateTime :: TimestampWithTz ( tstamp, p) => {
1099+ total_seconds ( tstamp. second ( ) , tstamp. nanosecond ( ) , * p)
10901100 }
10911101 DateTime :: Date ( _) => Missing ,
10921102 } ,
@@ -1109,11 +1119,11 @@ impl EvalExpr for EvalFnExtractTimezoneHour {
11091119 let result = match value. borrow ( ) {
11101120 Null => Null ,
11111121 Value :: DateTime ( dt) => match dt. as_ref ( ) {
1112- DateTime :: TimeWithTz ( _, tz) => Value :: from ( tz. whole_hours ( ) ) ,
1113- DateTime :: TimestampWithTz ( tstamp) => Value :: from ( tstamp. offset ( ) . whole_hours ( ) ) ,
1122+ DateTime :: TimeWithTz ( _, _ , tz) => Value :: from ( tz. whole_hours ( ) ) ,
1123+ DateTime :: TimestampWithTz ( tstamp, _ ) => Value :: from ( tstamp. offset ( ) . whole_hours ( ) ) ,
11141124 DateTime :: Date ( _) => Missing ,
1115- DateTime :: Time ( _) => Missing ,
1116- DateTime :: Timestamp ( _) => Missing ,
1125+ DateTime :: Time ( _, _ ) => Missing ,
1126+ DateTime :: Timestamp ( _, _ ) => Missing ,
11171127 } ,
11181128 _ => Missing ,
11191129 } ;
@@ -1134,13 +1144,13 @@ impl EvalExpr for EvalFnExtractTimezoneMinute {
11341144 let result = match value. borrow ( ) {
11351145 Null => Null ,
11361146 Value :: DateTime ( dt) => match dt. as_ref ( ) {
1137- DateTime :: TimeWithTz ( _, tz) => Value :: from ( tz. minutes_past_hour ( ) ) ,
1138- DateTime :: TimestampWithTz ( tstamp) => {
1147+ DateTime :: TimeWithTz ( _, _ , tz) => Value :: from ( tz. minutes_past_hour ( ) ) ,
1148+ DateTime :: TimestampWithTz ( tstamp, _ ) => {
11391149 Value :: from ( tstamp. offset ( ) . minutes_past_hour ( ) )
11401150 }
11411151 DateTime :: Date ( _) => Missing ,
1142- DateTime :: Time ( _) => Missing ,
1143- DateTime :: Timestamp ( _) => Missing ,
1152+ DateTime :: Time ( _, _ ) => Missing ,
1153+ DateTime :: Timestamp ( _, _ ) => Missing ,
11441154 } ,
11451155 _ => Missing ,
11461156 } ;
0 commit comments