@@ -277,6 +277,18 @@ pub fn spark_day(args: &[ColumnarValue]) -> Result<ColumnarValue> {
277277 ) ?) )
278278}
279279
280+ pub fn spark_last_day ( args : & [ ColumnarValue ] ) -> Result < ColumnarValue > {
281+ let input = resolve_local_date32 ( args) ?;
282+ let last_day = Date32Array :: from_iter ( input. iter ( ) . map ( |opt_days| {
283+ opt_days
284+ . and_then ( NaiveDate :: from_epoch_days)
285+ . and_then ( |date| date. with_day ( days_in_month ( date. year ( ) , date. month ( ) ) ) )
286+ . map ( |date| date. to_epoch_days ( ) )
287+ } ) ) ;
288+
289+ Ok ( ColumnarValue :: Array ( Arc :: new ( last_day) ) )
290+ }
291+
280292pub fn spark_make_date ( args : & [ ColumnarValue ] ) -> Result < ColumnarValue > {
281293 if args. len ( ) != 4 {
282294 return Err ( DataFusionError :: Execution (
@@ -595,6 +607,32 @@ mod tests {
595607 Ok ( ( ) )
596608 }
597609
610+ #[ test]
611+ fn test_spark_last_day ( ) -> Result < ( ) > {
612+ let date = |year, month, day| {
613+ NaiveDate :: from_ymd_opt ( year, month, day)
614+ . expect ( "test date must be valid" )
615+ . to_epoch_days ( )
616+ } ;
617+ let input = Arc :: new ( Date32Array :: from ( vec ! [
618+ Some ( date( 2009 , 1 , 12 ) ) ,
619+ Some ( date( 2024 , 2 , 10 ) ) ,
620+ Some ( date( 2023 , 2 , 10 ) ) ,
621+ Some ( date( 1969 , 12 , 1 ) ) ,
622+ None ,
623+ ] ) ) ;
624+ let args = vec ! [ ColumnarValue :: Array ( input) ] ;
625+ let expected_ret: ArrayRef = Arc :: new ( Date32Array :: from ( vec ! [
626+ Some ( date( 2009 , 1 , 31 ) ) ,
627+ Some ( date( 2024 , 2 , 29 ) ) ,
628+ Some ( date( 2023 , 2 , 28 ) ) ,
629+ Some ( date( 1969 , 12 , 31 ) ) ,
630+ None ,
631+ ] ) ) ;
632+ assert_eq ! ( & spark_last_day( & args) ?. into_array( 1 ) ?, & expected_ret) ;
633+ Ok ( ( ) )
634+ }
635+
598636 #[ test]
599637 fn test_spark_make_date_null_and_invalid_inputs ( ) -> Result < ( ) > {
600638 let result = spark_make_date ( & [
0 commit comments