diff --git a/cpp/src/arrow/compute/api_scalar.cc b/cpp/src/arrow/compute/api_scalar.cc index 771ef4d24c1..6d92a6531de 100644 --- a/cpp/src/arrow/compute/api_scalar.cc +++ b/cpp/src/arrow/compute/api_scalar.cc @@ -331,7 +331,8 @@ static auto kRoundOptionsType = GetFunctionOptionsType( DataMember("round_mode", &RoundOptions::round_mode)); static auto kRoundTemporalOptionsType = GetFunctionOptionsType( DataMember("multiple", &RoundTemporalOptions::multiple), - DataMember("unit", &RoundTemporalOptions::unit)); + DataMember("unit", &RoundTemporalOptions::unit), + DataMember("week_starts_monday", &RoundTemporalOptions::week_starts_monday)); static auto kRoundToMultipleOptionsType = GetFunctionOptionsType( DataMember("multiple", &RoundToMultipleOptions::multiple), DataMember("round_mode", &RoundToMultipleOptions::round_mode)); @@ -488,10 +489,12 @@ RoundOptions::RoundOptions(int64_t ndigits, RoundMode round_mode) } constexpr char RoundOptions::kTypeName[]; -RoundTemporalOptions::RoundTemporalOptions(int multiple, CalendarUnit unit) +RoundTemporalOptions::RoundTemporalOptions(int multiple, CalendarUnit unit, + bool week_starts_monday) : FunctionOptions(internal::kRoundTemporalOptionsType), multiple(std::move(multiple)), - unit(unit) {} + unit(unit), + week_starts_monday(week_starts_monday) {} constexpr char RoundTemporalOptions::kTypeName[]; RoundToMultipleOptions::RoundToMultipleOptions(double multiple, RoundMode round_mode) diff --git a/cpp/src/arrow/compute/api_scalar.h b/cpp/src/arrow/compute/api_scalar.h index cf0ff83fb06..41e8d5a49c2 100644 --- a/cpp/src/arrow/compute/api_scalar.h +++ b/cpp/src/arrow/compute/api_scalar.h @@ -106,7 +106,8 @@ enum class CalendarUnit : int8_t { class ARROW_EXPORT RoundTemporalOptions : public FunctionOptions { public: - explicit RoundTemporalOptions(int multiple = 1, CalendarUnit unit = CalendarUnit::DAY); + explicit RoundTemporalOptions(int multiple = 1, CalendarUnit unit = CalendarUnit::DAY, + bool week_starts_monday = true); static constexpr char const kTypeName[] = "RoundTemporalOptions"; static RoundTemporalOptions Defaults() { return RoundTemporalOptions(); } @@ -114,6 +115,8 @@ class ARROW_EXPORT RoundTemporalOptions : public FunctionOptions { int multiple; /// The unit used for rounding of time CalendarUnit unit; + /// What day does the week start with (Monday=true, Sunday=false) + bool week_starts_monday; }; class ARROW_EXPORT RoundToMultipleOptions : public FunctionOptions { diff --git a/cpp/src/arrow/compute/function_test.cc b/cpp/src/arrow/compute/function_test.cc index 1653224ee05..3f5f7c08d66 100644 --- a/cpp/src/arrow/compute/function_test.cc +++ b/cpp/src/arrow/compute/function_test.cc @@ -64,7 +64,7 @@ TEST(FunctionOptions, Equality) { options.emplace_back(new RoundTemporalOptions()); options.emplace_back(new RoundTemporalOptions( /*multiple=*/2, - /*unit=*/CalendarUnit::WEEK)); + /*unit=*/CalendarUnit::WEEK, /*week_starts_monday*/ true)); 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 ff7a169094f..38b810902ba 100644 --- a/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc +++ b/cpp/src/arrow/compute/kernels/scalar_temporal_test.cc @@ -379,7 +379,10 @@ class ScalarTemporalTest : public ::testing::Test { 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_weeks = + RoundTemporalOptions(1, CalendarUnit::WEEK, true); + RoundTemporalOptions round_to_1_weeks_sunday = + RoundTemporalOptions(1, CalendarUnit::WEEK, false); RoundTemporalOptions round_to_1_months = RoundTemporalOptions(1, CalendarUnit::MONTH); RoundTemporalOptions round_to_1_quarters = RoundTemporalOptions(1, CalendarUnit::QUARTER); @@ -396,7 +399,10 @@ class ScalarTemporalTest : public ::testing::Test { 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_weeks = + RoundTemporalOptions(15, CalendarUnit::WEEK, true); + RoundTemporalOptions round_to_15_weeks_sunday = + RoundTemporalOptions(15, CalendarUnit::WEEK, false); RoundTemporalOptions round_to_15_months = RoundTemporalOptions(15, CalendarUnit::MONTH); RoundTemporalOptions round_to_15_quarters = RoundTemporalOptions(15, CalendarUnit::QUARTER); @@ -2001,10 +2007,15 @@ TEST_F(ScalarTemporalTest, TestCeilTemporal) { "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])"; + R"(["1970-01-05", "2000-03-06", "1899-01-02", "2033-05-23", "2020-01-06", + "2020-01-06", "2020-01-06", "2010-01-04", "2010-01-04", "2010-01-04", + "2010-01-11", "2006-01-02", "2006-01-02", "2008-12-29", "2008-12-29", + "2012-01-02", null])"; + const char* ceil_1_weeks_sunday = + R"(["1970-01-04", "2000-03-05", "1899-01-08", "2033-05-22", "2020-01-05", + "2020-01-05", "2020-01-05", "2010-01-03", "2010-01-03", "2010-01-10", + "2010-01-10", "2006-01-08", "2006-01-01", "2008-12-28", "2009-01-04", + "2012-01-08", 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", @@ -2074,10 +2085,15 @@ TEST_F(ScalarTemporalTest, TestCeilTemporal) { "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])"; + R"(["1970-04-13", "2000-03-06", "1899-04-10", "2033-07-11", "2020-01-06", + "2020-01-06", "2020-01-06", "2010-03-29", "2010-03-29", "2010-03-29", + "2010-03-29", "2006-03-20", "2006-03-20", "2009-02-02", "2009-02-02", + "2012-04-02", null])"; + const char* ceil_15_weeks_sunday = + R"(["1970-04-12", "2000-03-05", "1899-04-09", "2033-07-10", "2020-01-05", + "2020-01-05", "2020-01-05", "2010-03-28", "2010-03-28", "2010-03-28", + "2010-03-28", "2006-03-19", "2006-03-19", "2009-02-01", "2009-02-01", + "2012-04-01", 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", @@ -2103,6 +2119,7 @@ TEST_F(ScalarTemporalTest, TestCeilTemporal) { 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_weeks_sunday, &round_to_1_weeks_sunday); 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); @@ -2115,6 +2132,8 @@ TEST_F(ScalarTemporalTest, TestCeilTemporal) { 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_weeks_sunday, + &round_to_15_weeks_sunday); 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); @@ -2176,10 +2195,15 @@ TEST_F(ScalarTemporalTest, TestFloorTemporal) { "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])"; + R"(["1969-12-29", "2000-02-28", "1898-12-26", "2033-05-16", "2019-12-30", + "2019-12-30", "2019-12-30", "2009-12-28", "2009-12-28", "2009-12-28", + "2010-01-04", "2005-12-26", "2005-12-26", "2008-12-22", "2008-12-29", + "2011-12-26", null])"; + const char* floor_1_weeks_sunday = + R"(["1969-12-28", "2000-02-27", "1899-01-01", "2033-05-15", "2019-12-29", + "2019-12-29", "2019-12-29", "2009-12-27", "2009-12-27", "2010-01-03", + "2010-01-03", "2006-01-01", "2005-12-25", "2008-12-28", "2008-12-28", + "2012-01-01", 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", @@ -2250,10 +2274,15 @@ TEST_F(ScalarTemporalTest, TestFloorTemporal) { "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])"; + R"(["1969-12-29", "1999-11-22", "1898-12-26", "2033-03-28", "2019-09-23", + "2019-09-23", "2019-09-23", "2009-12-14", "2009-12-14", "2009-12-14", + "2009-12-14", "2005-12-05", "2005-12-05", "2008-10-20", "2008-10-20", + "2011-12-19", null])"; + const char* floor_15_weeks_sunday = + R"(["1969-12-28", "1999-11-21", "1898-12-25", "2033-03-27", "2019-09-22", + "2019-09-22", "2019-09-22", "2009-12-13", "2009-12-13", "2009-12-13", + "2009-12-13", "2005-12-04", "2005-12-04", "2008-10-19", "2008-10-19", + "2011-12-18", 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", @@ -2279,6 +2308,7 @@ TEST_F(ScalarTemporalTest, TestFloorTemporal) { 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_weeks_sunday, &round_to_1_weeks_sunday); 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); @@ -2293,6 +2323,8 @@ TEST_F(ScalarTemporalTest, TestFloorTemporal) { 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_weeks_sunday, + &round_to_15_weeks_sunday); 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); @@ -2354,10 +2386,15 @@ TEST_F(ScalarTemporalTest, TestRoundTemporal) { "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])"; + R"(["1969-12-29", "2000-02-28", "1899-01-02", "2033-05-16", "2019-12-30", + "2019-12-30", "2019-12-30", "2009-12-28", "2010-01-04", "2010-01-04", + "2010-01-04", "2006-01-02", "2006-01-02", "2008-12-29", "2008-12-29", + "2012-01-02", null])"; + const char* round_1_weeks_sunday = + R"(["1970-01-04", "2000-02-27", "1899-01-01", "2033-05-15", "2019-12-29", + "2019-12-29", "2019-12-29", "2010-01-03", "2010-01-03", "2010-01-03", + "2010-01-03", "2006-01-01", "2006-01-01", "2008-12-28", "2008-12-28", + "2012-01-01", 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", @@ -2428,10 +2465,15 @@ TEST_F(ScalarTemporalTest, TestRoundTemporal) { "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])"; + R"(["1969-12-29", "2000-03-06", "1898-12-26", "2033-03-28", "2020-01-06", + "2020-01-06", "2020-01-06", "2009-12-14", "2009-12-14", "2009-12-14", + "2009-12-14", "2005-12-05", "2005-12-05", "2009-02-02", "2009-02-02", + "2011-12-19", null])"; + const char* round_15_weeks_sunday = + R"(["1969-12-28", "2000-03-05", "1898-12-25", "2033-03-27", "2020-01-05", + "2020-01-05", "2020-01-05", "2009-12-13", "2009-12-13", "2009-12-13", + "2009-12-13", "2005-12-04", "2005-12-04", "2009-02-01", "2009-02-01", + "2011-12-18", 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", @@ -2457,6 +2499,7 @@ TEST_F(ScalarTemporalTest, TestRoundTemporal) { 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_weeks_sunday, &round_to_1_weeks_sunday); 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); @@ -2471,6 +2514,8 @@ TEST_F(ScalarTemporalTest, TestRoundTemporal) { 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_weeks_sunday, + &round_to_15_weeks_sunday); 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); diff --git a/cpp/src/arrow/compute/kernels/scalar_temporal_unary.cc b/cpp/src/arrow/compute/kernels/scalar_temporal_unary.cc index dd5d6343d26..ed08c367664 100644 --- a/cpp/src/arrow/compute/kernels/scalar_temporal_unary.cc +++ b/cpp/src/arrow/compute/kernels/scalar_temporal_unary.cc @@ -725,6 +725,27 @@ const Duration FloorTimePoint(const int64_t arg, const int64_t multiple, } } +template +const Duration FloorWeekTimePoint(const int64_t arg, const int64_t multiple, + Localizer localizer_, const Duration weekday_offset, + Status* st) { + const auto t = localizer_.template ConvertTimePoint(arg) + weekday_offset; + const weeks d = floor(t).time_since_epoch(); + + if (multiple == 1) { + return localizer_.template ConvertLocalToSys(duration_cast(d), + st) - + weekday_offset; + } else { + const weeks unit = weeks{multiple}; + const weeks m = + (d.count() >= 0) ? d / unit * unit : (d - unit + weeks{1}) / unit * unit; + return localizer_.template ConvertLocalToSys(duration_cast(m), + st) - + weekday_offset; + } +} + template Duration CeilTimePoint(const int64_t arg, const int64_t multiple, Localizer localizer_, Status* st) { @@ -741,6 +762,23 @@ Duration CeilTimePoint(const int64_t arg, const int64_t multiple, Localizer loca duration_cast(cl + duration_cast(Unit{multiple})), st); } +template +Duration CeilWeekTimePoint(const int64_t arg, const int64_t multiple, + Localizer localizer_, const Duration weekday_offset, + Status* st) { + const Duration f = FloorWeekTimePoint(arg, multiple, localizer_, + weekday_offset, st); + const auto cl = + localizer_.template ConvertTimePoint(f.count()).time_since_epoch(); + const Duration cs = + localizer_.template ConvertLocalToSys(duration_cast(cl), st); + if (cs >= Duration{arg}) { + return cs; + } + return localizer_.template ConvertLocalToSys( + duration_cast(cl + duration_cast(weeks{multiple})), st); +} + template Duration RoundTimePoint(const int64_t arg, const int64_t multiple, Localizer localizer_, Status* st) { @@ -751,6 +789,17 @@ Duration RoundTimePoint(const int64_t arg, const int64_t multiple, Localizer loc return (Duration{arg} - f >= c - Duration{arg}) ? c : f; } +template +Duration RoundWeekTimePoint(const int64_t arg, const int64_t multiple, + Localizer localizer_, const Duration weekday_offset, + Status* st) { + const Duration f = FloorWeekTimePoint(arg, multiple, localizer_, + weekday_offset, st); + const Duration c = CeilWeekTimePoint(arg, multiple, localizer_, + weekday_offset, st); + return (Duration{arg} - f >= c - Duration{arg}) ? c : f; +} + template struct CeilTemporal { explicit CeilTemporal(const RoundTemporalOptions* options, Localizer&& localizer) @@ -789,8 +838,13 @@ struct CeilTemporal { st); break; case compute::CalendarUnit::WEEK: - t = CeilTimePoint(arg, options.multiple, localizer_, - st); + if (options.week_starts_monday) { + t = CeilWeekTimePoint(arg, options.multiple, localizer_, + days{3}, st); + } else { + t = CeilWeekTimePoint(arg, options.multiple, localizer_, + days{4}, st); + } break; case compute::CalendarUnit::MONTH: { year_month_day ymd = @@ -862,8 +916,13 @@ struct FloorTemporal { st); break; case compute::CalendarUnit::WEEK: - t = FloorTimePoint(arg, options.multiple, localizer_, - st); + if (options.week_starts_monday) { + t = FloorWeekTimePoint(arg, options.multiple, localizer_, + days{3}, st); + } else { + t = FloorWeekTimePoint(arg, options.multiple, localizer_, + days{4}, st); + } break; case compute::CalendarUnit::MONTH: { year_month_day ymd = @@ -932,8 +991,13 @@ struct RoundTemporal { st); break; case compute::CalendarUnit::WEEK: - t = RoundTimePoint(arg, options.multiple, localizer_, - st); + if (options.week_starts_monday) { + t = RoundWeekTimePoint(arg, options.multiple, localizer_, + days{3}, st); + } else { + t = RoundWeekTimePoint(arg, options.multiple, localizer_, + days{4}, st); + } break; case compute::CalendarUnit::MONTH: { auto t0 = localizer_.template ConvertTimePoint(arg); diff --git a/python/pyarrow/_compute.pyx b/python/pyarrow/_compute.pyx index e6a1dd20261..c6b33f26baf 100644 --- a/python/pyarrow/_compute.pyx +++ b/python/pyarrow/_compute.pyx @@ -867,10 +867,11 @@ cdef CCalendarUnit unwrap_round_temporal_unit(unit) except *: cdef class _RoundTemporalOptions(FunctionOptions): - def _set_options(self, multiple, unit): + def _set_options(self, multiple, unit, week_starts_monday): self.wrapped.reset( new CRoundTemporalOptions( - multiple, unwrap_round_temporal_unit(unit)) + multiple, unwrap_round_temporal_unit(unit), + week_starts_monday) ) @@ -887,10 +888,12 @@ class RoundTemporalOptions(_RoundTemporalOptions): Accepted values are "year", "quarter", "month", "week", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond". + week_starts_monday : bool, default True + If True, weeks start on Monday; if False, on Sunday. """ - def __init__(self, multiple=1, unit="day"): - self._set_options(multiple, unit) + def __init__(self, multiple=1, unit="day", week_starts_monday=True): + self._set_options(multiple, unit, week_starts_monday) cdef class _RoundToMultipleOptions(FunctionOptions): diff --git a/python/pyarrow/includes/libarrow.pxd b/python/pyarrow/includes/libarrow.pxd index 9469fd54f9a..d7666ec9129 100644 --- a/python/pyarrow/includes/libarrow.pxd +++ b/python/pyarrow/includes/libarrow.pxd @@ -1947,9 +1947,11 @@ cdef extern from "arrow/compute/api.h" namespace "arrow::compute" nogil: cdef cppclass CRoundTemporalOptions \ "arrow::compute::RoundTemporalOptions"(CFunctionOptions): - CRoundTemporalOptions(int multiple, CCalendarUnit unit) + CRoundTemporalOptions(int multiple, CCalendarUnit unit, + c_bool week_starts_monday) int multiple CCalendarUnit unit + c_bool week_starts_monday cdef cppclass CRoundToMultipleOptions \ "arrow::compute::RoundToMultipleOptions"(CFunctionOptions): diff --git a/python/pyarrow/tests/test_compute.py b/python/pyarrow/tests/test_compute.py index 71d2517e384..11af634dfc8 100644 --- a/python/pyarrow/tests/test_compute.py +++ b/python/pyarrow/tests/test_compute.py @@ -152,7 +152,7 @@ def test_option_class_equality(): pc.ReplaceSliceOptions(0, 1, "a"), pc.ReplaceSubstringOptions("a", "b"), pc.RoundOptions(2, "towards_infinity"), - pc.RoundTemporalOptions(1, "second"), + pc.RoundTemporalOptions(1, "second", True), pc.RoundToMultipleOptions(100, "towards_infinity"), pc.ScalarAggregateOptions(), pc.SelectKOptions(0, sort_keys=[("b", "ascending")]),