ENH: Add isocalendar accessor to DatetimeIndex and Series.dt
State: closed

This PR adds the the isocalendar property to `DatetimeIndex` and the corresponding `Series.dt` accessor.    The property returns a DataFrame, e.g.:

```python
>>> idx = pd.date_range(start='2019-12-29', freq='D', periods=4)
>>> idx.isocalendar
   year  week  day
0  2019    52    7
1  2020     1    1
2  2020     1    2
3  2020     1    3
```

and 

```python
>>> pandas.to_datetime(pandas.Series(["2020-01-01"])).dt.isocalendar
   year  week  day
0  2020     1    
>>> pandas.to_datetime(pandas.Series(["2019-12-31"])).dt.isocalendar.week
0    1
Name: week, dtype: int32
```

The behavior is consistent with `Timestamp.isocalendar` and `datetime.date.isocalendar`.

For more information about ISO 8601 calendar, see e.g. https://en.wikipedia.org/wiki/ISO_week_date.

Address GH33206

- [x] closes #33206 
- [x] tests added / passed
- [x] passes `black pandas`
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry

Note that I am very happy to rename the field, but I wanted to go ahead and open up the PR.


Labels:
name: Enhancement
name: Datetime
description: Datetime data dtype

Comments:
Thanks for the PR. I agree the naming is a little weird, though do we need a dedicated property for this? Might be more natural to just convert to the appropriate period and still use the .year attribute therefrom

@jbrockmendel @mroeschke 
Agreed with @WillAyd.

Since `Timestamp` has an `isocalendar` method from the standard library, I wouldn't be opposed to a `DatetimeIndex.isocalendar` or `Series.dt.isocalendar` method that converts the dates to returns a 3-tuple, (ISO year, ISO week number, ISO weekday). 
@WillAyd @mroeschke Thanks for the comments!  

I agree that the `isocalendar` method approach is cleaner and more symmetric with `Timestamp`, this was slightly easier for me to get my feet wet with the code.  An additional advantage of this is that it makes it clearer that all values are calculated using ISO (8601).  

Regarding whether this functionality is needed at all, I think if `weekofyear` is provided (which is currently the ISO week), then there absolutely should to be a way to get the year that corresponds to it.  
I'd say if we include `isocalendar` (and think of a nice API to easily get the `.year`, `.week`, etc), we could deprecate `weekofyear` (which `datetime.datetime` doesn't have).

Generally, I believe we should align all `.dt` attributes/methods to what exists in `datetime.datetime`)
Yes, I think a series of tuples is not completely user friendly.  What about like what's done in `.dt.components` [here](https://github.com/pandas-dev/pandas/blob/master/pandas/core/indexes/accessors.py#L249), i.e. it returns a frame?  

`isocalendar` could be a property returning a frame (with three columns `year`, `week`, `day`), and then the respective series could simply be accessed like: 

```python
.dt.isocalendar.year
.dt.isocalendar.week
.dt.isocalendar.day
```
What do you think?

Re the deprecation of `weekofyear`, I think that would be a good idea.  I get the impression that there's confusion around it by looking through old issues.  By access `week` through `isocalendar`, it would I think reduce confusion.
+1 to that API @mgmarino. Interested in working on both the `isocalendar` addition and deprecation of  `weekofyear` (and if there's additional attributes like this)?
Definitely!  I'll need a bit of a hand with the Deprecation process, but I think I'm pretty clear how to implement `isocalendar`.  The deprecation should probably be done in a separate PR anyways.  

For the `isocalendar` changes, shall I just keep this PR (to have the thread), with an appropriate rename? 
> The deprecation should probably be done in a separate PR anyways.

Sure sounds good.

> For the isocalendar changes, shall I just keep this PR (to have the thread), with an appropriate rename?

Definitely. Feel free to retool this PR (and original issue) about adding `isocalendar`
FYI, the failing tests seem to be due to visual studio not liking the ctuple return. I’ll still need some time to investigate a fix and/or rewrite to avoid the ctuple. 
@mroeschke  

Ok, I'm pretty confident that the build will now succeed (it succeeded on my local Azure pipelines), but here's the news:

- The error was due to a bug in cython fixed in 0.29.16 (See cython/cython#2745, cython/cython#1427)
- Because of this, I had to bump the minimum version of cython to 0.29.16.  

So, I would understand if this feature is not important enough to do this, so I'm happy to have your feedback, if I should:

- leave as is,
- bump the dependency version upgrade out to a separate PR.
- rework the internal code to avoid using ctuple.
- other?

Thanks for your help on this!
I think it's okay to bump Cython since it's a build dependency cc @jbrockmendel. 
Current comments addressed, failing doc build seems to be handled with #33309.
i think we're OK to bump cython to the newest bugfix release
@jbrockmendel @jreback @mroeschke Thank you for the comments, I believe they should be addressed now.  Once #33334 is merged, I'll rebase.
Rebased, happy to hear any further comments!
@jreback Thanks for the comments, I finally understood it now.   

Dtype -> UInt32, Doc added, Tests green.
lgtm. cc @TomAugspurger ok here?
this lgtm. let's merge on green.
Thanks @mgmarino! Very nice. Happy to have a follow up to deprecate weekofyear. 
Since `isocalendar`is a *method* and not an attribute on `Timestamp`, should we make `dt.isocalendar` a method instead of a property as well for consistency?
Good point @jorisvandenbossche. 

@mgmarino mind creating a follow up PR that makes `isocalendar` a method instead of an attribute? 
> mind creating a follow up PR that makes isocalendar a method instead of an attribute?

@mroeschke Sure no problem, seems reasonable.  The PR is open, I'll ping on green.  

> Happy to have a follow up to deprecate weekofyear.

Will do soon!