diff --git a/cpp/src/arrow/compute/api_scalar.cc b/cpp/src/arrow/compute/api_scalar.cc index 021499af228..25a3b85f333 100644 --- a/cpp/src/arrow/compute/api_scalar.cc +++ b/cpp/src/arrow/compute/api_scalar.cc @@ -118,6 +118,7 @@ struct EnumTraits return ""; } }; + template <> struct EnumTraits : BasicEnumTraits } }; +template <> +struct EnumTraits + : BasicEnumTraits { + static std::string name() { return "compute::CalendarUnit"; } + static std::string value_name(compute::CalendarUnit value) { + switch (value) { + case compute::CalendarUnit::NANOSECOND: + return "NANOSECOND"; + case compute::CalendarUnit::MICROSECOND: + return "MICROSECOND"; + case compute::CalendarUnit::MILLISECOND: + return "MILLISECOND"; + case compute::CalendarUnit::SECOND: + return "SECOND"; + case compute::CalendarUnit::MINUTE: + return "MINUTE"; + case compute::CalendarUnit::HOUR: + return "HOUR"; + case compute::CalendarUnit::DAY: + return "DAY"; + case compute::CalendarUnit::WEEK: + return "WEEK"; + case compute::CalendarUnit::MONTH: + return "MONTH"; + case compute::CalendarUnit::QUARTER: + return "QUARTER"; + case compute::CalendarUnit::YEAR: + return "YEAR"; + } + return ""; + } +}; + template <> struct EnumTraits : BasicEnumTraits( DataMember("ndigits", &RoundOptions::ndigits), DataMember("round_mode", &RoundOptions::round_mode)); +static auto kRoundTemporalOptionsType = GetFunctionOptionsType( + DataMember("multiple", &RoundTemporalOptions::multiple), + DataMember("unit", &RoundTemporalOptions::unit)); static auto kRoundToMultipleOptionsType = GetFunctionOptionsType( DataMember("multiple", &RoundToMultipleOptions::multiple), DataMember("round_mode", &RoundToMultipleOptions::round_mode)); @@ -412,6 +455,12 @@ RoundOptions::RoundOptions(int64_t ndigits, RoundMode round_mode) } constexpr char RoundOptions::kTypeName[]; +RoundTemporalOptions::RoundTemporalOptions(int multiple, CalendarUnit unit) + : FunctionOptions(internal::kRoundTemporalOptionsType), + multiple(std::move(multiple)), + unit(unit) {} +constexpr char RoundTemporalOptions::kTypeName[]; + RoundToMultipleOptions::RoundToMultipleOptions(double multiple, RoundMode round_mode) : RoundToMultipleOptions(std::make_shared(multiple), round_mode) {} RoundToMultipleOptions::RoundToMultipleOptions(std::shared_ptr multiple, @@ -511,6 +560,7 @@ void RegisterScalarOptions(FunctionRegistry* registry) { DCHECK_OK(registry->AddFunctionOptionsType(kReplaceSliceOptionsType)); DCHECK_OK(registry->AddFunctionOptionsType(kReplaceSubstringOptionsType)); DCHECK_OK(registry->AddFunctionOptionsType(kRoundOptionsType)); + DCHECK_OK(registry->AddFunctionOptionsType(kRoundTemporalOptionsType)); DCHECK_OK(registry->AddFunctionOptionsType(kRoundToMultipleOptionsType)); DCHECK_OK(registry->AddFunctionOptionsType(kSetLookupOptionsType)); DCHECK_OK(registry->AddFunctionOptionsType(kSliceOptionsType)); @@ -711,6 +761,21 @@ Result DayOfWeek(const Datum& arg, DayOfWeekOptions options, ExecContext* return CallFunction("day_of_week", {arg}, &options, ctx); } +Result CeilTemporal(const Datum& arg, RoundTemporalOptions options, + ExecContext* ctx) { + return CallFunction("ceil_temporal", {arg}, &options, ctx); +} + +Result FloorTemporal(const Datum& arg, RoundTemporalOptions options, + ExecContext* ctx) { + return CallFunction("floor_temporal", {arg}, &options, ctx); +} + +Result RoundTemporal(const Datum& arg, RoundTemporalOptions options, + ExecContext* ctx) { + return CallFunction("round_temporal", {arg}, &options, ctx); +} + Result Strftime(const Datum& arg, StrftimeOptions options, ExecContext* ctx) { return CallFunction("strftime", {arg}, &options, ctx); } diff --git a/cpp/src/arrow/compute/api_scalar.h b/cpp/src/arrow/compute/api_scalar.h index 3d922157c9c..0485d4b80a8 100644 --- a/cpp/src/arrow/compute/api_scalar.h +++ b/cpp/src/arrow/compute/api_scalar.h @@ -90,6 +90,32 @@ class ARROW_EXPORT RoundOptions : public FunctionOptions { RoundMode round_mode; }; +enum class CalendarUnit : int8_t { + NANOSECOND, + MICROSECOND, + MILLISECOND, + SECOND, + MINUTE, + HOUR, + DAY, + WEEK, + MONTH, + QUARTER, + YEAR +}; + +class ARROW_EXPORT RoundTemporalOptions : public FunctionOptions { + public: + explicit RoundTemporalOptions(int multiple = 1, CalendarUnit unit = CalendarUnit::DAY); + constexpr static char const kTypeName[] = "RoundTemporalOptions"; + static RoundTemporalOptions Defaults() { return RoundTemporalOptions(); } + + /// Number of units to round to + int multiple; + /// The unit used for rounding of time + CalendarUnit unit; +}; + class ARROW_EXPORT RoundToMultipleOptions : public FunctionOptions { public: explicit RoundToMultipleOptions(double multiple = 1.0, @@ -781,6 +807,54 @@ Result RoundToMultiple( const Datum& arg, RoundToMultipleOptions options = RoundToMultipleOptions::Defaults(), ExecContext* ctx = NULLPTR); +/// \brief Ceil a temporal value to a given frequency +/// +/// If argument is null the result will be null. +/// +/// \param[in] arg the temporal value to ceil +/// \param[in] options temporal rounding options, optional +/// \param[in] ctx the function execution context, optional +/// \return the element-wise rounded value +/// +/// \since 7.0.0 +/// \note API not yet finalized +ARROW_EXPORT +Result CeilTemporal( + const Datum& arg, RoundTemporalOptions options = RoundTemporalOptions::Defaults(), + ExecContext* ctx = NULLPTR); + +/// \brief Floor a temporal value to a given frequency +/// +/// If argument is null the result will be null. +/// +/// \param[in] arg the temporal value to floor +/// \param[in] options temporal rounding options, optional +/// \param[in] ctx the function execution context, optional +/// \return the element-wise rounded value +/// +/// \since 7.0.0 +/// \note API not yet finalized +ARROW_EXPORT +Result FloorTemporal( + const Datum& arg, RoundTemporalOptions options = RoundTemporalOptions::Defaults(), + ExecContext* ctx = NULLPTR); + +/// \brief Round a temporal value to a given frequency +/// +/// If argument is null the result will be null. +/// +/// \param[in] arg the temporal value to round +/// \param[in] options temporal rounding options, optional +/// \param[in] ctx the function execution context, optional +/// \return the element-wise rounded value +/// +/// \since 7.0.0 +/// \note API not yet finalized +ARROW_EXPORT +Result RoundTemporal( + const Datum& arg, RoundTemporalOptions options = RoundTemporalOptions::Defaults(), + ExecContext* ctx = NULLPTR); + /// \brief Compare a numeric array with a scalar. /// /// \param[in] left datum to compare, must be an Array diff --git a/cpp/src/arrow/compute/function_test.cc b/cpp/src/arrow/compute/function_test.cc index b503a1732d9..1653224ee05 100644 --- a/cpp/src/arrow/compute/function_test.cc +++ b/cpp/src/arrow/compute/function_test.cc @@ -61,6 +61,10 @@ TEST(FunctionOptions, Equality) { options.emplace_back(new RoundOptions()); options.emplace_back( new RoundOptions(/*ndigits=*/2, /*round_mode=*/RoundMode::TOWARDS_INFINITY)); + options.emplace_back(new RoundTemporalOptions()); + options.emplace_back(new RoundTemporalOptions( + /*multiple=*/2, + /*unit=*/CalendarUnit::WEEK)); options.emplace_back(new RoundToMultipleOptions()); options.emplace_back(new RoundToMultipleOptions( /*multiple=*/100, /*round_mode=*/RoundMode::TOWARDS_INFINITY)); diff --git a/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc b/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc index 92133136b62..34a16887c46 100644 --- a/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc +++ b/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc @@ -342,6 +342,39 @@ class ScalarTemporalTest : public ::testing::Test { "[-19980000, 0, 9082000000000, -5618000000000, 64800004000000, -420002000000, " "-10800000000000, 1200000300000, -300000, -18000000000000, 57624000000000, " "-33000000000, 0, 0, 0, 0, null]"; + + RoundTemporalOptions round_to_1_nanoseconds = + RoundTemporalOptions(1, CalendarUnit::NANOSECOND); + RoundTemporalOptions round_to_1_microseconds = + RoundTemporalOptions(1, CalendarUnit::MICROSECOND); + RoundTemporalOptions round_to_1_milliseconds = + RoundTemporalOptions(1, CalendarUnit::MILLISECOND); + RoundTemporalOptions round_to_1_seconds = RoundTemporalOptions(1, CalendarUnit::SECOND); + RoundTemporalOptions round_to_1_minutes = RoundTemporalOptions(1, CalendarUnit::MINUTE); + RoundTemporalOptions round_to_1_hours = RoundTemporalOptions(1, CalendarUnit::HOUR); + RoundTemporalOptions round_to_1_days = RoundTemporalOptions(1, CalendarUnit::DAY); + RoundTemporalOptions round_to_1_weeks = RoundTemporalOptions(1, CalendarUnit::WEEK); + RoundTemporalOptions round_to_1_months = RoundTemporalOptions(1, CalendarUnit::MONTH); + RoundTemporalOptions round_to_1_quarters = + RoundTemporalOptions(1, CalendarUnit::QUARTER); + RoundTemporalOptions round_to_1_years = RoundTemporalOptions(1, CalendarUnit::YEAR); + RoundTemporalOptions round_to_15_nanoseconds = + RoundTemporalOptions(15, CalendarUnit::NANOSECOND); + RoundTemporalOptions round_to_15_microseconds = + RoundTemporalOptions(15, CalendarUnit::MICROSECOND); + RoundTemporalOptions round_to_15_milliseconds = + RoundTemporalOptions(15, CalendarUnit::MILLISECOND); + RoundTemporalOptions round_to_15_seconds = + RoundTemporalOptions(15, CalendarUnit::SECOND); + RoundTemporalOptions round_to_15_minutes = + RoundTemporalOptions(15, CalendarUnit::MINUTE); + RoundTemporalOptions round_to_15_hours = RoundTemporalOptions(15, CalendarUnit::HOUR); + RoundTemporalOptions round_to_15_days = RoundTemporalOptions(15, CalendarUnit::DAY); + RoundTemporalOptions round_to_15_weeks = RoundTemporalOptions(15, CalendarUnit::WEEK); + RoundTemporalOptions round_to_15_months = RoundTemporalOptions(15, CalendarUnit::MONTH); + RoundTemporalOptions round_to_15_quarters = + RoundTemporalOptions(15, CalendarUnit::QUARTER); + RoundTemporalOptions round_to_15_years = RoundTemporalOptions(15, CalendarUnit::YEAR); }; TEST_F(ScalarTemporalTest, TestTemporalComponentExtractionAllTemporalTypes) { @@ -1324,6 +1357,595 @@ TEST_F(ScalarTemporalTest, TestTemporalDifferenceZoned) { } } +TEST_F(ScalarTemporalTest, TestCeilTemporal) { + std::string op = "ceil_temporal"; + const char* ceil_1_nanosecond = + R"(["1970-01-01 00:00:59.123456789", "2000-02-29 23:23:23.999999999", + "1899-01-01 00:59:20.001001001", "2033-05-18 03:33:20.000000000", + "2020-01-01 01:05:05.001000000", "2019-12-31 02:10:10.002000000", + "2019-12-30 03:15:15.003000000", "2009-12-31 04:20:20.004132000", + "2010-01-01 05:25:25.005321000", "2010-01-03 06:30:30.006163000", + "2010-01-04 07:35:35.000000000", "2006-01-01 08:40:40.000000000", + "2005-12-31 09:45:45.000000000", "2008-12-28 00:00:00.000000000", + "2008-12-29 00:00:00.000000000", "2012-01-01 01:02:03.000000000", null])"; + const char* ceil_1_microsecond = + R"(["1970-01-01 00:00:59.123457", "2000-02-29 23:23:24.000000", + "1899-01-01 00:59:20.001002", "2033-05-18 03:33:20.000000", + "2020-01-01 01:05:05.001000", "2019-12-31 02:10:10.002000", + "2019-12-30 03:15:15.003000", "2009-12-31 04:20:20.004132", + "2010-01-01 05:25:25.005321", "2010-01-03 06:30:30.006163", + "2010-01-04 07:35:35.000000", "2006-01-01 08:40:40.000000", + "2005-12-31 09:45:45.000000", "2008-12-28 00:00:00.000000", + "2008-12-29 00:00:00.000000", "2012-01-01 01:02:03.000000", null])"; + const char* ceil_1_millisecond = + R"(["1970-01-01 00:00:59.124", "2000-02-29 23:23:24.000", + "1899-01-01 00:59:20.002", "2033-05-18 03:33:20.000", + "2020-01-01 01:05:05.001", "2019-12-31 02:10:10.002", + "2019-12-30 03:15:15.003", "2009-12-31 04:20:20.005", + "2010-01-01 05:25:25.006", "2010-01-03 06:30:30.007", + "2010-01-04 07:35:35.000", "2006-01-01 08:40:40.000", + "2005-12-31 09:45:45.000", "2008-12-28 00:00:00.000", + "2008-12-29 00:00:00.000", "2012-01-01 01:02:03.000", null])"; + const char* ceil_1_second = + R"(["1970-01-01 00:01:00", "2000-02-29 23:23:24", "1899-01-01 00:59:21", + "2033-05-18 03:33:20", "2020-01-01 01:05:06", "2019-12-31 02:10:11", + "2019-12-30 03:15:16", "2009-12-31 04:20:21", "2010-01-01 05:25:26", + "2010-01-03 06:30:31", "2010-01-04 07:35:35", "2006-01-01 08:40:40", + "2005-12-31 09:45:45", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:02:03", null])"; + const char* ceil_1_minute = + R"(["1970-01-01 00:01:00", "2000-02-29 23:24:00", "1899-01-01 01:00:00", + "2033-05-18 03:34:00", "2020-01-01 01:06:00", "2019-12-31 02:11:00", + "2019-12-30 03:16:00", "2009-12-31 04:21:00", "2010-01-01 05:26:00", + "2010-01-03 06:31:00", "2010-01-04 07:36:00", "2006-01-01 08:41:00", + "2005-12-31 09:46:00", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:03:00", null])"; + const char* ceil_1_hour = + R"(["1970-01-01 01:00:00", "2000-03-01 00:00:00", "1899-01-01 01:00:00", + "2033-05-18 04:00:00", "2020-01-01 02:00:00", "2019-12-31 03:00:00", + "2019-12-30 04:00:00", "2009-12-31 05:00:00", "2010-01-01 06:00:00", + "2010-01-03 07:00:00", "2010-01-04 08:00:00", "2006-01-01 09:00:00", + "2005-12-31 10:00:00", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 02:00:00", null])"; + const char* ceil_1_day = + R"(["1970-01-02", "2000-03-01", "1899-01-02", "2033-05-19", "2020-01-02", + "2020-01-01", "2019-12-31", "2010-01-01", "2010-01-02", "2010-01-04", + "2010-01-05", "2006-01-02", "2006-01-01", "2008-12-28", "2008-12-29", + "2012-01-02", null])"; + const char* ceil_1_weeks = + R"(["1970-01-08", "2000-03-02", "1899-01-05", "2033-05-19", "2020-01-02", + "2020-01-02", "2020-01-02", "2010-01-07", "2010-01-07", "2010-01-07", + "2010-01-07", "2006-01-05", "2006-01-05", "2009-01-01", "2009-01-01", + "2012-01-05", null])"; + const char* ceil_1_months = + R"(["1970-02-01", "2000-03-01", "1899-02-01", "2033-06-01", "2020-02-01", + "2020-01-01", "2020-01-01", "2010-01-01", "2010-02-01", "2010-02-01", + "2010-02-01", "2006-02-01", "2006-01-01", "2009-01-01", "2009-01-01", + "2012-02-01", null])"; + const char* ceil_1_quarters = + R"(["1970-04-01", "2000-04-01", "1899-04-01", "2033-07-01", "2020-04-01", + "2020-01-01", "2020-01-01", "2010-01-01", "2010-04-01", "2010-04-01", + "2010-04-01", "2006-04-01", "2006-01-01", "2009-01-01", "2009-01-01", + "2012-04-01", null])"; + const char* ceil_1_years = + R"(["1971-01-01", "2001-01-01", "1900-01-01", "2034-01-01", "2021-01-01", + "2020-01-01", "2020-01-01", "2010-01-01", "2011-01-01", "2011-01-01", + "2011-01-01", "2007-01-01", "2006-01-01", "2009-01-01", "2009-01-01", + "2013-01-01", null])"; + const char* ceil_15_nanosecond = + R"(["1970-01-01 00:00:59.123456790", "2000-02-29 23:23:24.000000000", + "1899-01-01 00:59:20.001001005", "2033-05-18 03:33:20.000000010", + "2020-01-01 01:05:05.001000000", "2019-12-31 02:10:10.002000000", + "2019-12-30 03:15:15.003000000", "2009-12-31 04:20:20.004132000", + "2010-01-01 05:25:25.005321000", "2010-01-03 06:30:30.006163005", + "2010-01-04 07:35:35.000000010", "2006-01-01 08:40:40.000000005", + "2005-12-31 09:45:45.000000000", "2008-12-28 00:00:00.000000000", + "2008-12-29 00:00:00.000000000", "2012-01-01 01:02:03.000000000", null])"; + const char* ceil_15_microsecond = + R"(["1970-01-01 00:00:59.123460", "2000-02-29 23:23:24.000000", + "1899-01-01 00:59:20.001015", "2033-05-18 03:33:20.000010", + "2020-01-01 01:05:05.001000", "2019-12-31 02:10:10.002000", + "2019-12-30 03:15:15.003000", "2009-12-31 04:20:20.004135", + "2010-01-01 05:25:25.005330", "2010-01-03 06:30:30.006165", + "2010-01-04 07:35:35.000010", "2006-01-01 08:40:40.000005", + "2005-12-31 09:45:45.000000", "2008-12-28 00:00:00.000000", + "2008-12-29 00:00:00.000000", "2012-01-01 01:02:03.000000", null])"; + const char* ceil_15_millisecond = + R"(["1970-01-01 00:00:59.130", "2000-02-29 23:23:24.000", + "1899-01-01 00:59:20.010", "2033-05-18 03:33:20.010", + "2020-01-01 01:05:05.010", "2019-12-31 02:10:10.005", + "2019-12-30 03:15:15.015", "2009-12-31 04:20:20.010", + "2010-01-01 05:25:25.020", "2010-01-03 06:30:30.015", + "2010-01-04 07:35:35.010", "2006-01-01 08:40:40.005", + "2005-12-31 09:45:45.000", "2008-12-28 00:00:00.000", + "2008-12-29 00:00:00.000", "2012-01-01 01:02:03.000", null])"; + const char* ceil_15_second = + R"(["1970-01-01 00:01:00", "2000-02-29 23:23:30", "1899-01-01 00:59:30", + "2033-05-18 03:33:30", "2020-01-01 01:05:15", "2019-12-31 02:10:15", + "2019-12-30 03:15:30", "2009-12-31 04:20:30", "2010-01-01 05:25:30", + "2010-01-03 06:30:45", "2010-01-04 07:35:45", "2006-01-01 08:40:45", + "2005-12-31 09:45:45", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:02:15", null])"; + const char* ceil_15_minute = + R"(["1970-01-01 00:15:00", "2000-02-29 23:30:00", "1899-01-01 01:00:00", + "2033-05-18 03:45:00", "2020-01-01 01:15:00", "2019-12-31 02:15:00", + "2019-12-30 03:30:00", "2009-12-31 04:30:00", "2010-01-01 05:30:00", + "2010-01-03 06:45:00", "2010-01-04 07:45:00", "2006-01-01 08:45:00", + "2005-12-31 10:00:00", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:15:00", null])"; + const char* ceil_15_hour = + R"(["1970-01-01 15:00:00", "2000-03-01 12:00:00", "1899-01-01 03:00:00", + "2033-05-18 18:00:00", "2020-01-01 12:00:00", "2019-12-31 06:00:00", + "2019-12-30 15:00:00", "2009-12-31 09:00:00", "2010-01-01 15:00:00", + "2010-01-03 12:00:00", "2010-01-04 18:00:00", "2006-01-01 09:00:00", + "2005-12-31 18:00:00", "2008-12-28 06:00:00", "2008-12-29 12:00:00", + "2012-01-01 15:00:00", null])"; + const char* ceil_15_day = + R"(["1970-01-16", "2000-03-09", "1899-01-13", "2033-05-30", "2020-01-09", + "2020-01-09", "2020-01-09", "2010-01-01", "2010-01-16", "2010-01-16", + "2010-01-16", "2006-01-07", "2006-01-07", "2009-01-06", "2009-01-06", + "2012-01-06", null])"; + const char* ceil_15_weeks = + R"(["1970-04-16", "2000-03-09", "1899-04-13", "2033-07-14", "2020-01-09", + "2020-01-09", "2020-01-09", "2010-04-01", "2010-04-01", "2010-04-01", + "2010-04-01", "2006-03-23", "2006-03-23", "2009-02-05", "2009-02-05", + "2012-04-05", null])"; + const char* ceil_15_months = + R"(["1971-04-01", "2001-04-01", "1900-01-01", "2033-10-01", "2021-04-01", + "2020-01-01", "2020-01-01", "2010-01-01", "2011-04-01", "2011-04-01", + "2011-04-01", "2006-04-01", "2006-04-01", "2010-01-01", "2010-01-01", + "2012-07-01", null])"; + const char* ceil_15_quarters = + R"(["1973-10-01", "2003-10-01", "1902-07-01", "2033-10-01", "2022-07-01", + "2022-07-01", "2022-07-01", "2011-04-01", "2011-04-01", "2011-04-01", + "2011-04-01", "2007-07-01", "2007-07-01", "2011-04-01", "2011-04-01", + "2015-01-01", null])"; + const char* ceil_15_years = + R"(["1980-01-01", "2010-01-01", "1905-01-01", "2040-01-01", "2025-01-01", + "2025-01-01", "2025-01-01", "2010-01-01", "2025-01-01", "2025-01-01", + "2025-01-01", "2010-01-01", "2010-01-01", "2010-01-01", "2010-01-01", + "2025-01-01", null])"; + + auto unit = timestamp(TimeUnit::NANO, "UTC"); + CheckScalarUnary(op, unit, times, unit, ceil_1_nanosecond, &round_to_1_nanoseconds); + CheckScalarUnary(op, unit, times, unit, ceil_1_microsecond, &round_to_1_microseconds); + CheckScalarUnary(op, unit, times, unit, ceil_1_millisecond, &round_to_1_milliseconds); + CheckScalarUnary(op, unit, times, unit, ceil_1_second, &round_to_1_seconds); + CheckScalarUnary(op, unit, times, unit, ceil_1_minute, &round_to_1_minutes); + CheckScalarUnary(op, unit, times, unit, ceil_1_hour, &round_to_1_hours); + CheckScalarUnary(op, unit, times, unit, ceil_1_day, &round_to_1_days); + CheckScalarUnary(op, unit, times, unit, ceil_1_weeks, &round_to_1_weeks); + CheckScalarUnary(op, unit, times, unit, ceil_1_months, &round_to_1_months); + CheckScalarUnary(op, unit, times, unit, ceil_1_quarters, &round_to_1_quarters); + CheckScalarUnary(op, unit, times, unit, ceil_1_years, &round_to_1_years); + + CheckScalarUnary(op, unit, times, unit, ceil_15_nanosecond, &round_to_15_nanoseconds); + CheckScalarUnary(op, unit, times, unit, ceil_15_microsecond, &round_to_15_microseconds); + CheckScalarUnary(op, unit, times, unit, ceil_15_millisecond, &round_to_15_milliseconds); + CheckScalarUnary(op, unit, times, unit, ceil_15_second, &round_to_15_seconds); + CheckScalarUnary(op, unit, times, unit, ceil_15_minute, &round_to_15_minutes); + CheckScalarUnary(op, unit, times, unit, ceil_15_hour, &round_to_15_hours); + CheckScalarUnary(op, unit, times, unit, ceil_15_day, &round_to_15_days); + CheckScalarUnary(op, unit, times, unit, ceil_15_weeks, &round_to_15_weeks); + CheckScalarUnary(op, unit, times, unit, ceil_15_months, &round_to_15_months); + CheckScalarUnary(op, unit, times, unit, ceil_15_quarters, &round_to_15_quarters); + CheckScalarUnary(op, unit, times, unit, ceil_15_years, &round_to_15_years); +} + +TEST_F(ScalarTemporalTest, TestFloorTemporal) { + std::string op = "floor_temporal"; + const char* floor_1_nanosecond = + R"(["1970-01-01 00:00:59.123456789", "2000-02-29 23:23:23.999999999", + "1899-01-01 00:59:20.001001001", "2033-05-18 03:33:20.000000000", + "2020-01-01 01:05:05.001000000", "2019-12-31 02:10:10.002000000", + "2019-12-30 03:15:15.003000000", "2009-12-31 04:20:20.004132000", + "2010-01-01 05:25:25.005321000", "2010-01-03 06:30:30.006163000", + "2010-01-04 07:35:35.000000000", "2006-01-01 08:40:40.000000000", + "2005-12-31 09:45:45.000000000", "2008-12-28 00:00:00.000000000", + "2008-12-29 00:00:00.000000000", "2012-01-01 01:02:03.000000000", null])"; + const char* floor_1_microsecond = + R"(["1970-01-01 00:00:59.123456", "2000-02-29 23:23:23.999999", + "1899-01-01 00:59:20.001001", "2033-05-18 03:33:20.000000", + "2020-01-01 01:05:05.001000", "2019-12-31 02:10:10.002000", + "2019-12-30 03:15:15.003000", "2009-12-31 04:20:20.004132", + "2010-01-01 05:25:25.005321", "2010-01-03 06:30:30.006163", + "2010-01-04 07:35:35.000000", "2006-01-01 08:40:40.000000", + "2005-12-31 09:45:45.000000", "2008-12-28 00:00:00.000000", + "2008-12-29 00:00:00.000000", "2012-01-01 01:02:03.000000", null])"; + const char* floor_1_millisecond = + R"(["1970-01-01 00:00:59.123", "2000-02-29 23:23:23.999", + "1899-01-01 00:59:20.001", "2033-05-18 03:33:20.000", + "2020-01-01 01:05:05.001", "2019-12-31 02:10:10.002", + "2019-12-30 03:15:15.003", "2009-12-31 04:20:20.004", + "2010-01-01 05:25:25.005", "2010-01-03 06:30:30.006", + "2010-01-04 07:35:35.000", "2006-01-01 08:40:40.000", + "2005-12-31 09:45:45.000", "2008-12-28 00:00:00.000", + "2008-12-29 00:00:00.000", "2012-01-01 01:02:03.000", null])"; + const char* floor_1_second = + R"(["1970-01-01 00:00:59", "2000-02-29 23:23:23", "1899-01-01 00:59:20", + "2033-05-18 03:33:20", "2020-01-01 01:05:05", "2019-12-31 02:10:10", + "2019-12-30 03:15:15", "2009-12-31 04:20:20", "2010-01-01 05:25:25", + "2010-01-03 06:30:30", "2010-01-04 07:35:35", "2006-01-01 08:40:40", + "2005-12-31 09:45:45", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:02:03", null])"; + const char* floor_1_minute = + R"(["1970-01-01 00:00:00", "2000-02-29 23:23:00", "1899-01-01 00:59:00", + "2033-05-18 03:33:00", "2020-01-01 01:05:00", "2019-12-31 02:10:00", + "2019-12-30 03:15:00", "2009-12-31 04:20:00", "2010-01-01 05:25:00", + "2010-01-03 06:30:00", "2010-01-04 07:35:00", "2006-01-01 08:40:00", + "2005-12-31 09:45:00", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:02:00", null])"; + const char* floor_1_hour = + R"(["1970-01-01 00:00:00", "2000-02-29 23:00:00", "1899-01-01 00:00:00", + "2033-05-18 03:00:00", "2020-01-01 01:00:00", "2019-12-31 02:00:00", + "2019-12-30 03:00:00", "2009-12-31 04:00:00", "2010-01-01 05:00:00", + "2010-01-03 06:00:00", "2010-01-04 07:00:00", "2006-01-01 08:00:00", + "2005-12-31 09:00:00", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:00:00", null])"; + const char* floor_1_day = + R"(["1970-01-01", "2000-02-29", "1899-01-01", "2033-05-18", "2020-01-01", + "2019-12-31", "2019-12-30", "2009-12-31", "2010-01-01", "2010-01-03", + "2010-01-04", "2006-01-01", "2005-12-31", "2008-12-28", "2008-12-29", + "2012-01-01", null])"; + const char* floor_1_weeks = + R"(["1970-01-01", "2000-02-24", "1898-12-29", "2033-05-12", "2019-12-26", + "2019-12-26", "2019-12-26", "2009-12-31", "2009-12-31", "2009-12-31", + "2009-12-31", "2005-12-29", "2005-12-29", "2008-12-25", "2008-12-25", + "2011-12-29", null])"; + const char* floor_1_months = + R"(["1970-01-01", "2000-02-01", "1899-01-01", "2033-05-01", "2020-01-01", + "2019-12-01", "2019-12-01", "2009-12-01", "2010-01-01", "2010-01-01", + "2010-01-01", "2006-01-01", "2005-12-01", "2008-12-01", "2008-12-01", + "2012-01-01", null])"; + const char* floor_1_quarters = + R"(["1970-01-01", "2000-01-01", "1899-01-01", "2033-04-01", "2020-01-01", + "2019-10-01", "2019-10-01", "2009-10-01", "2010-01-01", "2010-01-01", + "2010-01-01", "2006-01-01", "2005-10-01", "2008-10-01", "2008-10-01", + "2012-01-01", null])"; + const char* floor_1_years = + R"(["1970-01-01", "2000-01-01", "1899-01-01", "2033-01-01", "2020-01-01", + "2019-01-01", "2019-01-01", "2009-01-01", "2010-01-01", "2010-01-01", + "2010-01-01", "2006-01-01", "2005-01-01", "2008-01-01", "2008-01-01", + "2012-01-01", null])"; + + const char* floor_15_nanosecond = + R"(["1970-01-01 00:00:59.123456775", "2000-02-29 23:23:23.999999985", + "1899-01-01 00:59:20.001000990", "2033-05-18 03:33:19.999999995", + "2020-01-01 01:05:05.001000000", "2019-12-31 02:10:10.002000000", + "2019-12-30 03:15:15.003000000", "2009-12-31 04:20:20.004132000", + "2010-01-01 05:25:25.005321000", "2010-01-03 06:30:30.006162990", + "2010-01-04 07:35:34.999999995", "2006-01-01 08:40:39.999999990", + "2005-12-31 09:45:45.000000000", "2008-12-28 00:00:00.000000000", + "2008-12-29 00:00:00.000000000", "2012-01-01 01:02:03.000000000", null])"; + const char* floor_15_microsecond = + R"(["1970-01-01 00:00:59.123445", "2000-02-29 23:23:23.999985", + "1899-01-01 00:59:20.001000", "2033-05-18 03:33:19.999995", + "2020-01-01 01:05:05.001000", "2019-12-31 02:10:10.002000", + "2019-12-30 03:15:15.003000", "2009-12-31 04:20:20.004120", + "2010-01-01 05:25:25.005315", "2010-01-03 06:30:30.006150", + "2010-01-04 07:35:34.999995", "2006-01-01 08:40:39.999990", + "2005-12-31 09:45:45.000000", "2008-12-28 00:00:00.000000", + "2008-12-29 00:00:00.000000", "2012-01-01 01:02:03.000000", null])"; + const char* floor_15_millisecond = + R"(["1970-01-01 00:00:59.115", "2000-02-29 23:23:23.985", + "1899-01-01 00:59:19.995", "2033-05-18 03:33:19.995", + "2020-01-01 01:05:04.995", "2019-12-31 02:10:09.990", + "2019-12-30 03:15:15.000", "2009-12-31 04:20:19.995", + "2010-01-01 05:25:25.005", "2010-01-03 06:30:30.000", + "2010-01-04 07:35:34.995", "2006-01-01 08:40:39.990", + "2005-12-31 09:45:45.000", "2008-12-28 00:00:00.000", + "2008-12-29 00:00:00.000", "2012-01-01 01:02:03.000", null])"; + const char* floor_15_second = + R"(["1970-01-01 00:00:45", "2000-02-29 23:23:15", "1899-01-01 00:59:15", + "2033-05-18 03:33:15", "2020-01-01 01:05:00", "2019-12-31 02:10:00", + "2019-12-30 03:15:15", "2009-12-31 04:20:15", "2010-01-01 05:25:15", + "2010-01-03 06:30:30", "2010-01-04 07:35:30", "2006-01-01 08:40:30", + "2005-12-31 09:45:45", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:02:00", null])"; + const char* floor_15_minute = + R"(["1970-01-01 00:00:00", "2000-02-29 23:15:00", "1899-01-01 00:45:00", + "2033-05-18 03:30:00", "2020-01-01 01:00:00", "2019-12-31 02:00:00", + "2019-12-30 03:15:00", "2009-12-31 04:15:00", "2010-01-01 05:15:00", + "2010-01-03 06:30:00", "2010-01-04 07:30:00", "2006-01-01 08:30:00", + "2005-12-31 09:45:00", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:00:00", null])"; + const char* floor_15_hour = + R"(["1970-01-01 00:00:00", "2000-02-29 21:00:00", "1898-12-31 12:00:00", + "2033-05-18 03:00:00", "2019-12-31 21:00:00", "2019-12-30 15:00:00", + "2019-12-30 00:00:00", "2009-12-30 18:00:00", "2010-01-01 00:00:00", + "2010-01-02 21:00:00", "2010-01-04 03:00:00", "2005-12-31 18:00:00", + "2005-12-31 03:00:00", "2008-12-27 15:00:00", "2008-12-28 21:00:00", + "2012-01-01 00:00:00", null])"; + const char* floor_15_day = + R"(["1970-01-01", "2000-02-23", "1898-12-29", "2033-05-15", "2019-12-25", + "2019-12-25", "2019-12-25", "2009-12-17", "2010-01-01", "2010-01-01", + "2010-01-01", "2005-12-23", "2005-12-23", "2008-12-22", "2008-12-22", + "2011-12-22", null])"; + const char* floor_15_weeks = + R"(["1970-01-01", "1999-11-25", "1898-12-29", "2033-03-31", "2019-09-26", + "2019-09-26", "2019-09-26", "2009-12-17", "2009-12-17", "2009-12-17", + "2009-12-17", "2005-12-08", "2005-12-08", "2008-10-23", "2008-10-23", + "2011-12-22", null])"; + const char* floor_15_months = + R"(["1970-01-01", "2000-01-01", "1898-10-01", "2032-07-01", "2020-01-01", + "2018-10-01", "2018-10-01", "2008-10-01", "2010-01-01", "2010-01-01", + "2010-01-01", "2005-01-01", "2005-01-01", "2008-10-01", "2008-10-01", + "2011-04-01", null])"; + const char* floor_15_quarters = + R"(["1970-01-01", "2000-01-01", "1898-10-01", "2030-01-01", "2018-10-01", + "2018-10-01", "2018-10-01", "2007-07-01", "2007-07-01", "2007-07-01", + "2007-07-01", "2003-10-01", "2003-10-01", "2007-07-01", "2007-07-01", + "2011-04-01", null])"; + const char* floor_15_years = + R"(["1965-01-01", "1995-01-01", "1890-01-01", "2025-01-01", "2010-01-01", + "2010-01-01", "2010-01-01", "1995-01-01", "2010-01-01", "2010-01-01", + "2010-01-01", "1995-01-01", "1995-01-01", "1995-01-01", "1995-01-01", + "2010-01-01", null])"; + + auto unit = timestamp(TimeUnit::NANO, "UTC"); + CheckScalarUnary(op, unit, times, unit, floor_1_nanosecond, &round_to_1_nanoseconds); + CheckScalarUnary(op, unit, times, unit, floor_1_microsecond, &round_to_1_microseconds); + CheckScalarUnary(op, unit, times, unit, floor_1_millisecond, &round_to_1_milliseconds); + CheckScalarUnary(op, unit, times, unit, floor_1_second, &round_to_1_seconds); + CheckScalarUnary(op, unit, times, unit, floor_1_minute, &round_to_1_minutes); + CheckScalarUnary(op, unit, times, unit, floor_1_hour, &round_to_1_hours); + CheckScalarUnary(op, unit, times, unit, floor_1_day, &round_to_1_days); + CheckScalarUnary(op, unit, times, unit, floor_1_weeks, &round_to_1_weeks); + CheckScalarUnary(op, unit, times, unit, floor_1_months, &round_to_1_months); + CheckScalarUnary(op, unit, times, unit, floor_1_quarters, &round_to_1_quarters); + CheckScalarUnary(op, unit, times, unit, floor_1_years, &round_to_1_years); + + CheckScalarUnary(op, unit, times, unit, floor_15_nanosecond, &round_to_15_nanoseconds); + CheckScalarUnary(op, unit, times, unit, floor_15_microsecond, + &round_to_15_microseconds); + CheckScalarUnary(op, unit, times, unit, floor_15_millisecond, + &round_to_15_milliseconds); + CheckScalarUnary(op, unit, times, unit, floor_15_second, &round_to_15_seconds); + CheckScalarUnary(op, unit, times, unit, floor_15_minute, &round_to_15_minutes); + CheckScalarUnary(op, unit, times, unit, floor_15_hour, &round_to_15_hours); + CheckScalarUnary(op, unit, times, unit, floor_15_day, &round_to_15_days); + CheckScalarUnary(op, unit, times, unit, floor_15_weeks, &round_to_15_weeks); + CheckScalarUnary(op, unit, times, unit, floor_15_months, &round_to_15_months); + CheckScalarUnary(op, unit, times, unit, floor_15_quarters, &round_to_15_quarters); + CheckScalarUnary(op, unit, times, unit, floor_15_years, &round_to_15_years); +} + +TEST_F(ScalarTemporalTest, TestRoundTemporal) { + std::string op = "round_temporal"; + const char* round_1_nanoseconds = + R"(["1970-01-01 00:00:59.123456789", "2000-02-29 23:23:23.999999999", + "1899-01-01 00:59:20.001001001", "2033-05-18 03:33:20.000000000", + "2020-01-01 01:05:05.001000000", "2019-12-31 02:10:10.002000000", + "2019-12-30 03:15:15.003000000", "2009-12-31 04:20:20.004132000", + "2010-01-01 05:25:25.005321000", "2010-01-03 06:30:30.006163000", + "2010-01-04 07:35:35.000000000", "2006-01-01 08:40:40.000000000", + "2005-12-31 09:45:45.000000000", "2008-12-28 00:00:00.000000000", + "2008-12-29 00:00:00.000000000", "2012-01-01 01:02:03.000000000", null])"; + const char* round_1_microseconds = + R"(["1970-01-01 00:00:59.123457", "2000-02-29 23:23:24.000000", + "1899-01-01 00:59:20.001001", "2033-05-18 03:33:20.000000", + "2020-01-01 01:05:05.001000", "2019-12-31 02:10:10.002000", + "2019-12-30 03:15:15.003000", "2009-12-31 04:20:20.004132", + "2010-01-01 05:25:25.005321", "2010-01-03 06:30:30.006163", + "2010-01-04 07:35:35.000000", "2006-01-01 08:40:40.000000", + "2005-12-31 09:45:45.000000", "2008-12-28 00:00:00.000000", + "2008-12-29 00:00:00.000000", "2012-01-01 01:02:03.000000", null])"; + const char* round_1_milliseconds = + R"(["1970-01-01 00:00:59.123", "2000-02-29 23:23:24.000", + "1899-01-01 00:59:20.001", "2033-05-18 03:33:20.000", + "2020-01-01 01:05:05.001", "2019-12-31 02:10:10.002", + "2019-12-30 03:15:15.003", "2009-12-31 04:20:20.004", + "2010-01-01 05:25:25.005", "2010-01-03 06:30:30.006", + "2010-01-04 07:35:35.000", "2006-01-01 08:40:40.000", + "2005-12-31 09:45:45.000", "2008-12-28 00:00:00.000", + "2008-12-29 00:00:00.000", "2012-01-01 01:02:03.000", null])"; + const char* round_1_seconds = + R"(["1970-01-01 00:00:59", "2000-02-29 23:23:24", "1899-01-01 00:59:20", + "2033-05-18 03:33:20", "2020-01-01 01:05:05", "2019-12-31 02:10:10", + "2019-12-30 03:15:15", "2009-12-31 04:20:20", "2010-01-01 05:25:25", + "2010-01-03 06:30:30", "2010-01-04 07:35:35", "2006-01-01 08:40:40", + "2005-12-31 09:45:45", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:02:03", null])"; + const char* round_1_minutes = + R"(["1970-01-01 00:01:00", "2000-02-29 23:23:00", "1899-01-01 00:59:00", + "2033-05-18 03:33:00", "2020-01-01 01:05:00", "2019-12-31 02:10:00", + "2019-12-30 03:15:00", "2009-12-31 04:20:00", "2010-01-01 05:25:00", + "2010-01-03 06:31:00", "2010-01-04 07:36:00", "2006-01-01 08:41:00", + "2005-12-31 09:46:00", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:02:00", null])"; + const char* round_1_hours = + R"(["1970-01-01 00:00:00", "2000-02-29 23:00:00", "1899-01-01 01:00:00", + "2033-05-18 04:00:00", "2020-01-01 01:00:00", "2019-12-31 02:00:00", + "2019-12-30 03:00:00", "2009-12-31 04:00:00", "2010-01-01 05:00:00", + "2010-01-03 07:00:00", "2010-01-04 08:00:00", "2006-01-01 09:00:00", + "2005-12-31 10:00:00", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:00:00", null])"; + const char* round_1_days = + R"(["1970-01-01", "2000-03-01", "1899-01-01", "2033-05-18", "2020-01-01", + "2019-12-31", "2019-12-30", "2009-12-31", "2010-01-01", "2010-01-03", + "2010-01-04", "2006-01-01", "2005-12-31", "2008-12-28", "2008-12-29", + "2012-01-01", null])"; + const char* round_1_weeks = + R"(["1970-01-01", "2000-03-02", "1898-12-29", "2033-05-19", "2020-01-02", + "2020-01-02", "2020-01-02", "2009-12-31", "2009-12-31", "2009-12-31", + "2010-01-07", "2005-12-29", "2005-12-29", "2008-12-25", "2009-01-01", + "2011-12-29", null])"; + const char* round_1_months = + R"(["1970-01-01", "2000-03-01", "1899-01-01", "2033-06-01", "2020-01-01", + "2020-01-01", "2020-01-01", "2010-01-01", "2010-01-01", "2010-01-01", + "2010-01-01", "2006-01-01", "2006-01-01", "2009-01-01", "2009-01-01", + "2012-01-01", null])"; + const char* round_1_quarters = + R"(["1970-01-01", "2000-04-01", "1899-01-01", "2033-07-01", "2020-01-01", + "2020-01-01", "2020-01-01", "2010-01-01", "2010-01-01", "2010-01-01", + "2010-01-01", "2006-01-01", "2006-01-01", "2009-01-01", "2009-01-01", + "2012-01-01", null])"; + const char* round_1_years = + R"(["1970-01-01", "2000-01-01", "1899-01-01", "2033-01-01", "2020-01-01", + "2020-01-01", "2020-01-01", "2010-01-01", "2010-01-01", "2010-01-01", + "2010-01-01", "2006-01-01", "2006-01-01", "2009-01-01", "2009-01-01", + "2012-01-01", null])"; + + const char* round_15_nanoseconds = + R"(["1970-01-01 00:00:59.123456790", "2000-02-29 23:23:24.000000000", + "1899-01-01 00:59:20.001001005", "2033-05-18 03:33:19.999999995", + "2020-01-01 01:05:05.001000000", "2019-12-31 02:10:10.002000000", + "2019-12-30 03:15:15.003000000", "2009-12-31 04:20:20.004132000", + "2010-01-01 05:25:25.005321000", "2010-01-03 06:30:30.006163005", + "2010-01-04 07:35:34.999999995", "2006-01-01 08:40:40.000000005", + "2005-12-31 09:45:45.000000000", "2008-12-28 00:00:00.000000000", + "2008-12-29 00:00:00.000000000", "2012-01-01 01:02:03.000000000", null])"; + const char* round_15_microseconds = + R"(["1970-01-01 00:00:59.123460", "2000-02-29 23:23:24.000000", + "1899-01-01 00:59:20.001000", "2033-05-18 03:33:19.999995", + "2020-01-01 01:05:05.001000", "2019-12-31 02:10:10.002000", + "2019-12-30 03:15:15.003000", "2009-12-31 04:20:20.004135", + "2010-01-01 05:25:25.005315", "2010-01-03 06:30:30.006165", + "2010-01-04 07:35:34.999995", "2006-01-01 08:40:40.000005", + "2005-12-31 09:45:45.000000", "2008-12-28 00:00:00.000000", + "2008-12-29 00:00:00.000000", "2012-01-01 01:02:03.000000", null])"; + const char* round_15_milliseconds = + R"(["1970-01-01 00:00:59.130", "2000-02-29 23:23:24.000", + "1899-01-01 00:59:19.995", "2033-05-18 03:33:19.995", + "2020-01-01 01:05:04.995", "2019-12-31 02:10:10.005", + "2019-12-30 03:15:15.000", "2009-12-31 04:20:20.010", + "2010-01-01 05:25:25.005", "2010-01-03 06:30:30.000", + "2010-01-04 07:35:34.995", "2006-01-01 08:40:40.005", + "2005-12-31 09:45:45.000", "2008-12-28 00:00:00.000", + "2008-12-29 00:00:00.000", "2012-01-01 01:02:03.000", null])"; + const char* round_15_seconds = + R"(["1970-01-01 00:01:00", "2000-02-29 23:23:30", "1899-01-01 00:59:15", + "2033-05-18 03:33:15", "2020-01-01 01:05:00", "2019-12-31 02:10:15", + "2019-12-30 03:15:15", "2009-12-31 04:20:15", "2010-01-01 05:25:30", + "2010-01-03 06:30:30", "2010-01-04 07:35:30", "2006-01-01 08:40:45", + "2005-12-31 09:45:45", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:02:00", null])"; + const char* round_15_minutes = + R"(["1970-01-01 00:00:00", "2000-02-29 23:30:00", "1899-01-01 01:00:00", + "2033-05-18 03:30:00", "2020-01-01 01:00:00", "2019-12-31 02:15:00", + "2019-12-30 03:15:00", "2009-12-31 04:15:00", "2010-01-01 05:30:00", + "2010-01-03 06:30:00", "2010-01-04 07:30:00", "2006-01-01 08:45:00", + "2005-12-31 09:45:00", "2008-12-28 00:00:00", "2008-12-29 00:00:00", + "2012-01-01 01:00:00", null])"; + const char* round_15_hours = + R"(["1970-01-01 00:00:00", "2000-02-29 21:00:00", "1899-01-01 03:00:00", + "2033-05-18 03:00:00", "2019-12-31 21:00:00", "2019-12-31 06:00:00", + "2019-12-30 00:00:00", "2009-12-31 09:00:00", "2010-01-01 00:00:00", + "2010-01-03 12:00:00", "2010-01-04 03:00:00", "2006-01-01 09:00:00", + "2005-12-31 03:00:00", "2008-12-28 06:00:00", "2008-12-28 21:00:00", + "2012-01-01 00:00:00", null])"; + const char* round_15_days = + R"(["1970-01-01", "2000-02-23", "1898-12-29", "2033-05-15", "2019-12-25", + "2019-12-25", "2019-12-25", "2010-01-01", "2010-01-01", "2010-01-01", + "2010-01-01", "2006-01-07", "2006-01-07", "2008-12-22", "2008-12-22", + "2012-01-06", null])"; + const char* round_15_weeks = + R"(["1970-01-01", "2000-03-09", "1898-12-29", "2033-03-31", "2020-01-09", + "2020-01-09", "2020-01-09", "2009-12-17", "2009-12-17", "2009-12-17", + "2009-12-17", "2005-12-08", "2005-12-08", "2009-02-05", "2009-02-05", + "2011-12-22", null])"; + const char* round_15_months = + R"(["1970-01-01", "2000-01-01", "1898-10-01", "2033-10-01", "2020-01-01", + "2020-01-01", "2020-01-01", "2010-01-01", "2010-01-01", "2010-01-01", + "2010-01-01", "2006-04-01", "2006-04-01", "2008-10-01", "2008-10-01", + "2012-07-01", null])"; + const char* round_15_quarters = + R"(["1970-01-01", "2000-01-01", "1898-10-01", "2033-10-01", "2018-10-01", + "2018-10-01", "2018-10-01", "2011-04-01", "2011-04-01", "2011-04-01", + "2011-04-01", "2007-07-01", "2007-07-01", "2007-07-01", "2007-07-01", + "2011-04-01", null])"; + const char* round_15_years = + R"(["1965-01-01", "1995-01-01", "1905-01-01", "2040-01-01", "2025-01-01", + "2025-01-01", "2025-01-01", "2010-01-01", "2010-01-01", "2010-01-01", + "2010-01-01", "2010-01-01", "2010-01-01", "2010-01-01", "2010-01-01", + "2010-01-01", null])"; + + auto unit = timestamp(TimeUnit::NANO, "UTC"); + CheckScalarUnary(op, unit, times, unit, round_1_nanoseconds, &round_to_1_nanoseconds); + CheckScalarUnary(op, unit, times, unit, round_1_microseconds, &round_to_1_microseconds); + CheckScalarUnary(op, unit, times, unit, round_1_milliseconds, &round_to_1_milliseconds); + CheckScalarUnary(op, unit, times, unit, round_1_seconds, &round_to_1_seconds); + CheckScalarUnary(op, unit, times, unit, round_1_minutes, &round_to_1_minutes); + CheckScalarUnary(op, unit, times, unit, round_1_hours, &round_to_1_hours); + CheckScalarUnary(op, unit, times, unit, round_1_days, &round_to_1_days); + CheckScalarUnary(op, unit, times, unit, round_1_weeks, &round_to_1_weeks); + CheckScalarUnary(op, unit, times, unit, round_1_months, &round_to_1_months); + CheckScalarUnary(op, unit, times, unit, round_1_quarters, &round_to_1_quarters); + CheckScalarUnary(op, unit, times, unit, round_1_years, &round_to_1_years); + + CheckScalarUnary(op, unit, times, unit, round_15_nanoseconds, &round_to_15_nanoseconds); + CheckScalarUnary(op, unit, times, unit, round_15_microseconds, + &round_to_15_microseconds); + CheckScalarUnary(op, unit, times, unit, round_15_milliseconds, + &round_to_15_milliseconds); + CheckScalarUnary(op, unit, times, unit, round_15_seconds, &round_to_15_seconds); + CheckScalarUnary(op, unit, times, unit, round_15_minutes, &round_to_15_minutes); + CheckScalarUnary(op, unit, times, unit, round_15_hours, &round_to_15_hours); + CheckScalarUnary(op, unit, times, unit, round_15_days, &round_to_15_days); + CheckScalarUnary(op, unit, times, unit, round_15_weeks, &round_to_15_weeks); + CheckScalarUnary(op, unit, times, unit, round_15_months, &round_to_15_months); + CheckScalarUnary(op, unit, times, unit, round_15_quarters, &round_to_15_quarters); + CheckScalarUnary(op, unit, times, unit, round_15_years, &round_to_15_years); +} + +TEST_F(ScalarTemporalTest, TestCeilFloorRoundTemporalBrussels) { + RoundTemporalOptions round_to_1_hours = RoundTemporalOptions(1, CalendarUnit::HOUR); + RoundTemporalOptions round_to_2_hours = RoundTemporalOptions(2, CalendarUnit::HOUR); + auto unit = timestamp(TimeUnit::NANO, "Europe/Brussels"); + + const char* times = R"(["2021-12-23 12:17:00", null])"; + const char* ceil_1_hours = R"(["2021-12-23 13:00", null])"; + const char* ceil_2_hours = R"(["2021-12-23 13:00", null])"; + const char* floor_1_hours = R"(["2021-12-23 12:00", null])"; + const char* floor_2_hours = R"(["2021-12-23 11:00", null])"; + const char* round_1_hours = R"(["2021-12-23 12:00", null])"; + const char* round_2_hours = R"(["2021-12-23 13:00", null])"; + + CheckScalarUnary("ceil_temporal", unit, times, unit, ceil_1_hours, &round_to_1_hours); + CheckScalarUnary("ceil_temporal", unit, times, unit, ceil_2_hours, &round_to_2_hours); + CheckScalarUnary("floor_temporal", unit, times, unit, floor_1_hours, &round_to_1_hours); + CheckScalarUnary("floor_temporal", unit, times, unit, floor_2_hours, &round_to_2_hours); + CheckScalarUnary("round_temporal", unit, times, unit, round_1_hours, &round_to_1_hours); + CheckScalarUnary("round_temporal", unit, times, unit, round_2_hours, &round_to_2_hours); +} + +TEST_F(ScalarTemporalTest, TestCeilFloorRoundTemporalKolkata) { + // Kolkata timezone was defined as UTC+5:21:10 from 1871 to 1906 when it changed to + // IST (UTC+05:30) without DST. This test is to check rounding is done in historical + // local time. + RoundTemporalOptions round_to_1_hours = RoundTemporalOptions(1, CalendarUnit::HOUR); + RoundTemporalOptions round_to_2_hours = RoundTemporalOptions(2, CalendarUnit::HOUR); + auto unit = timestamp(TimeUnit::NANO, "Asia/Kolkata"); + + const char* times = + R"(["2021-12-23 12:17", "1899-04-18 01:57:09.190202880", + "1899-09-12 07:03:30.080325120", "1904-06-21 20:55:36.493869056", null])"; + const char* ceil_1_hours = + R"(["2021-12-23 12:30", "1899-04-18 02:38:50", "1899-09-12 07:38:50", + "1904-06-21 21:38:50", null])"; + const char* ceil_2_hours = + R"(["2021-12-23 12:30", "1899-04-18 02:38:50", "1899-09-12 08:38:50", + "1904-06-21 22:38:50", null])"; + const char* floor_1_hours = + R"(["2021-12-23 11:30", "1899-04-18 01:38:50", "1899-09-12 06:38:50", + "1904-06-21 20:38:50", null])"; + const char* floor_2_hours = + R"(["2021-12-23 10:30", "1899-04-18 00:38:50", "1899-09-12 06:38:50", + "1904-06-21 20:38:50", null])"; + const char* round_1_hours = + R"(["2021-12-23 12:30", "1899-04-18 01:38:50", "1899-09-12 06:38:50", + "1904-06-21 20:38:50", null])"; + const char* round_2_hours = + R"(["2021-12-23 12:30", "1899-04-18 02:38:50", "1899-09-12 06:38:50", + "1904-06-21 20:38:50", null])"; + + CheckScalarUnary("ceil_temporal", unit, times, unit, ceil_1_hours, &round_to_1_hours); + CheckScalarUnary("ceil_temporal", unit, times, unit, ceil_2_hours, &round_to_2_hours); + CheckScalarUnary("floor_temporal", unit, times, unit, floor_1_hours, &round_to_1_hours); + CheckScalarUnary("floor_temporal", unit, times, unit, floor_2_hours, &round_to_2_hours); + CheckScalarUnary("round_temporal", unit, times, unit, round_1_hours, &round_to_1_hours); + CheckScalarUnary("round_temporal", unit, times, unit, round_2_hours, &round_to_2_hours); +} #endif // !_WIN32 } // namespace compute diff --git a/cpp/src/arrow/compute/kernels/scalar_temporal_unary.cc b/cpp/src/arrow/compute/kernels/scalar_temporal_unary.cc index c05ddd78928..be8c27ffc9e 100644 --- a/cpp/src/arrow/compute/kernels/scalar_temporal_unary.cc +++ b/cpp/src/arrow/compute/kernels/scalar_temporal_unary.cc @@ -37,17 +37,23 @@ namespace internal { namespace { +using arrow_vendored::date::ceil; using arrow_vendored::date::days; using arrow_vendored::date::floor; using arrow_vendored::date::hh_mm_ss; using arrow_vendored::date::local_days; using arrow_vendored::date::local_time; using arrow_vendored::date::locate_zone; +using arrow_vendored::date::Monday; +using arrow_vendored::date::months; +using arrow_vendored::date::round; +using arrow_vendored::date::Sunday; using arrow_vendored::date::sys_days; using arrow_vendored::date::sys_time; using arrow_vendored::date::trunc; using arrow_vendored::date::weekday; using arrow_vendored::date::weeks; +using arrow_vendored::date::year; using arrow_vendored::date::year_month_day; using arrow_vendored::date::year_month_weekday; using arrow_vendored::date::years; @@ -60,11 +66,15 @@ using arrow_vendored::date::literals::sun; using arrow_vendored::date::literals::thu; using arrow_vendored::date::literals::wed; using internal::applicator::SimpleUnary; +using std::chrono::duration_cast; +using std::chrono::hours; +using std::chrono::minutes; using DayOfWeekState = OptionsWrapper; using WeekState = OptionsWrapper; using StrftimeState = OptionsWrapper; using AssumeTimezoneState = OptionsWrapper; +using RoundTemporalState = OptionsWrapper; const std::shared_ptr& IsoCalendarType() { static auto type = struct_({field("iso_year", int64()), field("iso_week", int64()), @@ -128,6 +138,18 @@ struct TemporalComponentExtractWeek } }; +template