Skip to content

Commit 0d6884b

Browse files
API/COMPAT: add pydatetime-style positional args to Timestamp constructor
1 parent 82f54bd commit 0d6884b

File tree

4 files changed

+67
-1
lines changed

4 files changed

+67
-1
lines changed

doc/source/timeseries.rst

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ time.
9898
9999
pd.Timestamp(datetime(2012, 5, 1))
100100
pd.Timestamp('2012-05-01')
101+
pd.Timestamp(2012, 5, 1)
101102
102103
However, in many cases it is more natural to associate things like change
103104
variables with a time span instead. The span represented by ``Period`` can be

doc/source/whatsnew/v0.18.2.txt

+8
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ Other enhancements
3838
idx = pd.Index(["a1a2", "b1", "c1"])
3939
idx.str.extractall("[ab](?P<digit>\d)")
4040

41+
- ``Timestamp``s can now accept positional parameters like :func:`datetime.datetime`:
42+
43+
.. ipython:: python
44+
45+
Timestamp(2012, 1, 1)
46+
47+
Timestamp(2012, 1, 1, 8, 30)
48+
4149
.. _whatsnew_0182.api:
4250

4351
API changes

pandas/tseries/tests/test_tslib.py

+30
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,36 @@ def test_constructor_invalid(self):
180180
with tm.assertRaisesRegexp(ValueError, 'Cannot convert Period'):
181181
Timestamp(Period('1000-01-01'))
182182

183+
def test_constructor_positional(self):
184+
# GH 10758
185+
with tm.assertRaises(TypeError):
186+
Timestamp(2000, 1)
187+
with tm.assertRaises(ValueError):
188+
Timestamp(2000, 0, 1)
189+
with tm.assertRaises(ValueError):
190+
Timestamp(2000, 13, 1)
191+
with tm.assertRaises(ValueError):
192+
Timestamp(2000, 1, 0)
193+
with tm.assertRaises(ValueError):
194+
Timestamp(2000, 1, 32)
195+
with tm.assertRaises(TypeError):
196+
Timestamp(2000, 1, 1, None)
197+
with tm.assertRaises(TypeError):
198+
Timestamp(2000, 1, 1, None, None)
199+
with tm.assertRaises(TypeError):
200+
Timestamp(2000, 1, 1, None, None, None)
201+
202+
ts = Timestamp(2000, 1, 2)
203+
204+
actual = ts.to_pydatetime()
205+
expected = datetime.datetime(2000, 1, 2)
206+
self.assertEqual(actual, expected)
207+
self.assertEqual(type(actual), type(expected))
208+
209+
pos_args = [2000, 1, 2, 3, 4, 5, 999999]
210+
self.assertEqual(Timestamp(*pos_args).to_pydatetime(),
211+
datetime.datetime(*pos_args))
212+
183213
def test_conversion(self):
184214
# GH 9255
185215
ts = Timestamp('2000-01-01')

pandas/tslib.pyx

+28-1
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ cdef inline bint _is_fixed_offset(object tz):
216216

217217

218218
_zero_time = datetime_time(0, 0)
219+
_no_unit = object()
219220

220221
# Python front end to C extension type _Timestamp
221222
# This serves as the box for datetime64
@@ -288,10 +289,36 @@ class Timestamp(_Timestamp):
288289
def combine(cls, date, time):
289290
return cls(datetime.combine(date, time))
290291

291-
def __new__(cls, object ts_input, object offset=None, tz=None, unit=None):
292+
def __new__(cls,
293+
object ts_input, object offset=None, tz=None, unit=_no_unit,
294+
minute=0, second=0, microsecond=0, tzinfo=None):
295+
# The parameter list folds together legacy parameter names (the first
296+
# four) and positional parameter names from pydatetime (starting with
297+
# `minute`).
298+
#
299+
# When using the pydatetime form, the first three parameters are
300+
# required, but the fourth (called `unit` but standing in for `hour`)
301+
# is optional. However, when using the legacy form, only the first
302+
# parameter is required and the fourth parameter defaults to `None`.
303+
# We use a special non-`None` constant to distinguish when callers
304+
# pass `None` as the fourth pydatetime parameter.
305+
292306
cdef _TSObject ts
293307
cdef _Timestamp ts_base
294308

309+
if offset is not None and is_integer_object(offset):
310+
# User passed positional arguments:
311+
# Timestamp(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])
312+
# When using the positional form, the first three parameters are
313+
# required. Assign defaults to the rest.
314+
if unit is _no_unit:
315+
unit = 0
316+
# Forward positional arguments to datetime constructor.
317+
return Timestamp(datetime(ts_input, offset, tz, unit, minute, second, microsecond, tzinfo),
318+
tz=tzinfo)
319+
elif unit is _no_unit:
320+
unit = None
321+
295322
ts = convert_to_tsobject(ts_input, tz, unit, 0, 0)
296323

297324
if ts.value == NPY_NAT:

0 commit comments

Comments
 (0)