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

ENH: Return locale based month_name and weekday_name values (#12805, #12806) #18164

Merged
merged 1 commit into from
Mar 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
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
9 changes: 6 additions & 3 deletions doc/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,6 @@ These can be accessed like ``Series.dt.<property>``.
Series.dt.weekofyear
Series.dt.dayofweek
Series.dt.weekday
Series.dt.weekday_name
Series.dt.dayofyear
Series.dt.quarter
Series.dt.is_month_start
Expand Down Expand Up @@ -581,6 +580,8 @@ These can be accessed like ``Series.dt.<property>``.
Series.dt.round
Series.dt.floor
Series.dt.ceil
Series.dt.month_name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if weekday_name is anywhere here can you remove

Series.dt.day_name

**Timedelta Properties**

Expand Down Expand Up @@ -1723,7 +1724,6 @@ Time/Date Components
DatetimeIndex.week
DatetimeIndex.dayofweek
DatetimeIndex.weekday
DatetimeIndex.weekday_name
DatetimeIndex.quarter
DatetimeIndex.tz
DatetimeIndex.freq
Expand Down Expand Up @@ -1759,6 +1759,8 @@ Time-specific operations
DatetimeIndex.round
DatetimeIndex.floor
DatetimeIndex.ceil
DatetimeIndex.month_name
DatetimeIndex.day_name

Conversion
~~~~~~~~~~
Expand Down Expand Up @@ -1940,7 +1942,6 @@ Properties
Timestamp.tzinfo
Timestamp.value
Timestamp.week
Timestamp.weekday_name
Timestamp.weekofyear
Timestamp.year

Expand All @@ -1954,6 +1955,7 @@ Methods
Timestamp.combine
Timestamp.ctime
Timestamp.date
Timestamp.day_name
Timestamp.dst
Timestamp.floor
Timestamp.freq
Expand All @@ -1963,6 +1965,7 @@ Methods
Timestamp.isocalendar
Timestamp.isoformat
Timestamp.isoweekday
Timestamp.month_name
Timestamp.normalize
Timestamp.now
Timestamp.replace
Expand Down
4 changes: 3 additions & 1 deletion doc/source/whatsnew/v0.23.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 <https://www.mathjax.org/>`_ 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:

Expand Down Expand Up @@ -677,6 +678,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:

Expand Down
29 changes: 29 additions & 0 deletions pandas/_libs/tslibs/ccalendar.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Unfortunately) yes.

In [2]: list(calendar.month_name)
Out[2]:
['',
 'January',
 'February',
 'March',
 'April',
 'May',
 'June',
 'July',
 'August',
 'September',
 'October',
 'November',
 'December']

# 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}

Expand Down Expand Up @@ -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)
35 changes: 25 additions & 10 deletions pandas/_libs/tslibs/fields.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -85,34 +85,49 @@ 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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of using _dayname, _monthname, use cdef names ndarray[object]

_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
continue

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)
Expand Down
49 changes: 36 additions & 13 deletions pandas/_libs/tslibs/nattype.pyx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
# cython: profile=False
import warnings

from cpython cimport (
PyFloat_Check, PyComplex_Check,
Expand Down Expand Up @@ -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


Expand Down Expand Up @@ -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)
Expand Down
58 changes: 53 additions & 5 deletions pandas/_libs/tslibs/timestamps.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can u have this call day_name

return self.day_name()

@property
def dayofyear(self):
Expand Down
Loading