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

closes #12805
closes #12806
- [x] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry

I am not sure what locales are available on the CI machines, but the test will run all available locales. 

Labels:
name: Enhancement
name: Datetime
description: Datetime data dtype
name: Compat
description: pandas objects compatability with Numpy or Python functions

Comments:
need to add month_name to nat docstrings generation
Added `month_name` as a property to NaT, moved whatsnew updates, and moved name accessor tests to their own function with a skip if no locales are available. 
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=h1) Report
> Merging [#18164](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/ca737aca8b73b10b617f7fcc7da35545f9ec0a89?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/18164/graphs/tree.svg?src=pr&width=650&token=eZ4WkYLtcO&height=150)](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #18164      +/-   ##
==========================================
+ Coverage    91.4%    91.4%   +<.01%     
==========================================
  Files         163      163              
  Lines       50064    50069       +5     
==========================================
+ Hits        45759    45768       +9     
+ Misses       4305     4301       -4
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `89.21% <100%> (+0.02%)` | :arrow_up: |
| #single | `40.39% <100%> (-0.04%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/indexes/datetimes.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9kYXRldGltZXMucHk=) | `95.48% <100%> (+0.1%)` | :arrow_up: |
| [pandas/io/gbq.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree#diff-cGFuZGFzL2lvL2dicS5weQ==) | `25% <0%> (-58.34%)` | :arrow_down: |
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.8% <0%> (-0.1%)` | :arrow_down: |
| [pandas/io/formats/format.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree#diff-cGFuZGFzL2lvL2Zvcm1hdHMvZm9ybWF0LnB5) | `96.01% <0%> (ø)` | :arrow_up: |
| [pandas/core/generic.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ2VuZXJpYy5weQ==) | `95.72% <0%> (ø)` | :arrow_up: |
| [pandas/core/config\_init.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvY29uZmlnX2luaXQucHk=) | `98.34% <0%> (ø)` | :arrow_up: |
| [pandas/core/groupby.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ3JvdXBieS5weQ==) | `92.04% <0%> (+0.01%)` | :arrow_up: |
| [pandas/plotting/\_converter.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree#diff-cGFuZGFzL3Bsb3R0aW5nL19jb252ZXJ0ZXIucHk=) | `65.2% <0%> (+1.81%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=footer). Last update [ca737ac...6f39578](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=h1) Report
> Merging [#18164](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/5f271eb2e76a78b089879e3528018463ea0eeb1c?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/18164/graphs/tree.svg?token=eZ4WkYLtcO&src=pr&height=150&width=650)](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #18164      +/-   ##
==========================================
+ Coverage   91.69%   91.69%   +<.01%     
==========================================
  Files         150      150              
  Lines       49043    48997      -46     
==========================================
- Hits        44968    44929      -39     
+ Misses       4075     4068       -7
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.07% <100%> (ø)` | :arrow_up: |
| #single | `41.94% <12.5%> (+0.12%)` | :arrow_up: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/indexes/datetimes.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9kYXRldGltZXMucHk=) | `95.57% <100%> (-0.02%)` | :arrow_down: |
| [pandas/core/indexes/base.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9iYXNlLnB5) | `96.45% <0%> (-0.22%)` | :arrow_down: |
| [pandas/core/internals.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW50ZXJuYWxzLnB5) | `95.53% <0%> (-0.01%)` | :arrow_down: |
| [pandas/io/formats/format.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL2Zvcm1hdHMvZm9ybWF0LnB5) | `96.25% <0%> (-0.01%)` | :arrow_down: |
| [pandas/core/generic.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ2VuZXJpYy5weQ==) | `95.88% <0%> (-0.01%)` | :arrow_down: |
| [pandas/core/config\_init.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvY29uZmlnX2luaXQucHk=) | `100% <0%> (ø)` | :arrow_up: |
| [pandas/core/indexes/range.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9yYW5nZS5weQ==) | `95.7% <0%> (ø)` | :arrow_up: |
| [pandas/core/groupby.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ3JvdXBieS5weQ==) | `92.31% <0%> (+0.17%)` | :arrow_up: |
| [pandas/io/formats/style.py](https://codecov.io/gh/pandas-dev/pandas/pull/18164/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL2Zvcm1hdHMvc3R5bGUucHk=) | `96.22% <0%> (+0.18%)` | :arrow_up: |
| ... and [1 more](https://codecov.io/gh/pandas-dev/pandas/pull/18164/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=footer). Last update [5f271eb...d97f43b](https://codecov.io/gh/pandas-dev/pandas/pull/18164?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

> > @mroeschke  We could turn weekday_name and month_name into functions that can accept a locale argument and default it to 'en_US.UTF8'? I think that would be clean, but it would definitely be an API change.

> @jreback hmm, that's an idea. we could could make new ones weekday_names() (and then just deprecate weekday_name

That's an option. Another option is to leave it as is but to clearly document in those attributes how to get your locale dependent names. Eg it would be nice that the following would work:

```
In [26]: import calendar

In [27]: dt = pd.date_range('2016-01-01', periods=10, freq='10D')

In [28]: dt.weekday
Out[28]: Int64Index([4, 0, 3, 6, 2, 5, 1, 4, 0, 3], dtype='int64')

In [29]: dt.weekday.map(calendar.day_name)
...
TypeError: '_localized_day' object is not callable
```

(the problem here is that `calendar.day_name` is some kind of mapping (it has `__getitem__`) but not really)

This works:

```
In [32]: pd.Series(dt.weekday).map({i: calendar.day_name[i] for i in range(7)})
Out[32]: 
0       Friday
1       Monday
2     Thursday
3       Sunday
4    Wednesday
5     Saturday
6      Tuesday
7       Friday
8       Monday
9     Thursday
dtype: object
```

(second issue is that `Index.map` apparently does not work with dict, while `Series.map` does)

But I think both issues could be solved to make this easier.
(On the other hand, such a pointer in the docstring is certainly less discoverable than a `month_name` method, I just in doubt this is worth it adding yet another method ..)
Index.map dict issue is reported here: https://github.com/pandas-dev/pandas/issues/13517
I'll summarize the proposals and add an additional one:

1) Default to the user's system's locale (this PR)
2) Create a new function (would personally prefer `.day_name(locale='en_US.UTF8')` harmonizing with `calendar.day_name`)
3) Default to English locale and enhance the docs with a locale recipe
4) Utilize `pandas.set_option` and add something like `mode.time_locale`, defaulting to the English locale. 
 
I think 4) would be a nice option to maintain the existing behavior and minimize altering existing methods. Otherwise I think I'd prefer 3) over 2) (I realize the Pandas API is already large).

What do you guys think @jreback @jorisvandenbossche? 
so I actually like renaming ``weekday_name`` -> ``day_name`` regardless here for consistency.

4) is interesting

I wonder how common the need to look things up in different locales is, if its not that common (guess), then this makes sense

2) appeals as well (talking about the argument for the locale in the function call)

I decided to implement a `day_name(time_locale=None)` and `month_name(time_locale=None)` method that can accept a locale argument. Wanted to run the implementation by you guys. 

Also, should I got ahead and also depreciate the `.weekday_name` attribute in this PR?
> I decided to implement a day_name(time_locale=None) and month_name(time_locale=None) method that can accept a locale argument. Wanted to run the implementation by you guys.

that sounds good

> Also, should I got ahead and also depreciate the .weekday_name attribute in this PR?

yes this is also ok
Sorry for being idle on this PR. Rebased, and added the `day_name()` and `month_name()` methods to `Timestamp` and `DatetimeIndex`
Created `get_locale_names` in `ccalendar.pyx` that provides localized day and month names, `_make_missing_value_func` to replace `_make_nan_func` and `_make_nat_func`, and added deprecation to `weekday_name`

Although, I am not sure how to add a deprecation warning to `DatetimeIndex.weekday_name` since the method is pre-generated with `_field_accessor`
Simplified the `dict(enumerate(...))` calls, added a test for a depreciation warning, and added a test for `time_locale=None`

The `None` tests are failing on CI, but they are working locally for me.

```
pytest pandas/tests/scalar/test_timestamp.py::TestTimestamp::test_names
============================= test session starts ==============================
platform linux2 -- Python 2.7.13, pytest-3.2.1, py-1.4.34, pluggy-0.4.0
rootdir: /home/matt/Projects/pandas-mroeschke, inifile: setup.cfg
plugins: forked-0.2, cov-2.5.1
collected 92 items                                                              

pandas/tests/scalar/test_timestamp.py ............................................................................................

========================== 92 passed in 3.20 seconds ===========================
```

```
pytest pandas/tests/indexes/datetimes/test_misc.py::TestDatetime64::test_datetime_name_accessors
============================= test session starts ==============================
platform linux2 -- Python 2.7.13, pytest-3.2.1, py-1.4.34, pluggy-0.4.0
rootdir: /home/matt/Projects/pandas-mroeschke, inifile: setup.cfg
plugins: forked-0.2, cov-2.5.1
collected 46 items                                                              

pandas/tests/indexes/datetimes/test_misc.py ..............................................

========================== 46 passed in 1.20 seconds ===========================
```
Sorry for also not answering earlier to your overview of options https://github.com/pandas-dev/pandas/pull/18164#issuecomment-343548001. I still think the question "is it worth new methods given the already huge api" is an important one.

Regarding the current PR, I know day_name is to be consistent with the calendar module, but we already have both weekday and weekday_name attributes. Shouldn't we rather be consistent with ourselves? (not many people are familiar with calendar module)
I think the API that @mroeschke puts up is pretty reasonable. (option 2).

``weekday`` is a datetime method which we follow, ``weekday_name`` is basically invented; its a property (to go along with our API), and is not really anymore descriptive (and confusing actually, its not actually returning the weekday, but a day name).

``day_name``, when put alongside ``month_name`` is pretty reasonable. Further allowing locale optional is a nice enhancement.

If we could easily turn ``weekday_name`` from a property to a function I would be more inclines to not break and go with @jorisvandenbossche ; This is possible, but not easy. 
After a couple of version releases, this PR will have added a net of 1 API method (add `day_name` and `month_name`, depreciate and remove `weekday_name`). Of course there will be API change inertia in the interim, but I would guess `weekday_name` isn't a highly utilized API method (I might have personally only used it once when working with timeseries data).

I would also think it's a benefit to match standard library naming conventions when applicable. Also agreed with @jreback point of `weekday_name` being slightly misleading
@mroeschke can you rebase. this looks fine (have to review again)
@jreback rebased. Looks like Travis failed due to a pyarrow import failure. 
rebase on master
Rebased on master and addressed your comments @jreback. Looks like a travis build timed out.  
I believe I addressed everything

- Testing NaT
- Moved/added comments to tests
- Added tests for Series.dt.*name
- Added versionadded notes
- reused get_name_date_field in Timestamp
- renamed time_locale to locale
Changed name to names, and used the day_name method for weekday_name. All green
@jorisvandenbossche @TomAugspurger lgtm. if any final comments.
Removed doc instances of `weekday_name` and all green (minus a Travis timeout)
thanks @mroeschke nice patch!
@mroeschke a number of deprecation warnings need catching.
also these should be FutureWarning and not DeprecationWarning. can you do a followup.

```
  /home/travis/build/pandas-dev/pandas/pandas/tests/indexes/datetimes/test_misc.py:274: DeprecationWarning: `weekday_name` is deprecated and will be removed in a future version. Use `day_name` instead
    assert ts.weekday_name == eng_name
```