Skip to content

Commit

Permalink
Add quarters to libcudf datetime (#8779)
Browse files Browse the repository at this point in the history
Partly addresses #8676.
This PR adds `date_time:: extract_quarter`. The function returns an int `(1,2,3,4)` depending on which quarter of the year the date is in. Also fixed an incorrect date in previous testcase (#8711).

Authors:
  - https://github.com/shaneding

Approvers:
  - Nghia Truong (https://github.com/ttnghia)
  - Conor Hoekstra (https://github.com/codereport)

URL: #8779
  • Loading branch information
shaneding authored Jul 26, 2021
1 parent 7bb16fa commit 756499f
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 1 deletion.
15 changes: 15 additions & 0 deletions cpp/include/cudf/datetime.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,21 @@ std::unique_ptr<cudf::column> is_leap_year(
cudf::column_view const& column,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource());

/**
* @brief Returns the quarter of the date
*
* `output[i]` will be a value from {1, 2, 3, 4} corresponding to the quater of month given by
* `column[i]`. It will be null if the input row at `column[i]` is null.
*
* @throw cudf::logic_error if input column datatype is not a TIMESTAMP
*
* @param The input column containing datetime values
* @return A column of INT16 type indicating which quarter the date is in
*/
std::unique_ptr<cudf::column> extract_quarter(
cudf::column_view const& column,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource());

/** @} */ // end of group
} // namespace datetime
} // namespace cudf
5 changes: 5 additions & 0 deletions cpp/include/cudf/detail/datetime.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ std::unique_ptr<cudf::column> is_leap_year(
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource());

std::unique_ptr<cudf::column> extract_quarter(
cudf::column_view const& column,
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource());

} // namespace detail
} // namespace datetime
} // namespace cudf
31 changes: 31 additions & 0 deletions cpp/src/datetime/datetime_ops.cu
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,23 @@ struct extract_day_num_of_year {
}
};

// Extract the the quarter to which the timestamp belongs to
struct extract_quarter_op {
template <typename Timestamp>
CUDA_DEVICE_CALLABLE int16_t operator()(Timestamp const ts) const
{
using namespace cuda::std::chrono;

// Only has the days - time component is chopped off, which is what we want
auto const days_since_epoch = floor<days>(ts);
auto const date = year_month_day(days_since_epoch);
auto const month = unsigned{date.month()};

// (x + y - 1) / y = ceil(x/y), where x and y are unsigned. x = month, y = 3
return (month + 2) / 3;
}
};

struct is_leap_year_op {
template <typename Timestamp>
CUDA_DEVICE_CALLABLE bool operator()(Timestamp const ts) const
Expand Down Expand Up @@ -376,6 +393,13 @@ std::unique_ptr<column> is_leap_year(column_view const& column,
return apply_datetime_op<is_leap_year_op, type_id::BOOL8>(column, stream, mr);
}

std::unique_ptr<column> extract_quarter(column_view const& column,
rmm::cuda_stream_view stream,
rmm::mr::device_memory_resource* mr)
{
return apply_datetime_op<extract_quarter_op, type_id::INT16>(column, stream, mr);
}

} // namespace detail

std::unique_ptr<column> extract_year(column_view const& column, rmm::mr::device_memory_resource* mr)
Expand Down Expand Up @@ -452,5 +476,12 @@ std::unique_ptr<column> is_leap_year(column_view const& column, rmm::mr::device_
return detail::is_leap_year(column, rmm::cuda_stream_default, mr);
}

std::unique_ptr<column> extract_quarter(column_view const& column,
rmm::mr::device_memory_resource* mr)
{
CUDF_FUNC_RANGE();
return detail::extract_quarter(column, rmm::cuda_stream_default, mr);
}

} // namespace datetime
} // namespace cudf
38 changes: 37 additions & 1 deletion cpp/tests/datetime/datetime_ops_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <cudf_test/base_fixture.hpp>
#include <cudf_test/column_utilities.hpp>
#include <cudf_test/column_wrapper.hpp>
#include <cudf_test/iterator_utilities.hpp>
#include <cudf_test/timestamp_utilities.cuh>
#include <cudf_test/type_lists.hpp>

Expand Down Expand Up @@ -552,7 +553,7 @@ TEST_F(BasicDatetimeOpsTest, TestIsLeapYear)
915148800L, // 1999-01-01 00:00:00 GMT - non leap year
-11663029161L, // 1600-5-31 05:40:39 GMT - leap year
707904541L, // 1992-06-07 08:09:01 GMT - leap year
2181048447L, // 1900-11-20 09:12:33 GMT - non leap year
-2181005247L, // 1900-11-20 09:12:33 GMT - non leap year
0L, // UNIX EPOCH 1970-01-01 00:00:00 GMT - non leap year
-12212553600L, // First full year of Gregorian Calandar 1583-01-01 00:00:00 - non-leap-year
0L, // null
Expand All @@ -569,4 +570,39 @@ TEST_F(BasicDatetimeOpsTest, TestIsLeapYear)
{true, false, true, true, true, true, true, true, false, true, true, false}});
}

TEST_F(BasicDatetimeOpsTest, TestQuarter)
{
using namespace cudf::test;
using namespace cudf::datetime;
using namespace cuda::std::chrono;
using namespace cudf::test::iterators;

// Time in seconds since epoch
// Dates converted using epochconverter.com
auto timestamps_s =
cudf::test::fixed_width_column_wrapper<cudf::timestamp_s, cudf::timestamp_s::rep>{
{
1594332839L, // 2020-07-09 10:13:59 GMT
0L, // null
915148800L, // 1999-01-01 00:00:00 GMT
-11663029161L, // 1600-5-31 05:40:39 GMT
707904541L, // 1992-06-07 08:09:01 GMT
-2181005247L, // 1900-11-20 09:12:33 GMT
0L, // UNIX EPOCH 1970-01-01 00:00:00 GMT
-12212553600L, // First full year of Gregorian Calandar 1583-01-01 00:00:00
0L, // null
13591632822L, // 2400-09-13 13:33:42 GMT
4539564243L, // 2113-11-08 06:04:03 GMT
0L, // null
1608581568L, // 2020-12-21 08:12:48 GMT
1584821568L, // 2020-03-21 08:12:48 GMT
},
nulls_at({1, 8, 11})};

auto quarter = cudf::test::fixed_width_column_wrapper<int16_t>{
{3, 0 /*null*/, 1, 2, 2, 4, 1, 1, 0 /*null*/, 3, 4, 0 /*null*/, 4, 1}, nulls_at({1, 8, 11})};

CUDF_TEST_EXPECT_COLUMNS_EQUAL(*extract_quarter(timestamps_s), quarter);
}

CUDF_TEST_PROGRAM_MAIN()

0 comments on commit 756499f

Please sign in to comment.