Skip to content

Commit e652e91

Browse files
committed
ENH: GH11128 add weekday_name to DatetimeIndex and .dt
1 parent 81dfb28 commit e652e91

File tree

8 files changed

+66
-3
lines changed

8 files changed

+66
-3
lines changed

doc/source/api.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ These can be accessed like ``Series.dt.<property>``.
469469
Series.dt.days_in_month
470470
Series.dt.tz
471471
Series.dt.freq
472+
Series.dt.weekday_name
472473

473474
**Datetime Methods**
474475

@@ -1477,6 +1478,7 @@ Time/Date Components
14771478
DatetimeIndex.is_year_start
14781479
DatetimeIndex.is_year_end
14791480
DatetimeIndex.inferred_freq
1481+
DatetimeIndex.weekday_name
14801482

14811483
Selecting
14821484
~~~~~~~~~

doc/source/timeseries.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ There are several time/date properties that one can access from ``Timestamp`` or
491491
is_quarter_end,"Logical indicating if last day of quarter (defined by frequency)"
492492
is_year_start,"Logical indicating if first day of year (defined by frequency)"
493493
is_year_end,"Logical indicating if last day of year (defined by frequency)"
494+
weekday_name,"The name of day in a week (ex: Friday)"
494495

495496
Furthermore, if you have a ``Series`` with datetimelike values, then you can access these properties via the ``.dt`` accessor, see the :ref:`docs <basics.dt_accessors>`
496497

doc/source/whatsnew/v0.18.0.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ Other enhancements
152152
- ``Series`` gained an ``is_unique`` attribute (:issue:`11946`)
153153
- ``DataFrame.quantile`` and ``Series.quantile`` now accept ``interpolation`` keyword (:issue:`10174`).
154154
- ``DataFrame.select_dtypes`` now allows the ``np.float16`` typecode (:issue:`11990`)
155+
- Added ``weekday_name`` as a component to ``DatetimeIndex`` and ``.dt`` accessor. (:issue:`11128`)
155156

156157
.. _whatsnew_0180.enhancements.rounding:
157158

pandas/tests/test_series.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ def test_dt_namespace_accessor(self):
8888
ok_for_dt = ok_for_base + ['date', 'time', 'microsecond', 'nanosecond',
8989
'is_month_start', 'is_month_end',
9090
'is_quarter_start', 'is_quarter_end',
91-
'is_year_start', 'is_year_end', 'tz']
91+
'is_year_start', 'is_year_end', 'tz',
92+
'weekday_name']
9293
ok_for_dt_methods = ['to_period', 'to_pydatetime', 'tz_localize',
9394
'tz_convert', 'normalize', 'strftime', 'round',
9495
'floor', 'ceil']

pandas/tseries/index.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ def f(self):
6060

6161
result = tslib.get_start_end_field(
6262
values, field, self.freqstr, month_kw)
63+
elif field in ['weekday_name']:
64+
result = tslib.get_date_name_field(values, field)
65+
return self._maybe_mask_results(result)
6366
else:
6467
result = tslib.get_date_field(values, field)
6568

@@ -207,7 +210,7 @@ def _join_i8_wrapper(joinf, **kwargs):
207210
'daysinmonth', 'date', 'time', 'microsecond',
208211
'nanosecond', 'is_month_start', 'is_month_end',
209212
'is_quarter_start', 'is_quarter_end', 'is_year_start',
210-
'is_year_end', 'tz', 'freq']
213+
'is_year_end', 'tz', 'freq', 'weekday_name']
211214
_is_numeric_dtype = False
212215
_infer_as_myclass = True
213216

@@ -1564,6 +1567,10 @@ def _set_freq(self, value):
15641567
'is_year_end',
15651568
'is_year_end',
15661569
"Logical indicating if last day of year (defined by frequency)")
1570+
weekday_name = _field_accessor(
1571+
'weekday_name',
1572+
'weekday_name',
1573+
"The name of day in a week (ex: Friday)\n\n.. versionadded:: 0.18.0")
15671574

15681575
@property
15691576
def time(self):

pandas/tseries/tests/test_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def test_ops_properties(self):
3131
'is_month_start', 'is_month_end',
3232
'is_quarter_start',
3333
'is_quarter_end', 'is_year_start',
34-
'is_year_end'],
34+
'is_year_end', 'weekday_name'],
3535
lambda x: isinstance(x, DatetimeIndex))
3636

3737
def test_ops_properties_basic(self):

pandas/tseries/tests/test_timeseries.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3369,6 +3369,15 @@ def test_datetimeindex_accessors(self):
33693369
self.assertEqual(dti.is_year_end[0], False)
33703370
self.assertEqual(dti.is_year_end[364], True)
33713371

3372+
# GH 11128
3373+
self.assertEqual(dti.weekday_name[4], u'Monday')
3374+
self.assertEqual(dti.weekday_name[5], u'Tuesday')
3375+
self.assertEqual(dti.weekday_name[6], u'Wednesday')
3376+
self.assertEqual(dti.weekday_name[7], u'Thursday')
3377+
self.assertEqual(dti.weekday_name[8], u'Friday')
3378+
self.assertEqual(dti.weekday_name[9], u'Saturday')
3379+
self.assertEqual(dti.weekday_name[10], u'Sunday')
3380+
33723381
self.assertEqual(len(dti.year), 365)
33733382
self.assertEqual(len(dti.month), 365)
33743383
self.assertEqual(len(dti.day), 365)
@@ -3386,6 +3395,7 @@ def test_datetimeindex_accessors(self):
33863395
self.assertEqual(len(dti.is_quarter_end), 365)
33873396
self.assertEqual(len(dti.is_year_start), 365)
33883397
self.assertEqual(len(dti.is_year_end), 365)
3398+
self.assertEqual(len(dti.weekday_name), 365)
33893399

33903400
dti = DatetimeIndex(freq='BQ-FEB', start=datetime(1998, 1, 1),
33913401
periods=4)

pandas/tslib.pyx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,10 @@ class Timestamp(_Timestamp):
494494
def is_year_end(self):
495495
return self._get_start_end_field('is_year_end')
496496

497+
@property
498+
def weekday_name(self):
499+
return self._get_date_name_field('weekday_name')
500+
497501
def tz_localize(self, tz, ambiguous='raise'):
498502
"""
499503
Convert naive Timestamp to local time zone, or remove
@@ -1098,6 +1102,10 @@ cdef class _Timestamp(datetime):
10981102
out = get_start_end_field(np.array([self.value], dtype=np.int64), field, freqstr, month_kw)
10991103
return out[0]
11001104

1105+
cpdef _get_date_name_field(self, field):
1106+
out = get_date_name_field(np.array([self.value], dtype=np.int64), field)
1107+
return out[0]
1108+
11011109
property asm8:
11021110
def __get__(self):
11031111
return np.datetime64(self.value, 'ns')
@@ -4363,6 +4371,39 @@ def get_start_end_field(ndarray[int64_t] dtindex, object field, object freqstr=N
43634371
raise ValueError("Field %s not supported" % field)
43644372

43654373

4374+
@cython.wraparound(False)
4375+
@cython.boundscheck(False)
4376+
def get_date_name_field(ndarray[int64_t] dtindex, object field):
4377+
'''
4378+
Given a int64-based datetime index, return array of strings of date
4379+
name based on requested field (e.g. weekday_name)
4380+
'''
4381+
cdef:
4382+
_TSObject ts
4383+
Py_ssize_t i, count = 0
4384+
ndarray[object] out
4385+
pandas_datetimestruct dts
4386+
int dow
4387+
4388+
_dayname = np.array(
4389+
['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
4390+
dtype=np.str )
4391+
4392+
count = len(dtindex)
4393+
out = np.empty(count, dtype=object)
4394+
4395+
if field == 'weekday_name':
4396+
for i in range(count):
4397+
if dtindex[i] == NPY_NAT: out[i] = -1; continue
4398+
4399+
pandas_datetime_to_datetimestruct(dtindex[i], PANDAS_FR_ns, &dts)
4400+
dow = dayofweek(dts.year, dts.month, dts.day)
4401+
out[i] = _dayname[dow]
4402+
return out
4403+
4404+
raise ValueError("Field %s not supported" % field)
4405+
4406+
43664407
cdef inline int m8_weekday(int64_t val):
43674408
ts = convert_to_tsobject(val, None, None)
43684409
return ts_dayofweek(ts)

0 commit comments

Comments
 (0)