From 607910b2a26ab7d7e94dd8ce02198631c8649513 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke Date: Sun, 4 Mar 2018 12:15:37 -0800 Subject: [PATCH] Add month names (#18164) --- doc/source/api.rst | 9 ++- doc/source/whatsnew/v0.23.0.txt | 4 +- pandas/_libs/tslibs/ccalendar.pyx | 29 ++++++++ pandas/_libs/tslibs/fields.pyx | 35 +++++++--- pandas/_libs/tslibs/nattype.pyx | 49 +++++++++---- pandas/_libs/tslibs/timestamps.pyx | 58 ++++++++++++++-- pandas/core/indexes/datetimes.py | 59 +++++++++++++++- pandas/tests/indexes/datetimes/test_misc.py | 69 ++++++++++++++----- .../tests/scalar/timestamp/test_timestamp.py | 35 ++++++++-- pandas/tests/series/test_datetime_values.py | 44 +++++++++++- 10 files changed, 330 insertions(+), 61 deletions(-) diff --git a/doc/source/api.rst b/doc/source/api.rst index a5e26bc948a70..dba7f6526f22a 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -551,7 +551,6 @@ These can be accessed like ``Series.dt.``. Series.dt.weekofyear Series.dt.dayofweek Series.dt.weekday - Series.dt.weekday_name Series.dt.dayofyear Series.dt.quarter Series.dt.is_month_start @@ -581,6 +580,8 @@ These can be accessed like ``Series.dt.``. Series.dt.round Series.dt.floor Series.dt.ceil + Series.dt.month_name + Series.dt.day_name **Timedelta Properties** @@ -1723,7 +1724,6 @@ Time/Date Components DatetimeIndex.week DatetimeIndex.dayofweek DatetimeIndex.weekday - DatetimeIndex.weekday_name DatetimeIndex.quarter DatetimeIndex.tz DatetimeIndex.freq @@ -1759,6 +1759,8 @@ Time-specific operations DatetimeIndex.round DatetimeIndex.floor DatetimeIndex.ceil + DatetimeIndex.month_name + DatetimeIndex.day_name Conversion ~~~~~~~~~~ @@ -1940,7 +1942,6 @@ Properties Timestamp.tzinfo Timestamp.value Timestamp.week - Timestamp.weekday_name Timestamp.weekofyear Timestamp.year @@ -1954,6 +1955,7 @@ Methods Timestamp.combine Timestamp.ctime Timestamp.date + Timestamp.day_name Timestamp.dst Timestamp.floor Timestamp.freq @@ -1963,6 +1965,7 @@ Methods Timestamp.isocalendar Timestamp.isoformat Timestamp.isoweekday + Timestamp.month_name Timestamp.normalize Timestamp.now Timestamp.replace diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index fd6be268b6db7..a976fca66a57a 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -338,7 +338,8 @@ Other Enhancements - For subclassed ``DataFrames``, :func:`DataFrame.apply` will now preserve the ``Series`` subclass (if defined) when passing the data to the applied function (:issue:`19822`) - :func:`DataFrame.from_dict` now accepts a ``columns`` argument that can be used to specify the column names when ``orient='index'`` is used (:issue:`18529`) - Added option ``display.html.use_mathjax`` so `MathJax `_ can be disabled when rendering tables in ``Jupyter`` notebooks (:issue:`19856`, :issue:`19824`) - +- :meth:`Timestamp.month_name`, :meth:`DatetimeIndex.month_name`, and :meth:`Series.dt.month_name` are now available (:issue:`12805`) +- :meth:`Timestamp.day_name` and :meth:`DatetimeIndex.day_name` are now available to return day names with a specified locale (:issue:`12806`) .. _whatsnew_0230.api_breaking: @@ -728,6 +729,7 @@ Deprecations - The ``broadcast`` parameter of ``.apply()`` is deprecated in favor of ``result_type='broadcast'`` (:issue:`18577`) - The ``reduce`` parameter of ``.apply()`` is deprecated in favor of ``result_type='reduce'`` (:issue:`18577`) - The ``order`` parameter of :func:`factorize` is deprecated and will be removed in a future release (:issue:`19727`) +- :attr:`Timestamp.weekday_name`, :attr:`DatetimeIndex.weekday_name`, and :attr:`Series.dt.weekday_name` are deprecated in favor of :meth:`Timestamp.day_name`, :meth:`DatetimeIndex.day_name`, and :meth:`Series.dt.day_name` (:issue:`12806`) .. _whatsnew_0230.prior_deprecations: diff --git a/pandas/_libs/tslibs/ccalendar.pyx b/pandas/_libs/tslibs/ccalendar.pyx index 9bd315b43ea9e..0901d474d044c 100644 --- a/pandas/_libs/tslibs/ccalendar.pyx +++ b/pandas/_libs/tslibs/ccalendar.pyx @@ -12,6 +12,8 @@ cimport numpy as cnp from numpy cimport int64_t, int32_t cnp.import_array() +from locale import LC_TIME +from strptime import LocaleTime # ---------------------------------------------------------------------- # Constants @@ -35,11 +37,18 @@ cdef int32_t* _month_offset = [ # Canonical location for other modules to find name constants MONTHS = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'] +# The first blank line is consistent with calendar.month_name in the calendar +# standard library +MONTHS_FULL = ['', 'January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', + 'December'] MONTH_NUMBERS = {name: num for num, name in enumerate(MONTHS)} MONTH_ALIASES = {(num + 1): name for num, name in enumerate(MONTHS)} MONTH_TO_CAL_NUM = {name: num + 1 for num, name in enumerate(MONTHS)} DAYS = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN'] +DAYS_FULL = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', + 'Saturday', 'Sunday'] int_to_weekday = {num: name for num, name in enumerate(DAYS)} weekday_to_int = {int_to_weekday[key]: key for key in int_to_weekday} @@ -199,3 +208,23 @@ cpdef int32_t get_day_of_year(int year, int month, int day) nogil: day_of_year = mo_off + day return day_of_year + + +cpdef get_locale_names(object name_type, object locale=None): + """Returns an array of localized day or month names + + Parameters + ---------- + name_type : string, attribute of LocaleTime() in which to return localized + names + locale : string + + Returns + ------- + list of locale names + + """ + from pandas.util.testing import set_locale + + with set_locale(locale, LC_TIME): + return getattr(LocaleTime(), name_type) diff --git a/pandas/_libs/tslibs/fields.pyx b/pandas/_libs/tslibs/fields.pyx index 7a4b9775bd56e..ccf67e765e079 100644 --- a/pandas/_libs/tslibs/fields.pyx +++ b/pandas/_libs/tslibs/fields.pyx @@ -13,7 +13,7 @@ cimport numpy as cnp from numpy cimport ndarray, int64_t, int32_t, int8_t cnp.import_array() - +from ccalendar import get_locale_names, MONTHS_FULL, DAYS_FULL from ccalendar cimport (get_days_in_month, is_leapyear, dayofweek, get_week_of_year, get_day_of_year) from np_datetime cimport (pandas_datetimestruct, pandas_timedeltastruct, @@ -85,26 +85,27 @@ def build_field_sarray(ndarray[int64_t] dtindex): @cython.wraparound(False) @cython.boundscheck(False) -def get_date_name_field(ndarray[int64_t] dtindex, object field): +def get_date_name_field(ndarray[int64_t] dtindex, object field, + object locale=None): """ Given a int64-based datetime index, return array of strings of date name based on requested field (e.g. weekday_name) """ cdef: Py_ssize_t i, count = 0 - ndarray[object] out + ndarray[object] out, names pandas_datetimestruct dts int dow - _dayname = np.array( - ['Monday', 'Tuesday', 'Wednesday', 'Thursday', - 'Friday', 'Saturday', 'Sunday'], - dtype=np.object_) - count = len(dtindex) out = np.empty(count, dtype=object) - if field == 'weekday_name': + if field == 'day_name' or field == 'weekday_name': + if locale is None: + names = np.array(DAYS_FULL, dtype=np.object_) + else: + names = np.array(get_locale_names('f_weekday', locale), + dtype=np.object_) for i in range(count): if dtindex[i] == NPY_NAT: out[i] = np.nan @@ -112,7 +113,21 @@ def get_date_name_field(ndarray[int64_t] dtindex, object field): dt64_to_dtstruct(dtindex[i], &dts) dow = dayofweek(dts.year, dts.month, dts.day) - out[i] = _dayname[dow] + out[i] = names[dow].capitalize() + return out + elif field == 'month_name': + if locale is None: + names = np.array(MONTHS_FULL, dtype=np.object_) + else: + names = np.array(get_locale_names('f_month', locale), + dtype=np.object_) + for i in range(count): + if dtindex[i] == NPY_NAT: + out[i] = np.nan + continue + + dt64_to_dtstruct(dtindex[i], &dts) + out[i] = names[dts.month].capitalize() return out raise ValueError("Field %s not supported" % field) diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx index 9f4ef4e515058..be76b55fa169b 100644 --- a/pandas/_libs/tslibs/nattype.pyx +++ b/pandas/_libs/tslibs/nattype.pyx @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- # cython: profile=False -import warnings from cpython cimport ( PyFloat_Check, PyComplex_Check, @@ -39,24 +38,19 @@ _nat_scalar_rules[Py_GE] = False # ---------------------------------------------------------------------- -def _make_nan_func(func_name, cls): +def _make_nan_func(func_name, doc): def f(*args, **kwargs): return np.nan f.__name__ = func_name - f.__doc__ = getattr(cls, func_name).__doc__ + f.__doc__ = doc return f -def _make_nat_func(func_name, cls): +def _make_nat_func(func_name, doc): def f(*args, **kwargs): return NaT - f.__name__ = func_name - if isinstance(cls, str): - # passed the literal docstring directly - f.__doc__ = cls - else: - f.__doc__ = getattr(cls, func_name).__doc__ + f.__doc__ = doc return f @@ -318,11 +312,40 @@ class NaTType(_NaT): # These are the ones that can get their docstrings from datetime. # nan methods - weekday = _make_nan_func('weekday', datetime) - isoweekday = _make_nan_func('isoweekday', datetime) + weekday = _make_nan_func('weekday', datetime.weekday.__doc__) + isoweekday = _make_nan_func('isoweekday', datetime.isoweekday.__doc__) + month_name = _make_nan_func('month_name', # noqa:E128 + """ + Return the month name of the Timestamp with specified locale. + + Parameters + ---------- + locale : string, default None (English locale) + locale determining the language in which to return the month name + + Returns + ------- + month_name : string + + .. versionadded:: 0.23.0 + """) + day_name = _make_nan_func('day_name', # noqa:E128 + """ + Return the day name of the Timestamp with specified locale. + Parameters + ---------- + locale : string, default None (English locale) + locale determining the language in which to return the day name + + Returns + ------- + day_name : string + + .. versionadded:: 0.23.0 + """) # _nat_methods - date = _make_nat_func('date', datetime) + date = _make_nat_func('date', datetime.date.__doc__) utctimetuple = _make_error_func('utctimetuple', datetime) timetz = _make_error_func('timetz', datetime) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 421f781483290..5bb53cf20b478 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -24,7 +24,7 @@ cimport ccalendar from conversion import tz_localize_to_utc, date_normalize from conversion cimport (tz_convert_single, _TSObject, convert_to_tsobject, convert_datetime_to_tsobject) -from fields import get_date_field, get_start_end_field +from fields import get_start_end_field, get_date_name_field from nattype import NaT from nattype cimport NPY_NAT from np_datetime import OutOfBoundsDatetime @@ -352,6 +352,16 @@ cdef class _Timestamp(datetime): field, freqstr, month_kw) return out[0] + cpdef _get_date_name_field(self, object field, object locale): + cdef: + int64_t val + ndarray out + + val = self._maybe_convert_value_to_local() + out = get_date_name_field(np.array([val], dtype=np.int64), + field, locale=locale) + return out[0] + @property def _repr_base(self): return '{date} {time}'.format(date=self._date_repr, @@ -714,12 +724,50 @@ class Timestamp(_Timestamp): def dayofweek(self): return self.weekday() + def day_name(self, locale=None): + """ + Return the day name of the Timestamp with specified locale. + + Parameters + ---------- + locale : string, default None (English locale) + locale determining the language in which to return the day name + + Returns + ------- + day_name : string + + .. versionadded:: 0.23.0 + """ + return self._get_date_name_field('day_name', locale) + + def month_name(self, locale=None): + """ + Return the month name of the Timestamp with specified locale. + + Parameters + ---------- + locale : string, default None (English locale) + locale determining the language in which to return the month name + + Returns + ------- + month_name : string + + .. versionadded:: 0.23.0 + """ + return self._get_date_name_field('month_name', locale) + @property def weekday_name(self): - cdef dict wdays = {0: 'Monday', 1: 'Tuesday', 2: 'Wednesday', - 3: 'Thursday', 4: 'Friday', 5: 'Saturday', - 6: 'Sunday'} - return wdays[self.weekday()] + """ + .. deprecated:: 0.23.0 + Use ``Timestamp.day_name()`` instead + """ + warnings.warn("`weekday_name` is deprecated and will be removed in a " + "future version. Use `day_name` instead", + DeprecationWarning) + return self.day_name() @property def dayofyear(self): diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index c9b446b97e956..6b97ee90cd93c 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -231,7 +231,6 @@ class DatetimeIndex(DatelikeOps, TimelikeOps, DatetimeIndexOpsMixin, week dayofweek weekday - weekday_name quarter tz freq @@ -260,6 +259,8 @@ class DatetimeIndex(DatelikeOps, TimelikeOps, DatetimeIndexOpsMixin, to_pydatetime to_series to_frame + month_name + day_name Notes ----- @@ -318,7 +319,7 @@ def _add_comparison_methods(cls): _datetimelike_methods = ['to_period', 'tz_localize', 'tz_convert', 'normalize', 'strftime', 'round', 'floor', - 'ceil'] + 'ceil', 'month_name', 'day_name'] _is_numeric_dtype = False _infer_as_myclass = True @@ -1713,7 +1714,7 @@ def freq(self, value): weekday_name = _field_accessor( 'weekday_name', 'weekday_name', - "The name of day in a week (ex: Friday)\n\n.. versionadded:: 0.18.1") + "The name of day in a week (ex: Friday)\n\n.. deprecated:: 0.23.0") dayofyear = _field_accessor('dayofyear', 'doy', "The ordinal day of the year") @@ -2097,6 +2098,58 @@ def to_julian_date(self): self.nanosecond / 3600.0 / 1e+9 ) / 24.0) + def month_name(self, locale=None): + """ + Return the month names of the DateTimeIndex with specified locale. + + Parameters + ---------- + locale : string, default None (English locale) + locale determining the language in which to return the month name + + Returns + ------- + month_names : Index + Index of month names + + .. versionadded:: 0.23.0 + """ + values = self.asi8 + if self.tz is not None: + if self.tz is not utc: + values = self._local_timestamps() + + result = fields.get_date_name_field(values, 'month_name', + locale=locale) + result = self._maybe_mask_results(result) + return Index(result, name=self.name) + + def day_name(self, locale=None): + """ + Return the day names of the DateTimeIndex with specified locale. + + Parameters + ---------- + locale : string, default None (English locale) + locale determining the language in which to return the day name + + Returns + ------- + month_names : Index + Index of day names + + .. versionadded:: 0.23.0 + """ + values = self.asi8 + if self.tz is not None: + if self.tz is not utc: + values = self._local_timestamps() + + result = fields.get_date_name_field(values, 'day_name', + locale=locale) + result = self._maybe_mask_results(result) + return Index(result, name=self.name) + DatetimeIndex._add_comparison_methods() DatetimeIndex._add_numeric_methods_disabled() diff --git a/pandas/tests/indexes/datetimes/test_misc.py b/pandas/tests/indexes/datetimes/test_misc.py index 2013b5e6cd6dd..a65b80efc7911 100644 --- a/pandas/tests/indexes/datetimes/test_misc.py +++ b/pandas/tests/indexes/datetimes/test_misc.py @@ -1,3 +1,6 @@ +import locale +import calendar + import pytest import numpy as np @@ -87,7 +90,6 @@ def test_range_edges(self): class TestDatetime64(object): def test_datetimeindex_accessors(self): - dti_naive = DatetimeIndex(freq='D', start=datetime(1998, 1, 1), periods=365) # GH 13303 @@ -134,23 +136,6 @@ def test_datetimeindex_accessors(self): assert not dti.is_year_end[0] assert dti.is_year_end[364] - # GH 11128 - assert dti.weekday_name[4] == u'Monday' - assert dti.weekday_name[5] == u'Tuesday' - assert dti.weekday_name[6] == u'Wednesday' - assert dti.weekday_name[7] == u'Thursday' - assert dti.weekday_name[8] == u'Friday' - assert dti.weekday_name[9] == u'Saturday' - assert dti.weekday_name[10] == u'Sunday' - - assert Timestamp('2016-04-04').weekday_name == u'Monday' - assert Timestamp('2016-04-05').weekday_name == u'Tuesday' - assert Timestamp('2016-04-06').weekday_name == u'Wednesday' - assert Timestamp('2016-04-07').weekday_name == u'Thursday' - assert Timestamp('2016-04-08').weekday_name == u'Friday' - assert Timestamp('2016-04-09').weekday_name == u'Saturday' - assert Timestamp('2016-04-10').weekday_name == u'Sunday' - assert len(dti.year) == 365 assert len(dti.month) == 365 assert len(dti.day) == 365 @@ -256,6 +241,54 @@ def test_datetimeindex_accessors(self): assert dates.weekofyear.tolist() == expected assert [d.weekofyear for d in dates] == expected + # GH 12806 + @pytest.mark.parametrize('time_locale', [ + None] if tm.get_locales() is None else [None] + tm.get_locales()) + def test_datetime_name_accessors(self, time_locale): + # Test Monday -> Sunday and January -> December, in that sequence + if time_locale is None: + # If the time_locale is None, day-name and month_name should + # return the english attributes + expected_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', + 'Friday', 'Saturday', 'Sunday'] + expected_months = ['January', 'February', 'March', 'April', 'May', + 'June', 'July', 'August', 'September', + 'October', 'November', 'December'] + else: + with tm.set_locale(time_locale, locale.LC_TIME): + expected_days = calendar.day_name[:] + expected_months = calendar.month_name[1:] + + # GH 11128 + dti = DatetimeIndex(freq='D', start=datetime(1998, 1, 1), + periods=365) + english_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', + 'Friday', 'Saturday', 'Sunday'] + for day, name, eng_name in zip(range(4, 11), + expected_days, + english_days): + name = name.capitalize() + assert dti.weekday_name[day] == eng_name + assert dti.day_name(locale=time_locale)[day] == name + ts = Timestamp(datetime(2016, 4, day)) + assert ts.weekday_name == eng_name + assert ts.day_name(locale=time_locale) == name + dti = dti.append(DatetimeIndex([pd.NaT])) + assert np.isnan(dti.day_name(locale=time_locale)[-1]) + ts = Timestamp(pd.NaT) + assert np.isnan(ts.day_name(locale=time_locale)) + + # GH 12805 + dti = DatetimeIndex(freq='M', start='2012', end='2013') + result = dti.month_name(locale=time_locale) + expected = Index([month.capitalize() for month in expected_months]) + tm.assert_index_equal(result, expected) + for date, expected in zip(dti, expected_months): + result = date.month_name(locale=time_locale) + assert result == expected.capitalize() + dti = dti.append(DatetimeIndex([pd.NaT])) + assert np.isnan(dti.month_name(locale=time_locale)[-1]) + def test_nanosecond_field(self): dti = DatetimeIndex(np.arange(10)) diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index 504a76f259e55..0acf7acb19c0d 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -4,6 +4,7 @@ import pytest import dateutil import calendar +import locale import numpy as np from dateutil.tz import tzutc @@ -21,7 +22,7 @@ from pandas.errors import OutOfBoundsDatetime from pandas.compat import long, PY3 from pandas.compat.numpy import np_datetime64_compat -from pandas import Timestamp, Period, Timedelta +from pandas import Timestamp, Period, Timedelta, NaT class TestTimestampProperties(object): @@ -95,13 +96,33 @@ def check(value, equal): for end in ends: assert getattr(ts, end) - @pytest.mark.parametrize('data, expected', - [(Timestamp('2017-08-28 23:00:00'), 'Monday'), - (Timestamp('2017-08-28 23:00:00', tz='EST'), - 'Monday')]) - def test_weekday_name(self, data, expected): + # GH 12806 + @pytest.mark.parametrize('data', + [Timestamp('2017-08-28 23:00:00'), + Timestamp('2017-08-28 23:00:00', tz='EST')]) + @pytest.mark.parametrize('time_locale', [ + None] if tm.get_locales() is None else [None] + tm.get_locales()) + def test_names(self, data, time_locale): # GH 17354 - assert data.weekday_name == expected + # Test .weekday_name, .day_name(), .month_name + with tm.assert_produces_warning(DeprecationWarning, + check_stacklevel=False): + assert data.weekday_name == 'Monday' + if time_locale is None: + expected_day = 'Monday' + expected_month = 'August' + else: + with tm.set_locale(time_locale, locale.LC_TIME): + expected_day = calendar.day_name[0].capitalize() + expected_month = calendar.month_name[8].capitalize() + + assert data.day_name(time_locale) == expected_day + assert data.month_name(time_locale) == expected_month + + # Test NaT + nan_ts = Timestamp(NaT) + assert np.isnan(nan_ts.day_name(time_locale)) + assert np.isnan(nan_ts.month_name(time_locale)) @pytest.mark.parametrize('tz', [None, 'UTC', 'US/Eastern', 'Asia/Tokyo']) def test_is_leap_year(self, tz): diff --git a/pandas/tests/series/test_datetime_values.py b/pandas/tests/series/test_datetime_values.py index 93c8ebc5f05df..3abc0f724db25 100644 --- a/pandas/tests/series/test_datetime_values.py +++ b/pandas/tests/series/test_datetime_values.py @@ -1,6 +1,8 @@ # coding=utf-8 # pylint: disable-msg=E1101,W0612 +import locale +import calendar import pytest from datetime import datetime, date @@ -32,7 +34,7 @@ def test_dt_namespace_accessor(self): ok_for_dt = DatetimeIndex._datetimelike_ops ok_for_dt_methods = ['to_period', 'to_pydatetime', 'tz_localize', 'tz_convert', 'normalize', 'strftime', 'round', - 'floor', 'ceil', 'weekday_name'] + 'floor', 'ceil', 'day_name', 'month_name'] ok_for_td = TimedeltaIndex._datetimelike_ops ok_for_td_methods = ['components', 'to_pytimedelta', 'total_seconds', 'round', 'floor', 'ceil'] @@ -274,6 +276,46 @@ def test_dt_accessor_no_new_attributes(self): "You cannot add any new attribute"): s.dt.xlabel = "a" + @pytest.mark.parametrize('time_locale', [ + None] if tm.get_locales() is None else [None] + tm.get_locales()) + def test_dt_accessor_datetime_name_accessors(self, time_locale): + # Test Monday -> Sunday and January -> December, in that sequence + if time_locale is None: + # If the time_locale is None, day-name and month_name should + # return the english attributes + expected_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', + 'Friday', 'Saturday', 'Sunday'] + expected_months = ['January', 'February', 'March', 'April', 'May', + 'June', 'July', 'August', 'September', + 'October', 'November', 'December'] + else: + with tm.set_locale(time_locale, locale.LC_TIME): + expected_days = calendar.day_name[:] + expected_months = calendar.month_name[1:] + + s = Series(DatetimeIndex(freq='D', start=datetime(1998, 1, 1), + periods=365)) + english_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', + 'Friday', 'Saturday', 'Sunday'] + for day, name, eng_name in zip(range(4, 11), + expected_days, + english_days): + name = name.capitalize() + assert s.dt.weekday_name[day] == eng_name + assert s.dt.day_name(locale=time_locale)[day] == name + s = s.append(Series([pd.NaT])) + assert np.isnan(s.dt.day_name(locale=time_locale).iloc[-1]) + + s = Series(DatetimeIndex(freq='M', start='2012', end='2013')) + result = s.dt.month_name(locale=time_locale) + expected = Series([month.capitalize() for month in expected_months]) + tm.assert_series_equal(result, expected) + for s_date, expected in zip(s, expected_months): + result = s_date.month_name(locale=time_locale) + assert result == expected.capitalize() + s = s.append(Series([pd.NaT])) + assert np.isnan(s.dt.month_name(locale=time_locale).iloc[-1]) + def test_strftime(self): # GH 10086 s = Series(date_range('20130101', periods=5))