Implement roll_monthday, simplify SemiMonthOffset
State: closed

- [ ] closes #xxxx
- [ ] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [ ] whatsnew entry


Labels:
name: Performance
description: Memory or execution speed performance
name: Frequency
description: DateOffsets

Comments:
once have cleaned code, show perf benchmarks for this (and add if we don't have appropriate ones).
Looks like SemiMonthOffset gets the slight bump we'd expect and everything else is noise.

```
asv continuous -f 1.1 -E virtualenv master HEAD -b offset
[...]
   before     after       ratio
  [96439fb1] [eb5e72f5]
+   16.23μs    23.12μs      1.42  offset.CBDay.time_custom_bday_apply
+    6.87ms     8.53ms      1.24  offset.ApplyIndex.time_apply_series(<QuarterBegin: startingMonth=3>)
+   18.05μs    21.92μs      1.21  offset.CBDay.time_custom_bday_incr
+   16.97μs    19.10μs      1.13  offset.CBDay.time_custom_bday_apply_dt64
+    1.16μs     1.28μs      1.11  timestamp.TimestampProperties.time_offset(<DstTzInfo 'Europe/Amsterdam' LMT+0:20:00 STD>, None)
-   12.03μs    10.91μs      0.91  offset.SemiMonthOffset.time_begin_apply
-    6.05ms     5.46ms      0.90  offset.ApplyIndex.time_apply_index(<BusinessYearBegin: month=1>)
-   23.00μs    20.70μs      0.90  offset.SemiMonthOffset.time_end_decr_n
-   11.75μs    10.54μs      0.90  offset.SemiMonthOffset.time_end_apply
-   15.54μs    13.77μs      0.89  offset.SemiMonthOffset.time_end_incr
-    4.34ms     3.83ms      0.88  offset.SeriesArithmetic.time_add_offset_delta
-   29.34μs    25.84μs      0.88  offset.CBDayHolidays.time_custom_bday_cal_incr
-    8.40ms     7.29ms      0.87  offset.ApplyIndex.time_apply_index(<BusinessYearEnd: month=12>)
-   20.91μs    17.11μs      0.82  offset.SemiMonthOffset.time_begin_decr
-   22.30μs    17.18μs      0.77  offset.SemiMonthOffset.time_end_decr
-   14.15ms     7.96ms      0.56  offset.ApplyIndex.time_apply_series(<BusinessMonthBegin>)
-   16.55ms     9.24ms      0.56  offset.ApplyIndex.time_apply_series(<BusinessMonthEnd>)
```

```
taskset 5 asv continuous -f 1.1 -E virtualenv master HEAD -b offset
[...]
    before     after       ratio
  [96439fb1] [eb5e72f5]
+    8.11ms    15.89ms      1.96  offset.ApplyIndex.time_apply_series(<YearEnd: month=12>)
+   20.26μs    29.91μs      1.48  offset.SemiMonthOffset.time_begin_incr_n
+   16.89μs    20.50μs      1.21  offset.Day.time_timeseries_day_apply
+   28.96μs    32.43μs      1.12  offset.CBDayHolidays.time_custom_bday_cal_incr_neg_n
-   15.23μs    13.66μs      0.90  offset.SemiMonthOffset.time_begin_incr
-    7.66ms     6.86ms      0.90  offset.ApplyIndex.time_apply_index(<BusinessQuarterEnd: startingMonth=3>)
-   21.74μs    19.35μs      0.89  offset.SemiMonthOffset.time_end_decr_n
-    8.38ms     7.38ms      0.88  offset.ApplyIndex.time_apply_series(<BusinessYearBegin: month=1>)
-   12.71μs    11.08μs      0.87  offset.SemiMonthOffset.time_end_apply
-   19.09μs    16.60μs      0.87  offset.SemiMonthOffset.time_end_incr_n
-   10.41ms     8.84ms      0.85  offset.ApplyIndex.time_apply_series(<BusinessQuarterEnd: startingMonth=3>)
-   22.04μs    18.60μs      0.84  offset.SemiMonthOffset.time_begin_decr_n
```

```
taskset 5 asv continuous -f 1.1 -E virtualenv master HEAD -b offset
[...]
    before     after       ratio
  [96439fb1] [eb5e72f5]
+   13.10μs    25.49μs      1.95  offset.YearBegin.time_timeseries_year_incr
+    3.54ms     6.22ms      1.76  offset.SeriesArithmetic.time_add_offset_delta
+   23.15ms    26.46ms      1.14  frame_ctor.FromDictwithTimestamp.time_dict_with_timestamp_offsets(<Hour>)
+   14.95μs    16.76μs      1.12  offset.CBDay.time_custom_bday_apply
+   17.63μs    19.41μs      1.10  offset.CBDay.time_custom_bday_incr
-   31.88μs    28.77μs      0.90  offset.CBDayHolidays.time_custom_bday_cal_incr_neg_n
-   20.69μs    18.62μs      0.90  offset.SemiMonthOffset.time_end_decr_n
-   11.50μs    10.33μs      0.90  offset.SemiMonthOffset.time_end_apply
-   20.48μs    18.36μs      0.90  offset.SemiMonthOffset.time_begin_decr
-    8.16ms     7.15ms      0.88  offset.ApplyIndex.time_apply_series(<QuarterEnd: startingMonth=3>)
-   15.90μs    13.51μs      0.85  offset.SemiMonthOffset.time_begin_incr
-   14.35μs    10.19μs      0.71  offset.SemiMonthOffset.time_begin_apply
-   15.78ms     9.18ms      0.58  offset.ApplyIndex.time_apply_series(<BusinessQuarterEnd: startingMonth=3>)
```
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/18762?src=pr&el=h1) Report
> Merging [#18762](https://codecov.io/gh/pandas-dev/pandas/pull/18762?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/84335621ad0a0d83302a80b6911d3985c00b5cee?src=pr&el=desc) will **decrease** coverage by `<.01%`.
> The diff coverage is `100%`.

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

```diff
@@            Coverage Diff             @@
##           master   #18762      +/-   ##
==========================================
- Coverage   91.58%   91.57%   -0.01%     
==========================================
  Files         150      150              
  Lines       48972    48933      -39     
==========================================
- Hits        44851    44812      -39     
  Misses       4121     4121
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `89.94% <100%> (-0.01%)` | :arrow_down: |
| #single | `41.75% <39.39%> (+0.02%)` | :arrow_up: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/18762?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/tseries/offsets.py](https://codecov.io/gh/pandas-dev/pandas/pull/18762/diff?src=pr&el=tree#diff-cGFuZGFzL3RzZXJpZXMvb2Zmc2V0cy5weQ==) | `96.97% <100%> (-0.1%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/18762?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/18762?src=pr&el=footer). Last update [8433562...a5d9dee](https://codecov.io/gh/pandas-dev/pandas/pull/18762?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

Travis error is in test_geopandas; will wait to re-push until given the go-ahead.
I pushed a fix for geopandas you can rebase
Timeout
Will this be easier if split into smaller pieces?
This is becoming a blocker for fixing bugs in SemiMonthOffsets.
> only minor nitpick and can be fixed later (or here if you want)

Definitely later.  Some of this has crept into the scope of #18959, and `roll_monthday` I'm _hoping_ will be made unnecessary after some of the upcoming bugfixes.
ok, make a note of that, and rebase. ping on green.
ping
thanks!