Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add is_leap_year to DateTimeProperties and DatetimeIndex #8736

Merged
merged 2 commits into from
Jul 14, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions python/cudf/cudf/_lib/cpp/datetime.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ cdef extern from "cudf/datetime.hpp" namespace "cudf::datetime" nogil:
const column_view& months
) except +
cdef unique_ptr[column] day_of_year(const column_view& column) except +
cdef unique_ptr[column] is_leap_year(const column_view& column) except +
10 changes: 10 additions & 0 deletions python/cudf/cudf/_lib/datetime.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,13 @@ def extract_datetime_component(Column col, object field):
result = result.binary_operator("sub", result.dtype.type(1))

return result


def is_leap_year(Column col):
cdef unique_ptr[column] c_result
cdef column_view col_view = col.view()

with nogil:
c_result = move(libcudf_datetime.is_leap_year(col_view))

return Column.from_unique_ptr(move(c_result))
19 changes: 19 additions & 0 deletions python/cudf/cudf/core/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from pandas._config import get_option

import cudf
from cudf._lib.datetime import is_leap_year
from cudf._lib.filling import sequence
from cudf._lib.search import search_sorted
from cudf._lib.table import Table
Expand Down Expand Up @@ -2343,6 +2344,24 @@ def day_of_year(self):
"""
return self._get_dt_field("day_of_year")

@property
def is_leap_year(self):
"""
Boolean indicator if the date belongs to a leap year.

A leap year is a year, which has 366 days (instead of 365) including
29th of February as an intercalary day. Leap years are years which are
multiples of four with the exception of years divisible by 100 but not
by 400.

Returns
-------
ndarray
Booleans indicating if dates belong to a leap year.
"""
res = is_leap_year(self._values).fillna(False)
return cupy.array(res.to_gpu_array())
isVoid marked this conversation as resolved.
Show resolved Hide resolved

def to_pandas(self):
nanos = self._values.astype("datetime64[ns]")
return pd.DatetimeIndex(nanos.to_pandas(), name=self.name)
Expand Down
22 changes: 22 additions & 0 deletions python/cudf/cudf/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -6366,6 +6366,28 @@ def day_of_year(self):
"""
return self._get_dt_field("day_of_year")

@property
def is_leap_year(self):
"""
Boolean indicator if the date belongs to a leap year.

A leap year is a year, which has 366 days (instead of 365) including
29th of February as an intercalary day. Leap years are years which are
multiples of four with the exception of years divisible by 100 but not
by 400.

Returns
-------
Series
Booleans indicating if dates belong to a leap year.
"""
res = libcudf.datetime.is_leap_year(self.series._column).fillna(False)
return Series._from_data(
ColumnAccessor({None: res}),
index=self.series._index,
name=self.series.name,
)

def _get_dt_field(self, field):
out_column = self.series._column.get_dt_field(field)
return Series(
Expand Down
33 changes: 33 additions & 0 deletions python/cudf/cudf/tests/test_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -1264,3 +1264,36 @@ def test_datetime_to_datetime_error():
"'coerce', 'warn'], found: %d-%B-%Y %H:%M"
),
)


def test_is_leap_year():
data = [
"2020-05-31 08:00:00",
None,
"1999-12-31 18:40:00",
"2000-12-31 04:00:00",
None,
"1900-02-28 07:00:00",
"1800-03-14 07:30:00",
"2100-03-14 07:30:00",
"1970-01-01 00:00:00",
"1969-12-31 12:59:00",
]

# Series
ps = pd.Series(data, dtype="datetime64[s]")
gs = cudf.from_pandas(ps)

expect = ps.dt.is_leap_year
got = gs.dt.is_leap_year

assert_eq(expect, got)

# DatetimeIndex
pIndex = pd.DatetimeIndex(data)
gIndex = cudf.from_pandas(pIndex)

expect2 = pIndex.is_leap_year
got2 = gIndex.is_leap_year

assert_eq(expect2, got2)