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