This is an automated email from the ASF dual-hosted git repository.

kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 2bb6be1d33 GH-37367: [MATLAB] Add `arrow.array.Date32Array` class 
(#37445)
2bb6be1d33 is described below

commit 2bb6be1d337583678b0661a8ecfcb2b0f3291a02
Author: Kevin Gurney <[email protected]>
AuthorDate: Tue Aug 29 20:22:49 2023 -0400

    GH-37367: [MATLAB] Add `arrow.array.Date32Array` class (#37445)
    
    ### Rationale for this change
    
    Now that `arrow.type.Date32Type` class has been added to the MATLAB 
Interface (#37348), we can add the `arrow.array.Date32Array` class.
    
    `Date32Array`s can be created from MATLAB 
[`datetime`](https://www.mathworks.com/help/matlab/ref/datetime.html) values.
    
    ### What changes are included in this PR?
    
    1. Added a new `arrow.array.Date32Array` class.
    2. Added a new `arrow.type.traits.Date32Traits` class.
    3. Added `arrow.type.Date32Type` support to `arrow.type.traits.traits` 
function.
    4. Fixed typo `arrray` in `tTime32Array` test class.
    5. Fixed bug in `numeric_array.h` where the `CType` rather than the 
`ArrowType` was being used to determine the `DataType` of an array class that 
is a `NumericArray<T>`.
    
    `Date32Array`s can be created from MATLAB 
[`datetime`](https://www.mathworks.com/help/matlab/ref/datetime.html) values 
using the `fromMATLAB` method. `Date32Array`s can be converted to MATLAB 
`datetime` values using the `toMATLAB` method.
    
    **Example**
    ```matlab
    >> dates = [datetime(2021, 1, 2, 3, 4, 5), datetime(2023, 1, 1), 
datetime(1989, 2, 3, 10, 10, 10)]'
    
    dates =
    
      3x1 datetime array
    
       02-Jan-2021 03:04:05
       01-Jan-2023 00:00:00
       03-Feb-1989 10:10:10
    
    >> array = arrow.array.Date32Array.fromMATLAB(dates)
    
    array =
    
    [
      2021-01-02,
      2023-01-01,
      1989-02-03
    ]
    
    >> array.toMATLAB()
    
    ans =
    
      3x1 datetime array
    
       02-Jan-2021
       01-Jan-2023
       03-Feb-1989
    ```
    
    ### Are these changes tested?
    
    Yes.
    
    1. Added a new `tDate32Array` test class.
    2. Added `Date32` related test to `ttraits.m`.
    6. Added a new `tDate32Traits.m` test class.
    
    ### Are there any user-facing changes?
    
    Yes.
    
    1. Users can now create `arrow.array.Date32Array`s  from MATLAB `datetime`s.
    
    ### Future Directions
    
    1. #37230
    2. Add `arrow.array.Date64Array`.
    3. Add a way to extract the raw `int32` values from an 
`arrow.array.Date32Array` without converting to a MATLAB `datetime` using 
`toMATLAB`.
    
    ### Notes
    
    1. Thank you @ sgilmore10 for your help with this pull request!
    * Closes: #37367
    
    Lead-authored-by: Kevin Gurney <[email protected]>
    Co-authored-by: Sarah Gilmore <[email protected]>
    Signed-off-by: Sutou Kouhei <[email protected]>
---
 .../cpp/arrow/matlab/array/proxy/numeric_array.h   |   2 +-
 matlab/src/cpp/arrow/matlab/array/proxy/wrap.cc    |   2 +
 matlab/src/cpp/arrow/matlab/proxy/factory.cc       |   1 +
 matlab/src/cpp/arrow/matlab/type/proxy/traits.h    |   6 +
 matlab/src/cpp/arrow/matlab/type/proxy/wrap.cc     |   3 +
 matlab/src/matlab/+arrow/+array/Date32Array.m      |  92 +++++++
 .../+test/+tabular/createAllSupportedArrayTypes.m  |  11 +-
 .../src/matlab/+arrow/+type/+traits/Date32Traits.m |  30 +++
 matlab/src/matlab/+arrow/+type/+traits/traits.m    |   2 +
 matlab/test/arrow/array/tDate32Array.m             | 295 +++++++++++++++++++++
 matlab/test/arrow/array/tTime32Array.m             |   8 +-
 matlab/test/arrow/type/traits/tDate32Traits.m      |  33 +++
 matlab/test/arrow/type/traits/ttraits.m            |  14 +-
 13 files changed, 492 insertions(+), 7 deletions(-)

diff --git a/matlab/src/cpp/arrow/matlab/array/proxy/numeric_array.h 
b/matlab/src/cpp/arrow/matlab/array/proxy/numeric_array.h
index 9c81d5ff62..f9da38dbaa 100644
--- a/matlab/src/cpp/arrow/matlab/array/proxy/numeric_array.h
+++ b/matlab/src/cpp/arrow/matlab/array/proxy/numeric_array.h
@@ -56,7 +56,7 @@ class NumericArray : public 
arrow::matlab::array::proxy::Array {
             
             auto data_buffer = std::make_shared<MatlabBuffer>(numeric_mda);
 
-            const auto data_type = arrow::CTypeTraits<CType>::type_singleton();
+            const auto data_type = 
arrow::TypeTraits<ArrowType>::type_singleton();
             const auto length = 
static_cast<int64_t>(numeric_mda.getNumberOfElements()); // cast size_t to 
int64_t
 
             // Pack the validity bitmap values.
diff --git a/matlab/src/cpp/arrow/matlab/array/proxy/wrap.cc 
b/matlab/src/cpp/arrow/matlab/array/proxy/wrap.cc
index 3d1881a7df..104eecbb4f 100644
--- a/matlab/src/cpp/arrow/matlab/array/proxy/wrap.cc
+++ b/matlab/src/cpp/arrow/matlab/array/proxy/wrap.cc
@@ -55,6 +55,8 @@ namespace arrow::matlab::array::proxy {
                 return 
std::make_shared<proxy::NumericArray<arrow::Time32Type>>(std::static_pointer_cast<arrow::Time32Array>(array));
             case ID::TIME64:
                 return 
std::make_shared<proxy::NumericArray<arrow::Time64Type>>(std::static_pointer_cast<arrow::Time64Array>(array));
+            case ID::DATE32:
+                return 
std::make_shared<proxy::NumericArray<arrow::Date32Type>>(std::static_pointer_cast<arrow::Date32Array>(array));
             case ID::STRING:
                 return 
std::make_shared<proxy::StringArray>(std::static_pointer_cast<arrow::StringArray>(array));
             default:
diff --git a/matlab/src/cpp/arrow/matlab/proxy/factory.cc 
b/matlab/src/cpp/arrow/matlab/proxy/factory.cc
index 7a84810c5a..0ad8d52cd5 100644
--- a/matlab/src/cpp/arrow/matlab/proxy/factory.cc
+++ b/matlab/src/cpp/arrow/matlab/proxy/factory.cc
@@ -54,6 +54,7 @@ libmexclass::proxy::MakeResult Factory::make_proxy(const 
ClassName& class_name,
     REGISTER_PROXY(arrow.array.proxy.TimestampArray, 
arrow::matlab::array::proxy::NumericArray<arrow::TimestampType>);
     REGISTER_PROXY(arrow.array.proxy.Time32Array   , 
arrow::matlab::array::proxy::NumericArray<arrow::Time32Type>);
     REGISTER_PROXY(arrow.array.proxy.Time64Array   , 
arrow::matlab::array::proxy::NumericArray<arrow::Time64Type>);
+    REGISTER_PROXY(arrow.array.proxy.Date32Array   , 
arrow::matlab::array::proxy::NumericArray<arrow::Date32Type>);
     REGISTER_PROXY(arrow.tabular.proxy.RecordBatch , 
arrow::matlab::tabular::proxy::RecordBatch);
     REGISTER_PROXY(arrow.tabular.proxy.Schema      , 
arrow::matlab::tabular::proxy::Schema);
     REGISTER_PROXY(arrow.type.proxy.Field          , 
arrow::matlab::type::proxy::Field);
diff --git a/matlab/src/cpp/arrow/matlab/type/proxy/traits.h 
b/matlab/src/cpp/arrow/matlab/type/proxy/traits.h
index fdae911062..a4c5d06f8f 100644
--- a/matlab/src/cpp/arrow/matlab/type/proxy/traits.h
+++ b/matlab/src/cpp/arrow/matlab/type/proxy/traits.h
@@ -23,6 +23,7 @@
 #include "arrow/matlab/type/proxy/timestamp_type.h"
 #include "arrow/matlab/type/proxy/time32_type.h"
 #include "arrow/matlab/type/proxy/time64_type.h"
+#include "arrow/matlab/type/proxy/date32_type.h"
 #include "arrow/matlab/type/proxy/string_type.h"
 
 namespace arrow::matlab::type::proxy {
@@ -99,4 +100,9 @@ namespace arrow::matlab::type::proxy {
     struct Traits<arrow::Time64Type> {
         using TypeProxy = Time64Type;
     };
+
+    template <>
+    struct Traits<arrow::Date32Type> {
+        using TypeProxy = Date32Type;
+    };
 }
diff --git a/matlab/src/cpp/arrow/matlab/type/proxy/wrap.cc 
b/matlab/src/cpp/arrow/matlab/type/proxy/wrap.cc
index efb510e897..7dfdf58e1d 100644
--- a/matlab/src/cpp/arrow/matlab/type/proxy/wrap.cc
+++ b/matlab/src/cpp/arrow/matlab/type/proxy/wrap.cc
@@ -21,6 +21,7 @@
 #include "arrow/matlab/type/proxy/timestamp_type.h"
 #include "arrow/matlab/type/proxy/time32_type.h"
 #include "arrow/matlab/type/proxy/time64_type.h"
+#include "arrow/matlab/type/proxy/date32_type.h"
 #include "arrow/matlab/type/proxy/string_type.h"
 
 namespace arrow::matlab::type::proxy {
@@ -56,6 +57,8 @@ namespace arrow::matlab::type::proxy {
                 return 
std::make_shared<Time32Type>(std::static_pointer_cast<arrow::Time32Type>(type));
             case ID::TIME64:
                 return 
std::make_shared<Time64Type>(std::static_pointer_cast<arrow::Time64Type>(type));
+            case ID::DATE32:
+                return 
std::make_shared<Date32Type>(std::static_pointer_cast<arrow::Date32Type>(type));
             case ID::STRING:
                 return 
std::make_shared<StringType>(std::static_pointer_cast<arrow::StringType>(type));
             default:
diff --git a/matlab/src/matlab/+arrow/+array/Date32Array.m 
b/matlab/src/matlab/+arrow/+array/Date32Array.m
new file mode 100644
index 0000000000..a462bd4f85
--- /dev/null
+++ b/matlab/src/matlab/+arrow/+array/Date32Array.m
@@ -0,0 +1,92 @@
+% arrow.array.Date32Array
+
+% Licensed to the Apache Software Foundation (ASF) under one or more
+% contributor license agreements.  See the NOTICE file distributed with
+% this work for additional information regarding copyright ownership.
+% The ASF licenses this file to you under the Apache License, Version
+% 2.0 (the "License"); you may not use this file except in compliance
+% with the License.  You may obtain a copy of the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS,
+% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+% implied.  See the License for the specific language governing
+% permissions and limitations under the License.
+
+classdef Date32Array < arrow.array.Array
+
+    properties(Access=private)
+        NullSubstitutionValue = NaT
+    end
+
+    methods
+
+        function obj = Date32Array(proxy)
+            arguments
+                proxy(1, 1) libmexclass.proxy.Proxy {validate(proxy, 
"arrow.array.proxy.Date32Array")}
+            end
+            import arrow.internal.proxy.validate
+            [email protected](proxy);
+        end
+
+        function dates = toMATLAB(obj)
+            import arrow.type.DateUnit
+
+            matlabArray = obj.Proxy.toMATLAB();
+            % UNIX Epoch (January 1st, 1970).
+            unixEpoch = datetime(0, ConvertFrom="posixtime");
+            % A Date32 value encodes a certain number of whole days
+            % before or after the UNIX Epoch.
+            dates = unixEpoch + days(matlabArray);
+            dates(~obj.Valid) = obj.NullSubstitutionValue;
+        end
+
+        function dates = datetime(obj)
+            dates = obj.toMATLAB();
+        end
+
+    end
+
+    methods(Static)
+
+        function array = fromMATLAB(data, opts)
+            arguments
+                data
+                opts.InferNulls(1, 1) logical = true
+                opts.Valid
+            end
+
+            import arrow.array.Date32Array
+
+            arrow.internal.validate.type(data, "datetime");
+            arrow.internal.validate.shape(data);
+
+            validElements = arrow.internal.validate.parseValidElements(data, 
opts);
+
+            % If the input MATLAB datetime array is zoned (i.e. has a 
TimeZone),
+            % then the datetime representing the UNIX Epoch must also have a 
TimeZone.
+            if ~isempty(data.TimeZone)
+                unixEpoch = datetime(0, ConvertFrom="posixtime", 
TimeZone="UTC");
+            else
+                unixEpoch = datetime(0, ConvertFrom="posixtime");
+            end
+
+            % Explicitly round down (i.e. floor) to the nearest whole number
+            % of days because durations and datetimes are not guaranteed
+            % to encode "whole" number dates / times (e.g. 1.5 days is a valid 
duration)
+            % and the int32 function rounds to the nearest whole number.
+            % Rounding to the nearest whole number without flooring first 
would result in a
+            % "round up error" of 1 whole day in cases where the fractional 
part of
+            % the duration is large enough to result in rounding up (e.g. 1.5 
days would
+            % become 2 days).
+            numDays = int32(floor(days(data - unixEpoch)));
+            args = struct(MatlabArray=numDays, Valid=validElements);
+            proxy = 
arrow.internal.proxy.create("arrow.array.proxy.Date32Array", args);
+            array = Date32Array(proxy);
+        end
+
+    end
+
+end
diff --git 
a/matlab/src/matlab/+arrow/+internal/+test/+tabular/createAllSupportedArrayTypes.m
 
b/matlab/src/matlab/+arrow/+internal/+test/+tabular/createAllSupportedArrayTypes.m
index 15ee0589d5..6eb930271b 100644
--- 
a/matlab/src/matlab/+arrow/+internal/+test/+tabular/createAllSupportedArrayTypes.m
+++ 
b/matlab/src/matlab/+arrow/+internal/+test/+tabular/createAllSupportedArrayTypes.m
@@ -32,6 +32,7 @@ function [arrowArrays, matlabData] = 
createAllSupportedArrayTypes(opts)
     matlabData  = cell(numClasses, 1);
     
     timeClasses = getTimeArrayClasses();
+    dateClasses = getDateArrayClasses();
     numericArrayToMatlabTypeDict = getNumericArrayToMatlabDictionary();
 
     for ii = 1:numel(classes)
@@ -54,6 +55,10 @@ function [arrowArrays, matlabData] = 
createAllSupportedArrayTypes(opts)
             matlabData{ii} = randomDurations(opts.NumRows);
             cmd = compose("%s.fromMATLAB(matlabData{ii})", name);
             arrowArrays{ii} = eval(cmd);
+        elseif ismember(name, dateClasses)
+            matlabData{ii} = randomDatetimes(opts.NumRows);
+            cmd = compose("%s.fromMATLAB(matlabData{ii})", name);
+            arrowArrays{ii} = eval(cmd);
         else
             error("arrow:test:SupportedArrayCase", ...
                 "Missing if-branch for array class " + name); 
@@ -86,6 +91,10 @@ function timeClasses = getTimeArrayClasses()
     timeClasses = compose("arrow.array.Time%dArray", [32 64]);
 end
 
+function dateClasses = getDateArrayClasses()
+    dateClasses = compose("arrow.array.Date%dArray", 32);
+end
+
 function number = randomNumbers(numberType, numElements)
     number = cast(randi(255, [numElements 1]), numberType);
 end
@@ -107,4 +116,4 @@ end
 function dates = randomDatetimes(numElements)
     day = days(randi(255, [numElements 1]));
     dates = datetime(2023, 8, 23) + day;
-end
\ No newline at end of file
+end
diff --git a/matlab/src/matlab/+arrow/+type/+traits/Date32Traits.m 
b/matlab/src/matlab/+arrow/+type/+traits/Date32Traits.m
new file mode 100644
index 0000000000..867e81fb27
--- /dev/null
+++ b/matlab/src/matlab/+arrow/+type/+traits/Date32Traits.m
@@ -0,0 +1,30 @@
+% Licensed to the Apache Software Foundation (ASF) under one or more
+% contributor license agreements.  See the NOTICE file distributed with
+% this work for additional information regarding copyright ownership.
+% The ASF licenses this file to you under the Apache License, Version
+% 2.0 (the "License"); you may not use this file except in compliance
+% with the License.  You may obtain a copy of the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS,
+% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+% implied.  See the License for the specific language governing
+% permissions and limitations under the License.
+
+classdef Date32Traits < arrow.type.traits.TypeTraits
+
+    properties (Constant)
+        ArrayConstructor = @arrow.array.Date32Array
+        ArrayClassName = "arrow.array.Date32Array"
+        ArrayProxyClassName = "arrow.array.proxy.Date32Array"
+        ArrayStaticConstructor = @arrow.array.Date32Array.fromMATLAB
+        TypeConstructor = @arrow.type.Date32Type;
+        TypeClassName = "arrow.type.Date32Type"
+        TypeProxyClassName = "arrow.type.proxy.Date32Type"
+        MatlabConstructor = @datetime
+        MatlabClassName = "datetime"
+    end
+
+end
diff --git a/matlab/src/matlab/+arrow/+type/+traits/traits.m 
b/matlab/src/matlab/+arrow/+type/+traits/traits.m
index e7c7f9b327..b1f6193a3e 100644
--- a/matlab/src/matlab/+arrow/+type/+traits/traits.m
+++ b/matlab/src/matlab/+arrow/+type/+traits/traits.m
@@ -52,6 +52,8 @@ function typeTraits = traits(type)
                 typeTraits = Time32Traits();
             case ID.Time64
                 typeTraits = Time64Traits();
+            case ID.Date32
+                typeTraits = Date32Traits();
             otherwise
                 error("arrow:type:traits:UnsupportedArrowTypeID", "Unsupported 
Arrow type ID: " + type);
         end
diff --git a/matlab/test/arrow/array/tDate32Array.m 
b/matlab/test/arrow/array/tDate32Array.m
new file mode 100644
index 0000000000..a5fc1c1b64
--- /dev/null
+++ b/matlab/test/arrow/array/tDate32Array.m
@@ -0,0 +1,295 @@
+%TDATE32ARRAY Unit tests for arrow.array.Date32Array
+
+% Licensed to the Apache Software Foundation (ASF) under one or more
+% contributor license agreements.  See the NOTICE file distributed with
+% this work for additional information regarding copyright ownership.
+% The ASF licenses this file to you under the Apache License, Version
+% 2.0 (the "License"); you may not use this file except in compliance
+% with the License.  You may obtain a copy of the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS,
+% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+% implied.  See the License for the specific language governing
+% permissions and limitations under the License.
+
+classdef tDate32Array < matlab.unittest.TestCase
+
+    properties
+        ArrowArrayConstructorFcn = @arrow.array.Date32Array.fromMATLAB
+    end
+
+    properties (Constant)
+        UnixEpoch = datetime(0, ConvertFrom="posixtime");
+        MissingDates = [datetime(2023, 1, 1), NaT, NaT, datetime(2022, 1, 1), 
NaT];
+    end
+
+    methods (Test)
+
+        function TestBasic(testCase)
+            dates = testCase.UnixEpoch + days(1:10);
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            testCase.verifyInstanceOf(array, "arrow.array.Date32Array");
+        end
+
+        function TestTypeIsDate32(testCase)
+            dates = testCase.UnixEpoch + days(1:10);
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            testCase.verifyDate32Type(array.Type);
+        end
+
+        function TestLength(testCase)
+            dates = datetime.empty(0, 1);
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            testCase.verifyEqual(array.Length, int64(0));
+
+            dates = datetime(2023, 1, 1);
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            testCase.verifyEqual(array.Length, int64(1));
+
+            dates = testCase.UnixEpoch + days(1:10);
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            testCase.verifyEqual(array.Length, int64(10));
+        end
+
+        function TestToMATLAB(testCase)
+            % Verify toMATLAB() round-trips the original datetime array.
+            dates = testCase.UnixEpoch + days(1:10);
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            values = toMATLAB(array);
+            testCase.verifyEqual(values, dates');
+        end
+
+        function TestDatetime(testCase)
+            % Verify datetime() round-trips the original datetime array.
+            dates = testCase.UnixEpoch + days(1:10);
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            values = datetime(array);
+            testCase.verifyEqual(values, dates');
+        end
+
+        function TestValid(testCase)
+            % Verify the Valid property returns the expected logical vector.
+            dates = testCase.MissingDates;
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            testCase.verifyEqual(array.Valid, [true; false; false; true; 
false]);
+            testCase.verifyEqual(toMATLAB(array), dates');
+            testCase.verifyEqual(datetime(array), dates');
+        end
+
+        function TestInferNullsTrueNVPair(testCase)
+            % Verify arrow.array.Date32Array.fromMATLAB() behaves as
+            % expected when InferNulls=true is provided.
+            dates = testCase.MissingDates;
+            array = testCase.ArrowArrayConstructorFcn(dates, InferNulls=true);
+            expectedValid = [true; false; false; true; false];
+            testCase.verifyEqual(array.Valid, expectedValid);
+            testCase.verifyEqual(toMATLAB(array), dates');
+            testCase.verifyEqual(datetime(array), dates');
+        end
+
+        function TestInferNullsFalseNVPair(testCase)
+            % Verify arrow.array.Date32Array.fromMATLAB() behaves as
+            % expected when InferNulls=false is provided.
+            dates = testCase.MissingDates;
+            array = testCase.ArrowArrayConstructorFcn(dates, InferNulls=false);
+            expectedValid = [true; true; true; true; true];
+            testCase.verifyEqual(array.Valid, expectedValid);
+
+            % If NaT datetimes were not considered null values, then they
+            % are treated like int32(0) - i.e. the Unix epoch.
+            expectedDates = dates';
+            expectedDates([2, 3, 5]) = testCase.UnixEpoch;
+            testCase.verifyEqual(toMATLAB(array), expectedDates);
+            testCase.verifyEqual(datetime(array), expectedDates);
+        end
+
+        function TestValidNVPair(testCase)
+            % Verify arrow.array.Date32Array.fromMATLAB() accepts the Valid
+            % nv-pair, and it behaves as expected.
+            dates = testCase.MissingDates;
+
+            % Supply the Valid name-value pair as vector of indices.
+            array = testCase.ArrowArrayConstructorFcn(dates, Valid=[1, 2, 3]);
+            testCase.verifyEqual(array.Valid, [true; true; true; false; 
false]);
+            expectedDates = dates';
+            expectedDates([2, 3]) = testCase.UnixEpoch;
+            expectedDates([4, 5]) = NaT;
+            testCase.verifyEqual(toMATLAB(array), expectedDates);
+
+            % Supply the Valid name-value pair as a logical scalar.
+            array = testCase.ArrowArrayConstructorFcn(dates, Valid=false);
+            testCase.verifyEqual(array.Valid, [false; false; false; false; 
false]);
+            expectedDates(:) = NaT;
+            testCase.verifyEqual(toMATLAB(array), expectedDates);
+        end
+
+        function TestEmptyDatetimeVector(testCase)
+            % Verify arrow.array.Date32Array.fromMATLAB() accepts any
+            % empty-shaped datetime as input.
+
+            dates = datetime.empty(0, 0);
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            testCase.verifyEqual(array.Length, int64(0));
+            testCase.verifyEqual(array.Valid, logical.empty(0, 1));
+            testCase.verifyEqual(toMATLAB(array), datetime.empty(0, 1));
+
+            % Test with an N-Dimensional empty array
+            dates = datetime.empty(0, 1, 0);
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            testCase.verifyEqual(array.Length, int64(0));
+            testCase.verifyEqual(array.Valid, logical.empty(0, 1));
+            testCase.verifyEqual(toMATLAB(array), datetime.empty(0, 1));
+        end
+
+        function TestErrorIfNonVector(testCase)
+            % Verify arrow.array.Date32Array.fromMATLAB() throws an error
+            % if the input provided is not a vector.
+
+            dates = datetime(2023, 1, 1) + days(1:12);
+            dates = reshape(dates, 2, 6);
+            fcn = @() testCase.ArrowArrayConstructorFcn(dates);
+            testCase.verifyError(fcn, "arrow:array:InvalidShape");
+
+            dates = reshape(dates, 3, 2, 2);
+            fcn = @() testCase.ArrowArrayConstructorFcn(dates);
+            testCase.verifyError(fcn, "arrow:array:InvalidShape");
+        end
+
+        function TestErrorIfNonDatetime(testCase)
+            % Verify arrow.array.Date32Array.fromMATLAB() throws an error
+            % if not given a datetime as input.
+
+            dates = duration(1, 2, 3);
+            fcn = @() testCase.ArrowArrayConstructorFcn(dates);
+            testCase.verifyError(fcn, "arrow:array:InvalidType");
+
+            numbers = [1; 2; 3; 4];
+            fcn = @() testCase.ArrowArrayConstructorFcn(numbers);
+            testCase.verifyError(fcn, "arrow:array:InvalidType");
+        end
+
+        function TestInt32MaxDays(testCase)
+            % Verify that no precision is lost when trying to round-trip a
+            % datetime value that is within abs(intmin("int32")) days before
+            % and intmax("int32") days after the UNIX epoch.
+
+            % Cast to int64 before taking the absolute value to avoid loss
+            % of precision.
+            numDaysBefore = abs(int64(intmin("int32")));
+            numDaysAfter = intmax("int32");
+
+            expectedBefore = testCase.UnixEpoch - days(numDaysBefore);
+            expectedAfter = testCase.UnixEpoch + days(numDaysAfter);
+
+            array = testCase.ArrowArrayConstructorFcn(expectedBefore);
+            actualBefore = array.toMATLAB();
+            testCase.verifyEqual(actualBefore, expectedBefore);
+
+            array = testCase.ArrowArrayConstructorFcn(expectedAfter);
+            actualAfter = array.toMATLAB();
+            testCase.verifyEqual(actualAfter, expectedAfter);
+        end
+
+        function TestGreaterThanInt32MaxDays(testCase)
+            % Verify that precision is lost when trying to round-trip a
+            % datetime that is more than abs(intmin("int32")) days before
+            % or more than intmax("int32") after the UNIX epoch.
+
+            % Cast to int64 before taking the absolute value to avoid loss
+            % of precision.
+            numDaysBefore = abs(int64(intmin("int32"))) + 1;
+            numDaysAfter = int64(intmax("int32")) + 1;
+
+            expectedBefore = testCase.UnixEpoch - days(numDaysBefore);
+            expectedAfter = testCase.UnixEpoch + days(numDaysAfter);
+
+            array = testCase.ArrowArrayConstructorFcn(expectedBefore);
+            actualBefore = array.toMATLAB();
+            testCase.verifyNotEqual(actualBefore, expectedBefore);
+
+            array = testCase.ArrowArrayConstructorFcn(expectedAfter);
+            actualAfter = array.toMATLAB();
+            testCase.verifyNotEqual(actualAfter, expectedAfter);
+        end
+
+        function TestZonedDatetime(testCase)
+            % Verify that zoned datetimes are supported as inputs to the
+            % fromMATLAB method and that the output datetime returned by
+            % the toMATLAB method is unzoned.
+            expectedZoned = testCase.UnixEpoch + days(10);
+            expectedZoned.TimeZone = "America/New_York";
+            expected = expectedZoned;
+            expected.TimeZone = char.empty(0, 0);
+
+            array = testCase.ArrowArrayConstructorFcn(expectedZoned);
+            actual = array.toMATLAB();
+            testCase.verifyEqual(actual, expected);
+        end
+
+        function TestInt32MaxDaysZoned(testCase)
+            % Verify that zoned datetimes which are within 
abs(intmin("int32")) days
+            % before and intmax("int32") days after the UNIX epoch are 
round-tripped
+            % (not including the TimeZone).
+
+            % Cast to int64 before taking the absolute value to avoid loss
+            % of precision.
+            numDaysBefore = abs(int64(intmin("int32")));
+            numDaysAfter = intmax("int32");
+
+            expectedZonedBefore = testCase.UnixEpoch - days(numDaysBefore);
+            expectedZonedAfter = testCase.UnixEpoch + days(numDaysAfter);
+
+            expectedZonedBefore.TimeZone = "UTC";
+            expectedZonedAfter.TimeZone = "UTC";
+
+            expectedUnzonedBefore = expectedZonedBefore;
+            expectedUnzonedBefore.TimeZone = char.empty(0, 0);
+
+            expectedUnzonedAfter = expectedZonedAfter;
+            expectedUnzonedAfter.TimeZone = char.empty(0, 0);
+
+            array = testCase.ArrowArrayConstructorFcn(expectedZonedBefore);
+            actualBefore = array.toMATLAB();
+            testCase.verifyEqual(actualBefore, expectedUnzonedBefore);
+
+            array = testCase.ArrowArrayConstructorFcn(expectedUnzonedAfter);
+            actualAfter = array.toMATLAB();
+            testCase.verifyEqual(actualAfter, expectedUnzonedAfter);
+        end
+
+        function TestNonWholeDaysRoundDown(testCase)
+            % Verify that datetimes which are not whole days (i.e. are not
+            % datetimes with zero hours, zero minutes, and zero seconds),
+            % round down to the nearest whole day when round-tripping with
+            % Date32Array.
+            dates = testCase.UnixEpoch + days(10) + hours(20) + minutes(30) + 
seconds(40) + milliseconds(50);
+            % Round down to the nearest whole day when round-tripping.
+            expected = testCase.UnixEpoch + days(10);
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            actual = array.toMATLAB();
+            testCase.verifyEqual(actual, expected);
+
+            dates = testCase.UnixEpoch + days(10) + hours(10) + minutes(20) + 
seconds(30) + milliseconds(20);
+            % Round down to the nearest whole day when round-tripping.
+            expected = testCase.UnixEpoch + days(10);
+            array = testCase.ArrowArrayConstructorFcn(dates);
+            actual = array.toMATLAB();
+            testCase.verifyEqual(actual, expected);
+        end
+
+    end
+
+    methods
+
+        function verifyDate32Type(testCase, actual)
+            testCase.verifyInstanceOf(actual, "arrow.type.Date32Type");
+            testCase.verifyEqual(actual.ID, arrow.type.ID.Date32);
+            testCase.verifyEqual(actual.DateUnit, arrow.type.DateUnit.Day);
+        end
+
+    end
+
+end
diff --git a/matlab/test/arrow/array/tTime32Array.m 
b/matlab/test/arrow/array/tTime32Array.m
index d885cd80cc..e874889e58 100644
--- a/matlab/test/arrow/array/tTime32Array.m
+++ b/matlab/test/arrow/array/tTime32Array.m
@@ -108,10 +108,10 @@ classdef tTime32Array < matlab.unittest.TestCase
         function TestValid(testCase, Unit)
             % Verify the Valid property returns the expected logical vector.
             times = seconds([100 200 NaN 355 NaN 400]);
-            arrray = testCase.ArrowArrayConstructorFcn(times, TImeUnit=Unit);
-            testCase.verifyEqual(arrray.Valid, [true; true; false; true; 
false; true]);
-            testCase.verifyEqual(toMATLAB(arrray), times');
-            testCase.verifyEqual(duration(arrray), times');
+            array = testCase.ArrowArrayConstructorFcn(times, TimeUnit=Unit);
+            testCase.verifyEqual(array.Valid, [true; true; false; true; false; 
true]);
+            testCase.verifyEqual(toMATLAB(array), times');
+            testCase.verifyEqual(duration(array), times');
         end
 
         function InferNullsTrueNVPair(testCase, Unit)
diff --git a/matlab/test/arrow/type/traits/tDate32Traits.m 
b/matlab/test/arrow/type/traits/tDate32Traits.m
new file mode 100644
index 0000000000..6f3c07c99d
--- /dev/null
+++ b/matlab/test/arrow/type/traits/tDate32Traits.m
@@ -0,0 +1,33 @@
+%TDATE32TRAITS Unit tests for arrow.type.traits.Date32Traits
+
+% Licensed to the Apache Software Foundation (ASF) under one or more
+% contributor license agreements.  See the NOTICE file distributed with
+% this work for additional information regarding copyright ownership.
+% The ASF licenses this file to you under the Apache License, Version
+% 2.0 (the "License"); you may not use this file except in compliance
+% with the License.  You may obtain a copy of the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS,
+% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+% implied.  See the License for the specific language governing
+% permissions and limitations under the License.
+
+classdef tDate32Traits < hTypeTraits
+
+    properties
+        TraitsConstructor = @arrow.type.traits.Date32Traits
+        ArrayConstructor = @arrow.array.Date32Array
+        ArrayClassName = "arrow.array.Date32Array"
+        ArrayProxyClassName = "arrow.array.proxy.Date32Array"
+        ArrayStaticConstructor = @arrow.array.Date32Array.fromMATLAB
+        TypeConstructor = @arrow.type.Date32Type
+        TypeClassName = "arrow.type.Date32Type"
+        TypeProxyClassName = "arrow.type.proxy.Date32Type"
+        MatlabConstructor = @datetime
+        MatlabClassName = "datetime"
+    end
+
+end
diff --git a/matlab/test/arrow/type/traits/ttraits.m 
b/matlab/test/arrow/type/traits/ttraits.m
index 771562152a..70508a5e7c 100644
--- a/matlab/test/arrow/type/traits/ttraits.m
+++ b/matlab/test/arrow/type/traits/ttraits.m
@@ -175,6 +175,18 @@ classdef ttraits < matlab.unittest.TestCase
             testCase.verifyEqual(actualTraits, expectedTraits); 
         end
 
+        function TestDate32(testCase)
+            import arrow.type.traits.*
+            import arrow.type.*
+
+            type = ID.Date32;
+            expectedTraits = Date32Traits();
+
+            actualTraits = traits(type);
+
+            testCase.verifyEqual(actualTraits, expectedTraits);
+        end
+
         function TestMatlabUInt8(testCase)
             import arrow.type.traits.*
 
@@ -352,4 +364,4 @@ classdef ttraits < matlab.unittest.TestCase
 
     end
 
-end
\ No newline at end of file
+end

Reply via email to