diff --git a/cpp/src/arrow/compute/api_scalar.cc b/cpp/src/arrow/compute/api_scalar.cc index 83aaee5f0fe..15570294851 100644 --- a/cpp/src/arrow/compute/api_scalar.cc +++ b/cpp/src/arrow/compute/api_scalar.cc @@ -245,8 +245,12 @@ static auto kMakeStructOptionsType = GetFunctionOptionsType( DataMember("field_nullability", &MakeStructOptions::field_nullability), DataMember("field_metadata", &MakeStructOptions::field_metadata)); static auto kDayOfWeekOptionsType = GetFunctionOptionsType( - DataMember("one_based_numbering", &DayOfWeekOptions::one_based_numbering), + DataMember("count_from_zero", &DayOfWeekOptions::count_from_zero), DataMember("week_start", &DayOfWeekOptions::week_start)); +static auto kWeekOptionsType = GetFunctionOptionsType( + DataMember("week_starts_monday", &WeekOptions::week_starts_monday), + DataMember("count_from_zero", &WeekOptions::count_from_zero), + DataMember("first_week_is_fully_in_year", &WeekOptions::first_week_is_fully_in_year)); static auto kNullOptionsType = GetFunctionOptionsType( DataMember("nan_is_null", &NullOptions::nan_is_null)); } // namespace @@ -406,12 +410,20 @@ MakeStructOptions::MakeStructOptions(std::vector n) MakeStructOptions::MakeStructOptions() : MakeStructOptions(std::vector()) {} constexpr char MakeStructOptions::kTypeName[]; -DayOfWeekOptions::DayOfWeekOptions(bool one_based_numbering, uint32_t week_start) +DayOfWeekOptions::DayOfWeekOptions(bool count_from_zero, uint32_t week_start) : FunctionOptions(internal::kDayOfWeekOptionsType), - one_based_numbering(one_based_numbering), + count_from_zero(count_from_zero), week_start(week_start) {} constexpr char DayOfWeekOptions::kTypeName[]; +WeekOptions::WeekOptions(bool week_starts_monday, bool count_from_zero, + bool first_week_is_fully_in_year) + : FunctionOptions(internal::kWeekOptionsType), + week_starts_monday(week_starts_monday), + count_from_zero(count_from_zero), + first_week_is_fully_in_year(first_week_is_fully_in_year) {} +constexpr char WeekOptions::kTypeName[]; + NullOptions::NullOptions(bool nan_is_null) : FunctionOptions(internal::kNullOptionsType), nan_is_null(nan_is_null) {} constexpr char NullOptions::kTypeName[]; @@ -438,6 +450,7 @@ void RegisterScalarOptions(FunctionRegistry* registry) { DCHECK_OK(registry->AddFunctionOptionsType(kSliceOptionsType)); DCHECK_OK(registry->AddFunctionOptionsType(kMakeStructOptionsType)); DCHECK_OK(registry->AddFunctionOptionsType(kDayOfWeekOptionsType)); + DCHECK_OK(registry->AddFunctionOptionsType(kWeekOptionsType)); DCHECK_OK(registry->AddFunctionOptionsType(kNullOptionsType)); } } // namespace internal @@ -629,6 +642,7 @@ SCALAR_EAGER_UNARY(Day, "day") SCALAR_EAGER_UNARY(DayOfYear, "day_of_year") SCALAR_EAGER_UNARY(ISOYear, "iso_year") SCALAR_EAGER_UNARY(ISOWeek, "iso_week") +SCALAR_EAGER_UNARY(USWeek, "us_week") SCALAR_EAGER_UNARY(ISOCalendar, "iso_calendar") SCALAR_EAGER_UNARY(Quarter, "quarter") SCALAR_EAGER_UNARY(Hour, "hour") @@ -648,6 +662,10 @@ Result AssumeTimezone(const Datum& arg, AssumeTimezoneOptions options, return CallFunction("assume_timezone", {arg}, &options, ctx); } +Result Week(const Datum& arg, WeekOptions options, ExecContext* ctx) { + return CallFunction("week", {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 05e2ff30f5f..58aac3f485c 100644 --- a/cpp/src/arrow/compute/api_scalar.h +++ b/cpp/src/arrow/compute/api_scalar.h @@ -317,12 +317,12 @@ class ARROW_EXPORT MakeStructOptions : public FunctionOptions { struct ARROW_EXPORT DayOfWeekOptions : public FunctionOptions { public: - explicit DayOfWeekOptions(bool one_based_numbering = false, uint32_t week_start = 1); + explicit DayOfWeekOptions(bool count_from_zero = true, uint32_t week_start = 1); constexpr static char const kTypeName[] = "DayOfWeekOptions"; static DayOfWeekOptions Defaults() { return DayOfWeekOptions(); } - /// Number days from 1 if true and from 0 if false - bool one_based_numbering; + /// Number days from 0 if true and from 1 if false + bool count_from_zero; /// What day does the week start with (Monday=1, Sunday=7) uint32_t week_start; }; @@ -361,6 +361,33 @@ struct ARROW_EXPORT AssumeTimezoneOptions : public FunctionOptions { Nonexistent nonexistent; }; +struct ARROW_EXPORT WeekOptions : public FunctionOptions { + public: + explicit WeekOptions(bool week_starts_monday = true, bool count_from_zero = false, + bool first_week_is_fully_in_year = false); + constexpr static char const kTypeName[] = "WeekOptions"; + static WeekOptions Defaults() { return WeekOptions{}; } + static WeekOptions ISODefaults() { + return WeekOptions{/*week_starts_monday*/ true, + /*count_from_zero=*/false, + /*first_week_is_fully_in_year=*/false}; + } + static WeekOptions USDefaults() { + return WeekOptions{/*week_starts_monday*/ false, + /*count_from_zero=*/false, + /*first_week_is_fully_in_year=*/false}; + } + + /// What day does the week start with (Monday=true, Sunday=false) + bool week_starts_monday; + /// Dates from current year that fall into last ISO week of the previous year return + /// 0 if true and 52 or 53 if false. + bool count_from_zero; + /// Must the first week be fully in January (true), or is a week that begins on + /// December 29, 30, or 31 considered to be the first week of the new year (false)? + bool first_week_is_fully_in_year; +}; + /// @} /// \brief Get the absolute value of a value. @@ -1008,7 +1035,8 @@ Result ISOYear(const Datum& values, ExecContext* ctx = NULLPTR); /// \brief ISOWeek returns ISO week of year number for each element of `values`. /// First ISO week has the majority (4 or more) of its days in January. -/// Week of the year starts with 1 and can run up to 53. +/// ISO week starts on Monday. Year can have 52 or 53 weeks. +/// Week numbering can start with 1. /// /// \param[in] values input to extract ISO week of year from /// \param[in] ctx the function execution context, optional @@ -1018,6 +1046,34 @@ Result ISOYear(const Datum& values, ExecContext* ctx = NULLPTR); /// \note API not yet finalized ARROW_EXPORT Result ISOWeek(const Datum& values, ExecContext* ctx = NULLPTR); +/// \brief USWeek returns US week of year number for each element of `values`. +/// First US week has the majority (4 or more) of its days in January. +/// US week starts on Sunday. Year can have 52 or 53 weeks. +/// Week numbering starts with 1. +/// +/// \param[in] values input to extract US week of year from +/// \param[in] ctx the function execution context, optional +/// \return the resulting datum +/// +/// \since 6.0.0 +/// \note API not yet finalized +ARROW_EXPORT Result USWeek(const Datum& values, ExecContext* ctx = NULLPTR); + +/// \brief Week returns week of year number for each element of `values`. +/// First ISO week has the majority (4 or more) of its days in January. +/// Year can have 52 or 53 weeks. Week numbering can start with 0 or 1 +/// depending on DayOfWeekOptions.count_from_zero. +/// +/// \param[in] values input to extract week of year from +/// \param[in] options for setting numbering start +/// \param[in] ctx the function execution context, optional +/// \return the resulting datum +/// +/// \since 6.0.0 +/// \note API not yet finalized +ARROW_EXPORT Result Week(const Datum& values, WeekOptions options = WeekOptions(), + ExecContext* ctx = NULLPTR); + /// \brief ISOCalendar returns a (ISO year, ISO week, ISO day of week) struct for /// each element of `values`. /// ISO week starts on Monday denoted by 1 and ends on Sunday denoted by 7. diff --git a/cpp/src/arrow/compute/function_test.cc b/cpp/src/arrow/compute/function_test.cc index 183167490b6..626824d73ec 100644 --- a/cpp/src/arrow/compute/function_test.cc +++ b/cpp/src/arrow/compute/function_test.cc @@ -104,6 +104,7 @@ TEST(FunctionOptions, Equality) { options.emplace_back( new MakeStructOptions({"col1"}, {false}, {key_value_metadata({{"key", "val"}})})); options.emplace_back(new DayOfWeekOptions(false, 1)); + options.emplace_back(new WeekOptions(true, false, false)); options.emplace_back(new CastOptions(CastOptions::Safe(boolean()))); options.emplace_back(new CastOptions(CastOptions::Unsafe(int64()))); options.emplace_back(new FilterOptions()); diff --git a/cpp/src/arrow/compute/kernels/scalar_temporal.cc b/cpp/src/arrow/compute/kernels/scalar_temporal.cc index 396eec842ae..190ed50e81f 100644 --- a/cpp/src/arrow/compute/kernels/scalar_temporal.cc +++ b/cpp/src/arrow/compute/kernels/scalar_temporal.cc @@ -55,11 +55,14 @@ using arrow_vendored::date::literals::dec; using arrow_vendored::date::literals::jan; using arrow_vendored::date::literals::last; using arrow_vendored::date::literals::mon; +using arrow_vendored::date::literals::sun; using arrow_vendored::date::literals::thu; +using arrow_vendored::date::literals::wed; using internal::applicator::ScalarUnaryNotNull; using internal::applicator::SimpleUnary; using DayOfWeekState = OptionsWrapper; +using WeekState = OptionsWrapper; using StrftimeState = OptionsWrapper; using AssumeTimezoneState = OptionsWrapper; @@ -230,6 +233,18 @@ struct AssumeTimezoneExtractor } }; +template