Skip to content

Commit

Permalink
ENH: support .strftime for datetimelikes (closes #10086)
Browse files Browse the repository at this point in the history
  • Loading branch information
mortada committed May 13, 2015
1 parent eafd22d commit e27b9cb
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 9 deletions.
37 changes: 29 additions & 8 deletions pandas/tests/test_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ def test_dt_namespace_accessor(self):

ok_for_base = ['year','month','day','hour','minute','second','weekofyear','week','dayofweek','weekday','dayofyear','quarter','freq','days_in_month','daysinmonth']
ok_for_period = ok_for_base + ['qyear']
ok_for_period_methods = ['strftime']
ok_for_dt = ok_for_base + ['date','time','microsecond','nanosecond', 'is_month_start', 'is_month_end', 'is_quarter_start',
'is_quarter_end', 'is_year_start', 'is_year_end', 'tz']
ok_for_dt_methods = ['to_period','to_pydatetime','tz_localize','tz_convert', 'normalize']
ok_for_dt_methods = ['to_period','to_pydatetime','tz_localize','tz_convert', 'normalize', 'strftime']
ok_for_td = ['days','seconds','microseconds','nanoseconds']
ok_for_td_methods = ['components','to_pytimedelta']

Expand All @@ -109,13 +110,12 @@ def compare(s, name):
Series(date_range('20130101',periods=5,freq='s')),
Series(date_range('20130101 00:00:00',periods=5,freq='ms'))]:
for prop in ok_for_dt:

# we test freq below
if prop != 'freq':
compare(s, prop)

for prop in ok_for_dt_methods:
getattr(s.dt,prop)
getattr(s.dt, prop)

result = s.dt.to_pydatetime()
self.assertIsInstance(result,np.ndarray)
Expand All @@ -140,13 +140,12 @@ def compare(s, name):
Series(timedelta_range('1 day 01:23:45',periods=5,freq='s')),
Series(timedelta_range('2 days 01:23:45.012345',periods=5,freq='ms'))]:
for prop in ok_for_td:

# we test freq below
if prop != 'freq':
compare(s, prop)

for prop in ok_for_td_methods:
getattr(s.dt,prop)
getattr(s.dt, prop)

result = s.dt.components
self.assertIsInstance(result,DataFrame)
Expand All @@ -169,13 +168,14 @@ def compare(s, name):

# periodindex
for s in [Series(period_range('20130101',periods=5,freq='D'))]:

for prop in ok_for_period:

# we test freq below
if prop != 'freq':
compare(s, prop)

for prop in ok_for_period_methods:
getattr(s.dt, prop)

freq_result = s.dt.freq
self.assertEqual(freq_result, PeriodIndex(s.values).freq)

Expand All @@ -190,7 +190,7 @@ def get_dir(s):

s = Series(period_range('20130101',periods=5,freq='D').asobject)
results = get_dir(s)
tm.assert_almost_equal(results,list(sorted(set(ok_for_period))))
tm.assert_almost_equal(results, list(sorted(set(ok_for_period + ok_for_period_methods))))

# no setting allowed
s = Series(date_range('20130101',periods=5,freq='D'))
Expand All @@ -203,6 +203,27 @@ def f():
s.dt.hour[0] = 5
self.assertRaises(com.SettingWithCopyError, f)

def test_strftime(self):
# GH 10086
s = Series(date_range('20130101', periods=5))
result = s.dt.strftime('%Y/%m/%d')
expected = Series(['2013/01/01', '2013/01/02', '2013/01/03', '2013/01/04', '2013/01/05'])
tm.assert_series_equal(result, expected)

s.iloc[0] = pd.NaT
result = s.dt.strftime('%Y/%m/%d')
expected = Series(['NaT', '2013/01/02', '2013/01/03', '2013/01/04', '2013/01/05'])
tm.assert_series_equal(result, expected)

datetime_index = date_range('20150301', periods=5)
result = datetime_index.strftime("%Y/%m/%d")
expected = ['2015/03/01', '2015/03/02', '2015/03/03', '2015/03/04', '2015/03/05']
self.assertEqual(result, expected)

period_index = period_range('20150301', periods=5)
expected = ['2015/03/01', '2015/03/02', '2015/03/03', '2015/03/04', '2015/03/05']
self.assertEqual(result, expected)

def test_valid_dt_with_missing_values(self):

from datetime import date, time
Expand Down
5 changes: 4 additions & 1 deletion pandas/tseries/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def to_pydatetime(self):
accessors=DatetimeIndex._datetimelike_ops,
typ='property')
DatetimeProperties._add_delegate_accessors(delegate=DatetimeIndex,
accessors=["to_period","tz_localize","tz_convert","normalize"],
accessors=["to_period","tz_localize","tz_convert","normalize","strftime"],
typ='method')

class TimedeltaProperties(Properties):
Expand Down Expand Up @@ -181,6 +181,9 @@ class PeriodProperties(Properties):
PeriodProperties._add_delegate_accessors(delegate=PeriodIndex,
accessors=PeriodIndex._datetimelike_ops,
typ='property')
PeriodProperties._add_delegate_accessors(delegate=PeriodIndex,
accessors=["strftime"],
typ='method')


class CombinedDatetimelikeProperties(DatetimeProperties, TimedeltaProperties):
Expand Down
15 changes: 15 additions & 0 deletions pandas/tseries/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,21 @@ def astype(self, dtype):
else: # pragma: no cover
raise ValueError('Cannot cast DatetimeIndex to dtype %s' % dtype)

def strftime(self, date_format):
"""
Return a list of formmatted strings specified by date_format
Parameters
----------
date_format : str
date format string (e.g. "%Y-%m-%d")
Returns
-------
a list formatted strings
"""
return self.format(date_format=date_format)

def _get_time_micros(self):
utc = _utc()
values = self.asi8
Expand Down
15 changes: 15 additions & 0 deletions pandas/tseries/period.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,21 @@ def astype(self, dtype):
return Index(self.values, dtype)
raise ValueError('Cannot cast PeriodIndex to dtype %s' % dtype)

def strftime(self, date_format):
"""
Return a list of formmatted strings specified by date_format
Parameters
----------
date_format : str
date format string (e.g. "%Y-%m-%d")
Returns
-------
a list formatted strings
"""
return self.format(date_format=date_format)

def searchsorted(self, key, side='left'):
if isinstance(key, Period):
if key.freq != self.freq:
Expand Down

0 comments on commit e27b9cb

Please sign in to comment.