Repository: pandas-dev/pandas
Pull request: ENH: Timestamp constructor now raises more explanatory error message
Timestamp constructor now raises explanatory error message when year, month or day is missing

- [x] closes #31200
- [x] tests added / passed
- [x] passes `black pandas`
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry


Problem statement:
raise more explanatory error when failing initialising pd.Timestamp
It's not really an issue, just a suggestion. I noticed this behavior when initialising a timestamp:

```python
# this doesn't fail
pd.Timestamp('2020')
# this does
pd.Timestamp(year=2020)
```

I guess that the latter fails because of args/kwargs specification issues (when an integer is passed it is read as a posix timestamp in the first place), and I'm OK with it. However, the error it raises is:

```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-e2faf77534f3> in <module>
----> 1 pd.Timestamp(year=2020)

pandas/_libs/tslibs/timestamps.pyx in pandas._libs.tslibs.timestamps.Timestamp.__new__()

TypeError: an integer is required (got type NoneType)
```

This is a bit misleading for beginners - it doesn't say anything about **why** it failed, but just about **what** failed.

Is there a chance it can be changed to something more explicit in the long term? Something like "provide at least year, month, day"?

Hints from issue discussion:
Since `Timestamp` inherits from `datetime.datetime`, we should just ideally dispatch to the same error message `datetime.datetime` would raise.

```
In [2]: datetime.datetime(year=2020)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-0cf88a91ae91> in <module>()
----> 1 datetime.datetime(year=2020)

TypeError: Required argument 'month' (pos 2) not found
```
I will take a look

Commit message: ENH: Timestamp constructor now raises more explanatory error message (GH31200)

Timestamp constructor now raises explanatory error message when year, month or day is missing

Patch to review:
diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst
index dc7edd8db662e..c5090fa26737f 100644
--- a/doc/source/whatsnew/v1.1.0.rst
+++ b/doc/source/whatsnew/v1.1.0.rst
@@ -42,7 +42,7 @@ Other enhancements
 ^^^^^^^^^^^^^^^^^^
 
 - :class:`Styler` may now render CSS more efficiently where multiple cells have the same styling (:issue:`30876`)
--
+- :func:`Timestamp` now raises more explanatory error message when year, month or day is missing (:issue:`31200`)
 -
 
 .. ---------------------------------------------------------------------------
diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx
index 4915671aa6512..5dcc58865d799 100644
--- a/pandas/_libs/tslibs/timestamps.pyx
+++ b/pandas/_libs/tslibs/timestamps.pyx
@@ -412,6 +412,17 @@ class Timestamp(_Timestamp):
                 )
 
         elif ts_input is _no_input:
+            # GH 31200
+            # When year, month or day is not given, we call the datetime
+            # constructor to make sure we get the same error message
+            # since Timestamp inherits datetime
+            if year is None:
+                datetime(month=month, day=day)
+            elif month is None:
+                datetime(year=year, day=day)
+            elif day is None:
+                datetime(year=year, month=month)
+
             # User passed keyword arguments.
             ts_input = datetime(year, month, day, hour or 0,
                                 minute or 0, second or 0,
diff --git a/pandas/tests/tslibs/test_timestamps.py b/pandas/tests/tslibs/test_timestamps.py
new file mode 100644
index 0000000000000..b14926fb9b13f
--- /dev/null
+++ b/pandas/tests/tslibs/test_timestamps.py
@@ -0,0 +1,11 @@
+import pytest
+
+from pandas import Timestamp
+
+
+@pytest.mark.parametrize("kwargs", [{}, {"year": 2020}, {"year": 2020, "month": 1}])
+def test_timestamp_constructor_missing_keyword(kwargs):
+    # GH 31200
+    msg = r"function missing required argument .* \(pos .\)"
+    with pytest.raises(TypeError, match=msg):
+        Timestamp(**kwargs)


Code review comments:
diff_hunk: @@ -412,6 +412,17 @@ class Timestamp(_Timestamp):
                 )
 
         elif ts_input is _no_input:
+            # GH 31200
+            # When year, month or day is not given, we call the datetime
+            # constructor to make sure we get the same error message
+            # since Timestamp inherits datetime
+            if year is None:
path: pandas/_libs/tslibs/timestamps.pyx
text: @user1:
Let's just leverage the `datetime` call below when it's assigned to `ts_input` to raise the error for us.

Maybe something like:

```
datetime_kwargs = {'hour': hours or 0, 'minute': minute or 0, ...}
if year is not None:
    datetime_kwargs['year'] = year
if month is not None:
    ...
ts_input = datetime(**datetime_kwargs)
```

@author:
this is a great idea, I have adapted the code. Thanks

diff_hunk: @@ -42,7 +42,7 @@ Other enhancements
 ^^^^^^^^^^^^^^^^^^
 
 - :class:`Styler` may now render CSS more efficiently where multiple cells have the same styling (:issue:`30876`)
--
+- :func:`Timestamp` now raises more explanatory error message when year, month or day is missing (:issue:`31200`)
path: doc/source/whatsnew/v1.1.0.rst
text: @user1:
Thanks @author 

I don't know how important this is, but perhaps it should be
```
:class:`Timestamp`
```
?

@author:
done, thanks