Skip to content

Commit

Permalink
Add month names (pandas-dev#18164)
Browse files Browse the repository at this point in the history
  • Loading branch information
mroeschke authored and jreback committed Mar 4, 2018
1 parent 2fad756 commit 607910b
Show file tree
Hide file tree
Showing 10 changed files with 330 additions and 61 deletions.
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
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 @@ -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:

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

_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)
return self.day_name()

@property
def dayofyear(self):
Expand Down
Loading

0 comments on commit 607910b

Please sign in to comment.