diff --git a/python/cudf/cudf/core/series.py b/python/cudf/cudf/core/series.py index 855ec8d3e67..b15a7b01db6 100644 --- a/python/cudf/cudf/core/series.py +++ b/python/cudf/cudf/core/series.py @@ -6050,7 +6050,7 @@ def is_month_end(self): ------- >>> import pandas as pd, cudf >>> s = cudf.Series( - ... pd.date_range(start='2000-08-026', end='2000-09-03', freq='1D')) + ... pd.date_range(start='2000-08-26', end='2000-09-03', freq='1D')) >>> s 0 2000-08-26 1 2000-08-27 @@ -6082,6 +6082,100 @@ def is_month_end(self): ) return (self.day == last_day.dt.day).fillna(False) + @property + def is_quarter_start(self): + """ + Boolean indicator if the date is the first day of a quarter. + + Returns + ------- + Series + Booleans indicating if dates are the begining of a quarter + + Example + ------- + >>> import pandas as pd, cudf + >>> s = cudf.Series( + ... pd.date_range(start='2000-09-26', end='2000-10-03', freq='1D')) + >>> s + 0 2000-09-26 + 1 2000-09-27 + 2 2000-09-28 + 3 2000-09-29 + 4 2000-09-30 + 5 2000-10-01 + 6 2000-10-02 + 7 2000-10-03 + dtype: datetime64[ns] + >>> s.dt.is_quarter_start + 0 False + 1 False + 2 False + 3 False + 4 False + 5 True + 6 False + 7 False + dtype: bool + """ + day = self.series._column.get_dt_field("day") + first_month = self.series._column.get_dt_field("month").isin( + [1, 4, 7, 10] + ) + + result = ((day == cudf.Scalar(1)) & first_month).fillna(False) + return Series._from_data( + {None: result}, index=self.series._index, name=self.series.name, + ) + + @property + def is_quarter_end(self): + """ + Boolean indicator if the date is the last day of a quarter. + + Returns + ------- + Series + Booleans indicating if dates are the end of a quarter + + Example + ------- + >>> import pandas as pd, cudf + >>> s = cudf.Series( + ... pd.date_range(start='2000-09-26', end='2000-10-03', freq='1D')) + >>> s + 0 2000-09-26 + 1 2000-09-27 + 2 2000-09-28 + 3 2000-09-29 + 4 2000-09-30 + 5 2000-10-01 + 6 2000-10-02 + 7 2000-10-03 + dtype: datetime64[ns] + >>> s.dt.is_quarter_end + 0 False + 1 False + 2 False + 3 False + 4 True + 5 False + 6 False + 7 False + dtype: bool + """ + day = self.series._column.get_dt_field("day") + last_day = libcudf.datetime.last_day_of_month(self.series._column) + last_day = last_day.get_dt_field("day") + last_month = self.series._column.get_dt_field("month").isin( + [3, 6, 9, 12] + ) + + result = ((day == last_day) & last_month).fillna(False) + return Series._from_data( + {None: result}, index=self.series._index, name=self.series.name, + ) + @property def is_year_start(self): """ diff --git a/python/cudf/cudf/tests/test_datetime.py b/python/cudf/cudf/tests/test_datetime.py index a3a2e9f6ade..96d50c66f7e 100644 --- a/python/cudf/cudf/tests/test_datetime.py +++ b/python/cudf/cudf/tests/test_datetime.py @@ -1475,3 +1475,69 @@ def test_is_year_end(data, dtype): got = gs.dt.is_year_end assert_eq(expect, got) + + +@pytest.mark.parametrize( + "data", + [ + [ + "2020-05-01", + "2020-05-31", + "2020-02-29", + None, + "1999-12-01", + "2000-12-21", + None, + "1900-02-28", + "1800-03-14", + "2100-03-10", + "1970-04-1", + "1970-01-01", + "1969-12-11", + "2020-12-31", + ] + ], +) +@pytest.mark.parametrize("dtype", ["datetime64[ns]"]) +def test_is_quarter_start(data, dtype): + # Series + ps = pd.Series(data, dtype=dtype) + gs = cudf.from_pandas(ps) + + expect = ps.dt.is_quarter_start + got = gs.dt.is_quarter_start + + assert_eq(expect, got) + + +@pytest.mark.parametrize( + "data", + [ + [ + "2020-05-01", + "2020-05-31", + "2020-02-29", + None, + "1999-12-01", + "2000-12-21", + None, + "1900-02-28", + "1800-03-14", + "2100-03-10", + "1970-04-1", + "1970-01-01", + "1969-12-11", + "2020-12-31", + ] + ], +) +@pytest.mark.parametrize("dtype", ["datetime64[ns]"]) +def test_is_quarter_end(data, dtype): + # Series + ps = pd.Series(data, dtype=dtype) + gs = cudf.from_pandas(ps) + + expect = ps.dt.is_quarter_end + got = gs.dt.is_quarter_end + + assert_eq(expect, got)