Issue #2736: Added datetime.timestamp() method.
This commit is contained in:
parent
ed36b2e55b
commit
a4415141da
|
@ -752,17 +752,6 @@ Other constructors, all class methods:
|
||||||
|
|
||||||
datetime(1970, 1, 1) + timedelta(seconds=timestamp)
|
datetime(1970, 1, 1) + timedelta(seconds=timestamp)
|
||||||
|
|
||||||
There is no method to obtain the timestamp from a :class:`datetime`
|
|
||||||
instance, but POSIX timestamp corresponding to a :class:`datetime`
|
|
||||||
instance ``dt`` can be easily calculated as follows. For a naive
|
|
||||||
``dt``::
|
|
||||||
|
|
||||||
timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
|
|
||||||
|
|
||||||
And for an aware ``dt``::
|
|
||||||
|
|
||||||
timestamp = (dt - datetime(1970, 1, 1, tzinfo=timezone.utc)) / timedelta(seconds=1)
|
|
||||||
|
|
||||||
.. versionchanged:: 3.3
|
.. versionchanged:: 3.3
|
||||||
Raise :exc:`OverflowError` instead of :exc:`ValueError` if the timestamp
|
Raise :exc:`OverflowError` instead of :exc:`ValueError` if the timestamp
|
||||||
is out of the range of values supported by the platform C
|
is out of the range of values supported by the platform C
|
||||||
|
@ -1054,6 +1043,39 @@ Instance methods:
|
||||||
Return the proleptic Gregorian ordinal of the date. The same as
|
Return the proleptic Gregorian ordinal of the date. The same as
|
||||||
``self.date().toordinal()``.
|
``self.date().toordinal()``.
|
||||||
|
|
||||||
|
.. method:: datetime.timestamp()
|
||||||
|
|
||||||
|
Return POSIX timestamp corresponding to the :class:`datetime`
|
||||||
|
instance. The return value is a :class:`float` similar to that
|
||||||
|
returned by :func:`time.time`.
|
||||||
|
|
||||||
|
Naive :class:`datetime` instances are assumed to represent local
|
||||||
|
time and this method relies on the platform C :c:func:`mktime`
|
||||||
|
function to perform the conversion. Since :class:`datetime`
|
||||||
|
supports wider range of values than :c:func:`mktime` on many
|
||||||
|
platforms, this method may raise :exc:`OverflowError` for times far
|
||||||
|
in the past or far in the future.
|
||||||
|
|
||||||
|
For aware :class:`datetime` instances, the return value is computed
|
||||||
|
as::
|
||||||
|
|
||||||
|
(dt - datetime(1970, 1, 1, tzinfo=timezone.utc)).total_seconds()
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
There is no method to obtain the POSIX timestamp directly from a
|
||||||
|
naive :class:`datetime` instance representing UTC time. If your
|
||||||
|
application uses this convention and your system timezone is not
|
||||||
|
set to UTC, you can obtain the POSIX timestamp by supplying
|
||||||
|
``tzinfo=timezone.utc``::
|
||||||
|
|
||||||
|
timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
|
||||||
|
|
||||||
|
or by calculating the timestamp directly::
|
||||||
|
|
||||||
|
timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
|
||||||
|
|
||||||
.. method:: datetime.weekday()
|
.. method:: datetime.weekday()
|
||||||
|
|
||||||
|
|
|
@ -1434,6 +1434,15 @@ class datetime(date):
|
||||||
self.hour, self.minute, self.second,
|
self.hour, self.minute, self.second,
|
||||||
dst)
|
dst)
|
||||||
|
|
||||||
|
def timestamp(self):
|
||||||
|
"Return POSIX timestamp as float"
|
||||||
|
if self._tzinfo is None:
|
||||||
|
return _time.mktime((self.year, self.month, self.day,
|
||||||
|
self.hour, self.minute, self.second,
|
||||||
|
-1, -1, -1)) + self.microsecond / 1e6
|
||||||
|
else:
|
||||||
|
return (self - _EPOCH).total_seconds()
|
||||||
|
|
||||||
def utctimetuple(self):
|
def utctimetuple(self):
|
||||||
"Return UTC time tuple compatible with time.gmtime()."
|
"Return UTC time tuple compatible with time.gmtime()."
|
||||||
offset = self.utcoffset()
|
offset = self.utcoffset()
|
||||||
|
@ -1889,7 +1898,7 @@ class timezone(tzinfo):
|
||||||
timezone.utc = timezone._create(timedelta(0))
|
timezone.utc = timezone._create(timedelta(0))
|
||||||
timezone.min = timezone._create(timezone._minoffset)
|
timezone.min = timezone._create(timezone._minoffset)
|
||||||
timezone.max = timezone._create(timezone._maxoffset)
|
timezone.max = timezone._create(timezone._maxoffset)
|
||||||
|
_EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
|
||||||
"""
|
"""
|
||||||
Some time zone algebra. For a datetime x, let
|
Some time zone algebra. For a datetime x, let
|
||||||
x.n = x stripped of its timezone -- its naive time.
|
x.n = x stripped of its timezone -- its naive time.
|
||||||
|
|
|
@ -1735,6 +1735,42 @@ class TestDateTime(TestDate):
|
||||||
got = self.theclass.utcfromtimestamp(ts)
|
got = self.theclass.utcfromtimestamp(ts)
|
||||||
self.verify_field_equality(expected, got)
|
self.verify_field_equality(expected, got)
|
||||||
|
|
||||||
|
# Run with US-style DST rules: DST begins 2 a.m. on second Sunday in
|
||||||
|
# March (M3.2.0) and ends 2 a.m. on first Sunday in November (M11.1.0).
|
||||||
|
@support.run_with_tz('EST+05EDT,M3.2.0,M11.1.0')
|
||||||
|
def test_timestamp_naive(self):
|
||||||
|
t = self.theclass(1970, 1, 1)
|
||||||
|
self.assertEqual(t.timestamp(), 18000.0)
|
||||||
|
t = self.theclass(1970, 1, 1, 1, 2, 3, 4)
|
||||||
|
self.assertEqual(t.timestamp(),
|
||||||
|
18000.0 + 3600 + 2*60 + 3 + 4*1e-6)
|
||||||
|
# Missing hour defaults to standard time
|
||||||
|
t = self.theclass(2012, 3, 11, 2, 30)
|
||||||
|
self.assertEqual(self.theclass.fromtimestamp(t.timestamp()),
|
||||||
|
t + timedelta(hours=1))
|
||||||
|
# Ambiguous hour defaults to DST
|
||||||
|
t = self.theclass(2012, 11, 4, 1, 30)
|
||||||
|
self.assertEqual(self.theclass.fromtimestamp(t.timestamp()), t)
|
||||||
|
|
||||||
|
# Timestamp may raise an overflow error on some platforms
|
||||||
|
for t in [self.theclass(1,1,1), self.theclass(9999,12,12)]:
|
||||||
|
try:
|
||||||
|
s = t.timestamp()
|
||||||
|
except OverflowError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.assertEqual(self.theclass.fromtimestamp(s), t)
|
||||||
|
|
||||||
|
def test_timestamp_aware(self):
|
||||||
|
t = self.theclass(1970, 1, 1, tzinfo=timezone.utc)
|
||||||
|
self.assertEqual(t.timestamp(), 0.0)
|
||||||
|
t = self.theclass(1970, 1, 1, 1, 2, 3, 4, tzinfo=timezone.utc)
|
||||||
|
self.assertEqual(t.timestamp(),
|
||||||
|
3600 + 2*60 + 3 + 4*1e-6)
|
||||||
|
t = self.theclass(1970, 1, 1, 1, 2, 3, 4,
|
||||||
|
tzinfo=timezone(timedelta(hours=-5), 'EST'))
|
||||||
|
self.assertEqual(t.timestamp(),
|
||||||
|
18000 + 3600 + 2*60 + 3 + 4*1e-6)
|
||||||
def test_microsecond_rounding(self):
|
def test_microsecond_rounding(self):
|
||||||
for fts in [self.theclass.fromtimestamp,
|
for fts in [self.theclass.fromtimestamp,
|
||||||
self.theclass.utcfromtimestamp]:
|
self.theclass.utcfromtimestamp]:
|
||||||
|
|
|
@ -21,6 +21,8 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #2736: Added datetime.timestamp() method.
|
||||||
|
|
||||||
- Issue #13854: Make multiprocessing properly handle non-integer
|
- Issue #13854: Make multiprocessing properly handle non-integer
|
||||||
non-string argument to SystemExit.
|
non-string argument to SystemExit.
|
||||||
|
|
||||||
|
|
|
@ -766,6 +766,8 @@ typedef struct
|
||||||
|
|
||||||
/* The interned UTC timezone instance */
|
/* The interned UTC timezone instance */
|
||||||
static PyObject *PyDateTime_TimeZone_UTC;
|
static PyObject *PyDateTime_TimeZone_UTC;
|
||||||
|
/* The interned Epoch datetime instance */
|
||||||
|
static PyObject *PyDateTime_Epoch;
|
||||||
|
|
||||||
/* Create new timezone instance checking offset range. This
|
/* Create new timezone instance checking offset range. This
|
||||||
function does not check the name argument. Caller must assure
|
function does not check the name argument. Caller must assure
|
||||||
|
@ -4747,6 +4749,44 @@ datetime_timetuple(PyDateTime_DateTime *self)
|
||||||
dstflag);
|
dstflag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
datetime_timestamp(PyDateTime_DateTime *self)
|
||||||
|
{
|
||||||
|
PyObject *result;
|
||||||
|
|
||||||
|
if (HASTZINFO(self) && self->tzinfo != Py_None) {
|
||||||
|
PyObject *delta;
|
||||||
|
delta = datetime_subtract((PyObject *)self, PyDateTime_Epoch);
|
||||||
|
if (delta == NULL)
|
||||||
|
return NULL;
|
||||||
|
result = delta_total_seconds(delta);
|
||||||
|
Py_DECREF(delta);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
struct tm time;
|
||||||
|
time_t timestamp;
|
||||||
|
memset((void *) &time, '\0', sizeof(struct tm));
|
||||||
|
time.tm_year = GET_YEAR(self) - 1900;
|
||||||
|
time.tm_mon = GET_MONTH(self) - 1;
|
||||||
|
time.tm_mday = GET_DAY(self);
|
||||||
|
time.tm_hour = DATE_GET_HOUR(self);
|
||||||
|
time.tm_min = DATE_GET_MINUTE(self);
|
||||||
|
time.tm_sec = DATE_GET_SECOND(self);
|
||||||
|
time.tm_wday = -1;
|
||||||
|
time.tm_isdst = -1;
|
||||||
|
timestamp = mktime(&time);
|
||||||
|
/* Return value of -1 does not necessarily mean an error, but tm_wday
|
||||||
|
* cannot remain set to -1 if mktime succeeded. */
|
||||||
|
if (timestamp == (time_t)(-1) && time.tm_wday == -1) {
|
||||||
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
|
"timestamp out of range");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
result = PyFloat_FromDouble(timestamp + DATE_GET_MICROSECOND(self) / 1e6);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
datetime_getdate(PyDateTime_DateTime *self)
|
datetime_getdate(PyDateTime_DateTime *self)
|
||||||
{
|
{
|
||||||
|
@ -4894,6 +4934,9 @@ static PyMethodDef datetime_methods[] = {
|
||||||
{"timetuple", (PyCFunction)datetime_timetuple, METH_NOARGS,
|
{"timetuple", (PyCFunction)datetime_timetuple, METH_NOARGS,
|
||||||
PyDoc_STR("Return time tuple, compatible with time.localtime().")},
|
PyDoc_STR("Return time tuple, compatible with time.localtime().")},
|
||||||
|
|
||||||
|
{"timestamp", (PyCFunction)datetime_timestamp, METH_NOARGS,
|
||||||
|
PyDoc_STR("Return POSIX timestamp as float.")},
|
||||||
|
|
||||||
{"utctimetuple", (PyCFunction)datetime_utctimetuple, METH_NOARGS,
|
{"utctimetuple", (PyCFunction)datetime_utctimetuple, METH_NOARGS,
|
||||||
PyDoc_STR("Return UTC time tuple, compatible with time.localtime().")},
|
PyDoc_STR("Return UTC time tuple, compatible with time.localtime().")},
|
||||||
|
|
||||||
|
@ -5151,6 +5194,12 @@ PyInit__datetime(void)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_DECREF(x);
|
Py_DECREF(x);
|
||||||
|
|
||||||
|
/* Epoch */
|
||||||
|
PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0,
|
||||||
|
PyDateTime_TimeZone_UTC);
|
||||||
|
if (PyDateTime_Epoch == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* module initialization */
|
/* module initialization */
|
||||||
PyModule_AddIntConstant(m, "MINYEAR", MINYEAR);
|
PyModule_AddIntConstant(m, "MINYEAR", MINYEAR);
|
||||||
PyModule_AddIntConstant(m, "MAXYEAR", MAXYEAR);
|
PyModule_AddIntConstant(m, "MAXYEAR", MAXYEAR);
|
||||||
|
|
Loading…
Reference in New Issue