Skip to content

Commit afddc4f

Browse files
Bastiaanjreback
Bastiaan
authored andcommitted
ENH: GH11128 add weekday_name to DatetimeIndex and .dt
closes #11128 replaces #11813 - [x] tests added / passed - [x] passes ``git diff upstream/master | flake8 --diff`` - [x] whatsnew entry Completed merge of Bahrunnur's PR 'weekday-name' Moved 'enhancements' to v0.18.1.txt Added tests to pandas/tests/series/test_datetime_values.py Added weekday_name property producing 'NaT' to NaTType class Author: Bastiaan <[email protected]> Author: Bahrunnur <[email protected]> Closes #12803 from BastiaanBergman/ENH11128 and squashes the following commits: c579d71 [Bastiaan] Tiny fixes as requested by jreback, GH12803. 6f246d5 [Bastiaan] Small fixes as requested by jreback, GH12803. 7b14d5c [Bahrunnur] ENH: GH11128 add weekday_name to DatetimeIndex and .dt
1 parent cc67b72 commit afddc4f

File tree

8 files changed

+77
-8
lines changed

8 files changed

+77
-8
lines changed

doc/source/api.rst

+2
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ These can be accessed like ``Series.dt.<property>``.
457457
Series.dt.weekofyear
458458
Series.dt.dayofweek
459459
Series.dt.weekday
460+
Series.dt.weekday_name
460461
Series.dt.dayofyear
461462
Series.dt.quarter
462463
Series.dt.is_month_start
@@ -1476,6 +1477,7 @@ Time/Date Components
14761477
DatetimeIndex.week
14771478
DatetimeIndex.dayofweek
14781479
DatetimeIndex.weekday
1480+
DatetimeIndex.weekday_name
14791481
DatetimeIndex.quarter
14801482
DatetimeIndex.tz
14811483
DatetimeIndex.freq

doc/source/timeseries.rst

+1
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ There are several time/date properties that one can access from ``Timestamp`` or
523523
is_quarter_end,"Logical indicating if last day of quarter (defined by frequency)"
524524
is_year_start,"Logical indicating if first day of year (defined by frequency)"
525525
is_year_end,"Logical indicating if last day of year (defined by frequency)"
526+
weekday_name,"The name of day in a week (ex: Friday)"
526527

527528
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>`
528529

doc/source/whatsnew/v0.18.1.txt

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ Other Enhancements
8181
- ``pd.read_msgpack()`` now supports serializing and de-serializing categoricals with msgpack (:issue:`12573`)
8282
- ``interpolate()`` now supports ``method='akima'`` (:issue:`7588`).
8383
- ``Index.take`` now handles ``allow_fill`` and ``fill_value`` consistently (:issue:`12631`)
84+
- Added ``weekday_name`` as a component to ``DatetimeIndex`` and ``.dt`` accessor. (:issue:`11128`)
8485

8586
.. ipython:: python
8687

pandas/tests/series/test_datetime_values.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class TestSeriesDatetimeValues(TestData, tm.TestCase):
2525

2626
def test_dt_namespace_accessor(self):
2727

28-
# GH 7207
28+
# GH 7207, 11128
2929
# test .dt namespace accessor
3030

3131
ok_for_base = ['year', 'month', 'day', 'hour', 'minute', 'second',
@@ -37,10 +37,11 @@ def test_dt_namespace_accessor(self):
3737
ok_for_dt = ok_for_base + ['date', 'time', 'microsecond', 'nanosecond',
3838
'is_month_start', 'is_month_end',
3939
'is_quarter_start', 'is_quarter_end',
40-
'is_year_start', 'is_year_end', 'tz']
40+
'is_year_start', 'is_year_end', 'tz',
41+
'weekday_name']
4142
ok_for_dt_methods = ['to_period', 'to_pydatetime', 'tz_localize',
4243
'tz_convert', 'normalize', 'strftime', 'round',
43-
'floor', 'ceil']
44+
'floor', 'ceil', 'weekday_name']
4445
ok_for_td = ['days', 'seconds', 'microseconds', 'nanoseconds']
4546
ok_for_td_methods = ['components', 'to_pytimedelta', 'total_seconds',
4647
'round', 'floor', 'ceil']

pandas/tseries/index.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ def f(self):
6262

6363
result = tslib.get_start_end_field(
6464
values, field, self.freqstr, month_kw)
65+
elif field in ['weekday_name']:
66+
result = tslib.get_date_name_field(values, field)
67+
return self._maybe_mask_results(result)
6568
else:
6669
result = tslib.get_date_field(values, field)
6770

@@ -209,7 +212,7 @@ def _join_i8_wrapper(joinf, **kwargs):
209212
'daysinmonth', 'date', 'time', 'microsecond',
210213
'nanosecond', 'is_month_start', 'is_month_end',
211214
'is_quarter_start', 'is_quarter_end', 'is_year_start',
212-
'is_year_end', 'tz', 'freq']
215+
'is_year_end', 'tz', 'freq', 'weekday_name']
213216
_is_numeric_dtype = False
214217
_infer_as_myclass = True
215218

@@ -1565,6 +1568,12 @@ def _set_freq(self, value):
15651568
'dow',
15661569
"The day of the week with Monday=0, Sunday=6")
15671570
weekday = dayofweek
1571+
1572+
weekday_name = _field_accessor(
1573+
'weekday_name',
1574+
'weekday_name',
1575+
"The name of day in a week (ex: Friday)\n\n.. versionadded:: 0.18.1")
1576+
15681577
dayofyear = _field_accessor(
15691578
'dayofyear',
15701579
'doy',

pandas/tseries/tests/test_base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def test_ops_properties(self):
3232
'is_month_start', 'is_month_end',
3333
'is_quarter_start',
3434
'is_quarter_end', 'is_year_start',
35-
'is_year_end'],
35+
'is_year_end', 'weekday_name'],
3636
lambda x: isinstance(x, DatetimeIndex))
3737

3838
def test_ops_properties_basic(self):

pandas/tseries/tests/test_timeseries.py

+20-2
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ def test_nat_vector_field_access(self):
959959
def test_nat_scalar_field_access(self):
960960
fields = ['year', 'quarter', 'month', 'day', 'hour', 'minute',
961961
'second', 'microsecond', 'nanosecond', 'week', 'dayofyear',
962-
'days_in_month', 'daysinmonth', 'dayofweek']
962+
'days_in_month', 'daysinmonth', 'dayofweek', 'weekday_name']
963963
for field in fields:
964964
result = getattr(NaT, field)
965965
self.assertTrue(np.isnan(result))
@@ -1852,7 +1852,7 @@ def test_timestamp_fields(self):
18521852
fields = ['dayofweek', 'dayofyear', 'week', 'weekofyear', 'quarter',
18531853
'days_in_month', 'is_month_start', 'is_month_end',
18541854
'is_quarter_start', 'is_quarter_end', 'is_year_start',
1855-
'is_year_end']
1855+
'is_year_end', 'weekday_name']
18561856
for f in fields:
18571857
expected = getattr(idx, f)[-1]
18581858
result = getattr(Timestamp(idx[-1]), f)
@@ -3544,6 +3544,23 @@ def test_datetimeindex_accessors(self):
35443544
self.assertEqual(dti.is_year_end[0], False)
35453545
self.assertEqual(dti.is_year_end[364], True)
35463546

3547+
# GH 11128
3548+
self.assertEqual(dti.weekday_name[4], u'Monday')
3549+
self.assertEqual(dti.weekday_name[5], u'Tuesday')
3550+
self.assertEqual(dti.weekday_name[6], u'Wednesday')
3551+
self.assertEqual(dti.weekday_name[7], u'Thursday')
3552+
self.assertEqual(dti.weekday_name[8], u'Friday')
3553+
self.assertEqual(dti.weekday_name[9], u'Saturday')
3554+
self.assertEqual(dti.weekday_name[10], u'Sunday')
3555+
3556+
self.assertEqual(Timestamp('2016-04-04').weekday_name, u'Monday')
3557+
self.assertEqual(Timestamp('2016-04-05').weekday_name, u'Tuesday')
3558+
self.assertEqual(Timestamp('2016-04-06').weekday_name, u'Wednesday')
3559+
self.assertEqual(Timestamp('2016-04-07').weekday_name, u'Thursday')
3560+
self.assertEqual(Timestamp('2016-04-08').weekday_name, u'Friday')
3561+
self.assertEqual(Timestamp('2016-04-09').weekday_name, u'Saturday')
3562+
self.assertEqual(Timestamp('2016-04-10').weekday_name, u'Sunday')
3563+
35473564
self.assertEqual(len(dti.year), 365)
35483565
self.assertEqual(len(dti.month), 365)
35493566
self.assertEqual(len(dti.day), 365)
@@ -3561,6 +3578,7 @@ def test_datetimeindex_accessors(self):
35613578
self.assertEqual(len(dti.is_quarter_end), 365)
35623579
self.assertEqual(len(dti.is_year_start), 365)
35633580
self.assertEqual(len(dti.is_year_end), 365)
3581+
self.assertEqual(len(dti.weekday_name), 365)
35643582

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

pandas/tslib.pyx

+38-1
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,11 @@ class Timestamp(_Timestamp):
398398
def dayofweek(self):
399399
return self.weekday()
400400

401+
@property
402+
def weekday_name(self):
403+
out = get_date_name_field(np.array([self.value], dtype=np.int64), 'weekday_name')
404+
return out[0]
405+
401406
@property
402407
def dayofyear(self):
403408
return self._get_field('doy')
@@ -667,7 +672,7 @@ class NaTType(_NaT):
667672

668673
fields = ['year', 'quarter', 'month', 'day', 'hour',
669674
'minute', 'second', 'millisecond', 'microsecond', 'nanosecond',
670-
'week', 'dayofyear', 'days_in_month', 'daysinmonth', 'dayofweek']
675+
'week', 'dayofyear', 'days_in_month', 'daysinmonth', 'dayofweek', 'weekday_name']
671676
for field in fields:
672677
prop = property(fget=lambda self: np.nan)
673678
setattr(NaTType, field, prop)
@@ -4390,6 +4395,38 @@ def get_start_end_field(ndarray[int64_t] dtindex, object field, object freqstr=N
43904395

43914396
raise ValueError("Field %s not supported" % field)
43924397

4398+
@cython.wraparound(False)
4399+
@cython.boundscheck(False)
4400+
def get_date_name_field(ndarray[int64_t] dtindex, object field):
4401+
'''
4402+
Given a int64-based datetime index, return array of strings of date
4403+
name based on requested field (e.g. weekday_name)
4404+
'''
4405+
cdef:
4406+
_TSObject ts
4407+
Py_ssize_t i, count = 0
4408+
ndarray[object] out
4409+
pandas_datetimestruct dts
4410+
int dow
4411+
4412+
_dayname = np.array(
4413+
['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
4414+
dtype=np.object_ )
4415+
4416+
count = len(dtindex)
4417+
out = np.empty(count, dtype=object)
4418+
4419+
if field == 'weekday_name':
4420+
for i in range(count):
4421+
if dtindex[i] == NPY_NAT: out[i] = np.nan; continue
4422+
4423+
pandas_datetime_to_datetimestruct(dtindex[i], PANDAS_FR_ns, &dts)
4424+
dow = dayofweek(dts.year, dts.month, dts.day)
4425+
out[i] = _dayname[dow]
4426+
return out
4427+
4428+
raise ValueError("Field %s not supported" % field)
4429+
43934430

43944431
cdef inline int m8_weekday(int64_t val):
43954432
ts = convert_to_tsobject(val, None, None)

0 commit comments

Comments
 (0)