Repository: pandas-dev/pandas
Pull request: TST: add test for #9107
test to ensure OutOfBoundsDatetime exception is raised when calling
pd.to_datetime with out-of-bounds date strings

As discussed briefly in #28367 

- [x] closes #9107 ? the issue is no longer truly reproducible, this PR adds a test around the new behaviour 
- [x] tests added / passed
- [x] passes `black pandas`
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry


Problem statement:
to_datetime returns NaT for old dates with coerce=True
When use `coerce=True` in `pandas.to_datetime` old dates (before 1677-09-22) return NaT. The same dates without `coerce` are parsed correctly:

```
print pd.to_datetime('13000101', format='%Y%m%d', coerce=True)
print pd.to_datetime('13000101', format='%Y%m%d')
```

returns 

```
NaT
1300-01-01 00:00:00
```

pandas: 0.15.2
numpy: 1.9.1

Hints from issue discussion:
I _believe_ this is intentional, although it is poorly documented. The return value in the second case is a `datetime.datetime` object rather than a `pandas.Timestamp` object. @jreback thoughts?

To be clear, this (old dates) is a case where `to_datetime` cannot turn the date into a `Timestamp`, which is the normal result. So it's a choice (controlled here by `coerce`) between returning a pandas compatible `NaT` object or plain python `datetime` object.

this is correct, the 2nd is a `datetime.datetime` (`Timestamp` is a sub-class of this).

not a bug. let's turn this to a further update to the docs (see #8921).

@vfilimonov want to do this?

as of 1.0.0-dev this looks to be resolved:
```python
pd.to_datetime('13000101', format='%Y%m%d')

...

~/pandas-squigmig/pandas/core/tools/datetimes.py in _convert_listlike_datetimes(arg, box, format, name, tz, unit, errors, infer_datetime_format, dayfirst, yearfirst, exact)
    412                 try:
    413                     result, timezones = array_strptime(
--> 414                         arg, format, exact=exact, errors=errors
    415                     )
    416                     if "%Z" in format or "%z" in format:

~/pandas-squigmig/pandas/_libs/tslibs/strptime.pyx in pandas._libs.tslibs.strptime.array_strptime()
    335                 iresult[i] = NPY_NAT
    336                 continue
--> 337             raise
    338 
    339         result_timezone[i] = timezone

~/pandas-squigmig/pandas/_libs/tslibs/strptime.pyx in pandas._libs.tslibs.strptime.array_strptime()
    330         iresult[i] = dtstruct_to_dt64(&dts)
    331         try:
--> 332             check_dts_bounds(&dts)
    333         except ValueError:
    334             if is_coerce:

~/pandas-squigmig/pandas/_libs/tslibs/np_datetime.pyx in pandas._libs.tslibs.np_datetime.check_dts_bounds()
    116                                                dts.day, dts.hour,
    117                                                dts.min, dts.sec)
--> 118         raise OutOfBoundsDatetime(
    119             'Out of bounds nanosecond timestamp: {fmt}'.format(fmt=fmt))
    120 

OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 1300-01-01 00:00:00
```

Commit message: add test for #9107

test to ensure OutOfBoundsDatetime exception is raised when calling
pd.to_datetime with out-of-bounds date strings

Patch to review:
diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst
index 9840e4e94d28c..902503473c952 100644
--- a/doc/source/whatsnew/v1.0.0.rst
+++ b/doc/source/whatsnew/v1.0.0.rst
@@ -118,7 +118,7 @@ Datetimelike
 - Bug in :meth:`pandas.core.groupby.SeriesGroupBy.nunique` where ``NaT`` values were interfering with the count of unique values (:issue:`27951`)
 - Bug in :class:`Timestamp` subtraction when subtracting a :class:`Timestamp` from a ``np.datetime64`` object incorrectly raising ``TypeError`` (:issue:`28286`)
 - Addition and subtraction of integer or integer-dtype arrays with :class:`Timestamp` will now raise ``NullFrequencyError`` instead of ``ValueError`` (:issue:`28268`)
--
+- New test to ensure OutOfBoundsDatetime exception is raised when calling :func:``pd.to_datetime`` with out-of-bounds date strings
 
 
 Timedelta
diff --git a/pandas/tests/indexes/datetimes/test_tools.py b/pandas/tests/indexes/datetimes/test_tools.py
index 9af0f47f6dce9..a57b69971a458 100644
--- a/pandas/tests/indexes/datetimes/test_tools.py
+++ b/pandas/tests/indexes/datetimes/test_tools.py
@@ -1028,6 +1028,12 @@ def test_to_datetime_box_deprecated(self):
         result = pd.to_datetime(expected).to_datetime64()
         assert result == expected
 
+    @pytest.mark.parametrize("dt_str", ["00010101", "13000101", "30000101", "99990101"])
+    def test_old_date_out_of_bounds_exception(self, dt_str):
+        # GH 9107
+        with pytest.raises(OutOfBoundsDatetime):
+            pd.to_datetime(dt_str, format="%Y%m%d")
+
 
 class TestToDatetimeUnit:
     @pytest.mark.parametrize("cache", [True, False])


Code review comments:
diff_hunk: @@ -1028,6 +1028,12 @@ def test_to_datetime_box_deprecated(self):
         result = pd.to_datetime(expected).to_datetime64()
         assert result == expected
 
+    @pytest.mark.parametrize("dt_str", ["00010101", "13000101", "30000101", "99990101"])
+    def test_old_date_out_of_bounds_exception(self, dt_str):
path: pandas/tests/indexes/datetimes/test_tools.py
text: @user1:
a more informative name would be e.g. `test_to_datetime_with_format_out_of_bounds`

@author:
thanks - this is both more conventional and more informative