PEP 410
This commit is contained in:
parent
6f91ce74a0
commit
ccd5715a14
|
@ -808,13 +808,16 @@ as internal buffering of data.
|
|||
Availability: Unix.
|
||||
|
||||
|
||||
.. function:: fstat(fd)
|
||||
.. function:: fstat(fd, timestamp=None)
|
||||
|
||||
Return status for file descriptor *fd*, like :func:`~os.stat`.
|
||||
|
||||
Availability: Unix, Windows.
|
||||
|
||||
.. function:: fstatat(dirfd, path, flags=0)
|
||||
.. versionchanged:: 3.3
|
||||
Added the *timestamp* argument.
|
||||
|
||||
.. function:: fstatat(dirfd, path, flags=0, timestamp="float")
|
||||
|
||||
Like :func:`stat` but if *path* is relative, it is taken as relative to *dirfd*.
|
||||
*flags* is optional and may be 0 or :data:`AT_SYMLINK_NOFOLLOW`.
|
||||
|
@ -1696,7 +1699,7 @@ Files and Directories
|
|||
.. versionadded:: 3.3
|
||||
|
||||
|
||||
.. function:: lstat(path)
|
||||
.. function:: lstat(path, timestamp=None)
|
||||
|
||||
Perform the equivalent of an :c:func:`lstat` system call on the given path.
|
||||
Similar to :func:`~os.stat`, but does not follow symbolic links. On
|
||||
|
@ -1706,6 +1709,9 @@ Files and Directories
|
|||
.. versionchanged:: 3.2
|
||||
Added support for Windows 6.0 (Vista) symbolic links.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
The *timestamp* argument was added.
|
||||
|
||||
|
||||
.. function:: lutimes(path[, times])
|
||||
|
||||
|
@ -1969,7 +1975,7 @@ Files and Directories
|
|||
.. versionadded:: 3.3
|
||||
|
||||
|
||||
.. function:: stat(path)
|
||||
.. function:: stat(path, timestamp=None)
|
||||
|
||||
Perform the equivalent of a :c:func:`stat` system call on the given path.
|
||||
(This function follows symlinks; to stat a symlink use :func:`lstat`.)
|
||||
|
@ -1989,6 +1995,11 @@ Files and Directories
|
|||
* :attr:`st_ctime` - platform dependent; time of most recent metadata change on
|
||||
Unix, or the time of creation on Windows)
|
||||
|
||||
:attr:`st_atime`, :attr:`st_mtime` and :attr:`st_ctime` are :class:`float`
|
||||
by default, or :class:`int` if :func:`os.stat_float_times` is ``False``. Set
|
||||
the *timestamp* argument to get another :ref:`timestamp type
|
||||
<timestamp-types>`.
|
||||
|
||||
On some Unix systems (such as Linux), the following attributes may also be
|
||||
available:
|
||||
|
||||
|
@ -2044,6 +2055,9 @@ Files and Directories
|
|||
|
||||
Availability: Unix, Windows.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
Added the *timestamp* argument.
|
||||
|
||||
|
||||
.. function:: stat_float_times([newvalue])
|
||||
|
||||
|
@ -2069,6 +2083,9 @@ Files and Directories
|
|||
are processed, this application should turn the feature off until the library
|
||||
has been corrected.
|
||||
|
||||
.. deprecated:: 3.3
|
||||
Use *timestamp* argument of stat functions instead.
|
||||
|
||||
|
||||
.. function:: statvfs(path)
|
||||
|
||||
|
@ -2859,27 +2876,39 @@ written in Python, such as a mail server's external command delivery program.
|
|||
with :const:`P_NOWAIT` return suitable process handles.
|
||||
|
||||
|
||||
.. function:: wait3([options])
|
||||
.. function:: wait3(options[, timestamp=float])
|
||||
|
||||
Similar to :func:`waitpid`, except no process id argument is given and a
|
||||
3-element tuple containing the child's process id, exit status indication, and
|
||||
resource usage information is returned. Refer to :mod:`resource`.\
|
||||
:func:`getrusage` for details on resource usage information. The option
|
||||
argument is the same as that provided to :func:`waitpid` and :func:`wait4`.
|
||||
:attr:`ru_utime` and :attr:`ru_stime` attributes of the resource usage are
|
||||
:class:`float` by default, set the *timestamp* argument to get another
|
||||
:ref:`timestamp type <timestamp-types>`.
|
||||
|
||||
Availability: Unix.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
Added the *timestamp* argument.
|
||||
|
||||
.. function:: wait4(pid, options)
|
||||
|
||||
.. function:: wait4(pid, options[, timestamp=float])
|
||||
|
||||
Similar to :func:`waitpid`, except a 3-element tuple, containing the child's
|
||||
process id, exit status indication, and resource usage information is returned.
|
||||
Refer to :mod:`resource`.\ :func:`getrusage` for details on resource usage
|
||||
information. The arguments to :func:`wait4` are the same as those provided to
|
||||
:func:`waitpid`.
|
||||
:attr:`ru_utime` and :attr:`ru_stime` attributes of the resource usage are
|
||||
:class:`float` by default, set the *timestamp* argument to get another
|
||||
:ref:`timestamp type <timestamp-types>`.
|
||||
|
||||
Availability: Unix.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
Added the *timestamp* argument.
|
||||
|
||||
|
||||
.. data:: WNOHANG
|
||||
|
||||
|
|
|
@ -95,6 +95,14 @@ An explanation of some terminology and conventions is in order.
|
|||
| local time | | |
|
||||
+-------------------------+-------------------------+-------------------------+
|
||||
|
||||
.. _timestamp-types:
|
||||
|
||||
* Python supports the following timestamp types:
|
||||
|
||||
* :class:`int`
|
||||
* :class:`float`
|
||||
* :class:`decimal.Decimal`
|
||||
|
||||
|
||||
The module defines the following functions and data items:
|
||||
|
||||
|
@ -119,7 +127,7 @@ The module defines the following functions and data items:
|
|||
trailing newline.
|
||||
|
||||
|
||||
.. function:: clock()
|
||||
.. function:: clock(timestamp=float)
|
||||
|
||||
.. index::
|
||||
single: CPU time
|
||||
|
@ -136,16 +144,27 @@ The module defines the following functions and data items:
|
|||
:c:func:`QueryPerformanceCounter`. The resolution is typically better than one
|
||||
microsecond.
|
||||
|
||||
Return as a floating point number by default, set the *timestamp* argument
|
||||
to get another :ref:`timestamp type <timestamp-types>`.
|
||||
|
||||
.. function:: clock_getres(clk_id)
|
||||
.. versionchanged:: 3.3
|
||||
Added the *timestamp* argument.
|
||||
|
||||
|
||||
.. function:: clock_getres(clk_id, timestamp=float)
|
||||
|
||||
Return the resolution (precision) of the specified clock *clk_id*.
|
||||
Return a floating point number by default, set the *timestamp* argument to
|
||||
get another :ref:`timestamp type <timestamp-types>`.
|
||||
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. function:: clock_gettime(clk_id)
|
||||
.. function:: clock_gettime(clk_id, timestamp=float)
|
||||
|
||||
Return the time of the specified clock *clk_id*.
|
||||
Return a floating point number by default, set the *timestamp* argument to
|
||||
get another :ref:`timestamp type <timestamp-types>`.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
|
@ -214,19 +233,22 @@ The module defines the following functions and data items:
|
|||
flag is set to ``1`` when DST applies to the given time.
|
||||
|
||||
|
||||
.. function:: mktime(t)
|
||||
.. function:: mktime(t, timestamp=float)
|
||||
|
||||
This is the inverse function of :func:`localtime`. Its argument is the
|
||||
:class:`struct_time` or full 9-tuple (since the dst flag is needed; use ``-1``
|
||||
as the dst flag if it is unknown) which expresses the time in *local* time, not
|
||||
UTC. It returns a floating point number, for compatibility with :func:`time`.
|
||||
It returns a floating point number by default, for compatibility with
|
||||
:func:`time`, set the *timestamp* argument to get another :ref:`timestamp
|
||||
type <timestamp-types>`.
|
||||
|
||||
If the input value cannot be represented as a valid time, either
|
||||
:exc:`OverflowError` or :exc:`ValueError` will be raised (which depends on
|
||||
whether the invalid value is caught by Python or the underlying C libraries).
|
||||
The earliest date for which it can generate a time is platform-dependent.
|
||||
|
||||
|
||||
.. function:: monotonic()
|
||||
.. function:: monotonic(timestamp=float)
|
||||
|
||||
Monotonic clock. The reference point of the returned value is undefined so
|
||||
only the difference of consecutive calls is valid.
|
||||
|
@ -440,15 +462,20 @@ The module defines the following functions and data items:
|
|||
:exc:`TypeError` is raised.
|
||||
|
||||
|
||||
.. function:: time()
|
||||
.. function:: time(timestamp=float)
|
||||
|
||||
Return the time as a floating point number expressed in seconds since the epoch,
|
||||
in UTC. Note that even though the time is always returned as a floating point
|
||||
Return the time expressed in seconds since the epoch in UTC. Return a
|
||||
floating point number by default, set the *timestamp* argument to get
|
||||
another :ref:`timestamp type <timestamp-types>`.
|
||||
Note that even though the time is always returned as a floating point
|
||||
number, not all systems provide time with a better precision than 1 second.
|
||||
While this function normally returns non-decreasing values, it can return a
|
||||
lower value than a previous call if the system clock has been set back between
|
||||
the two calls.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
Added the *timestamp* argument.
|
||||
|
||||
|
||||
.. data:: timezone
|
||||
|
||||
|
@ -546,13 +573,16 @@ The module defines the following functions and data items:
|
|||
('EET', 'EEST')
|
||||
|
||||
|
||||
.. function:: wallclock()
|
||||
.. function:: wallclock(timestamp=float)
|
||||
|
||||
.. index::
|
||||
single: Wallclock
|
||||
single: benchmarking
|
||||
|
||||
Return the current time in fractions of a second to the system's best ability.
|
||||
Return a floating point number by default, set the *timestamp* argument to
|
||||
get another :ref:`timestamp type <timestamp-types>`.
|
||||
|
||||
Use this when the most accurate representation of wall-clock is required, i.e.
|
||||
when "processor time" is inappropriate. The reference point of the returned
|
||||
value is undefined so only the difference of consecutive calls is valid.
|
||||
|
|
|
@ -270,6 +270,42 @@ new, more precise information::
|
|||
'<function C.D.meth at 0x7f46b9fe31e0>'
|
||||
|
||||
|
||||
PEP 410: Use decimal.Decimal type for timestamps
|
||||
================================================
|
||||
|
||||
:pep:`410` - Use decimal.Decimal type for timestamps
|
||||
PEP written and implemented by Victor Stinner.
|
||||
|
||||
The following functions have a new optional *timestamp* argument to get a
|
||||
timestamp as a :class:`decimal.Decimal` instead of :class:`int` or
|
||||
:class:`float`:
|
||||
|
||||
* :mod:`time` module: :func:`~time.clock`, :func:`~time.clock_gettime`,
|
||||
:func:`~time.clock_getres`, :func:`~time.monotonic`, :func:`~time.time` and
|
||||
:func:`~time.wallclock`
|
||||
* :mod:`os` module: :func:`~os.fstat`, :func:`~os.fstatat`, :func:`~os.lstat`
|
||||
and :func:`~os.stat` (``st_atime``, ``st_ctime`` and ``st_mtime`` fields of
|
||||
the stat structure)
|
||||
|
||||
:class:`decimal.Decimal` supports a resolution of a nanosecond (10^-9)
|
||||
resolution, whereas :class:`float` has only a resolution of a microsecond
|
||||
(10^-6) in common cases. See the list of available :ref:`timestamp types
|
||||
<timestamp-types>`.
|
||||
|
||||
Example::
|
||||
|
||||
>>> import decimal, time
|
||||
>>> time.time()
|
||||
1328006975.681211
|
||||
>>> time.time(timestamp=int)
|
||||
1328006979
|
||||
>>> time.time(timestamp=decimal.Decimal)
|
||||
Decimal('1328006983.761119')
|
||||
|
||||
:func:`os.stat_float_times` has been deprecated, use *timestamp* argument of
|
||||
`os.stat` instead.
|
||||
|
||||
|
||||
Other Language Changes
|
||||
======================
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
#ifndef Py_PYTIME_H
|
||||
#define Py_PYTIME_H
|
||||
|
||||
#include "pyconfig.h" /* include for defines */
|
||||
#include "pyport.h"
|
||||
#include "object.h"
|
||||
|
||||
/**************************************************************************
|
||||
Symbols and macros to supply platform-independent interfaces to time related
|
||||
|
@ -37,6 +38,31 @@ do { \
|
|||
((tv_end.tv_sec - tv_start.tv_sec) + \
|
||||
(tv_end.tv_usec - tv_start.tv_usec) * 0.000001)
|
||||
|
||||
#if defined(HAVE_LONG_LONG)
|
||||
typedef unsigned PY_LONG_LONG _PyTime_fraction_t;
|
||||
#else
|
||||
typedef size_t _PyTime_fraction_t;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* timestamp = seconds + numerator / denominator */
|
||||
time_t seconds;
|
||||
_PyTime_fraction_t numerator;
|
||||
/* denominator cannot be zero */
|
||||
_PyTime_fraction_t denominator;
|
||||
/* the timestamp resolution is 1/divisor */
|
||||
} _PyTime_t;
|
||||
|
||||
/* Similar to POSIX gettimeofday. If system gettimeofday
|
||||
fails or is not available, fall back to lower resolution clocks. */
|
||||
PyAPI_FUNC(void) _PyTime_get(_PyTime_t *tp);
|
||||
|
||||
/* Convert a timestamp structure to the specified timestamp type.
|
||||
|
||||
Raise a ValueError if the timestamp type is unknown. */
|
||||
PyAPI_FUNC(PyObject*) _PyTime_Convert(_PyTime_t *ts, PyObject *timestamp);
|
||||
|
||||
/* Dummy to force linking. */
|
||||
PyAPI_FUNC(void) _PyTime_Init(void);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# does add tests for a few functions which have been determined to be more
|
||||
# portable than they had been thought to be.
|
||||
|
||||
import decimal
|
||||
import os
|
||||
import errno
|
||||
import unittest
|
||||
|
@ -238,6 +239,36 @@ class StatAttributeTests(unittest.TestCase):
|
|||
warnings.simplefilter("ignore", DeprecationWarning)
|
||||
self.check_stat_attributes(fname)
|
||||
|
||||
def test_stat_timestamp(self):
|
||||
# test deprecation
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("error", DeprecationWarning)
|
||||
self.assertRaises(DeprecationWarning, os.stat_float_times, False)
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", DeprecationWarning)
|
||||
old_value = os.stat_float_times()
|
||||
try:
|
||||
# test invalid timestamp types
|
||||
self.assertRaises(ValueError, os.stat, self.fname,
|
||||
timestamp="abc")
|
||||
self.assertRaises(ValueError, os.stat, self.fname,
|
||||
timestamp=decimal.Context)
|
||||
|
||||
for float_times in (False, True):
|
||||
os.stat_float_times(float_times)
|
||||
t = os.stat(self.fname).st_mtime
|
||||
if float_times:
|
||||
self.assertIsInstance(t, float)
|
||||
else:
|
||||
self.assertIsInstance(t, int)
|
||||
|
||||
for type in (int, float, decimal.Decimal):
|
||||
t = os.stat(self.fname, timestamp=type).st_mtime
|
||||
self.assertIsInstance(t, type)
|
||||
finally:
|
||||
os.stat_float_times(old_value)
|
||||
|
||||
def test_statvfs_attributes(self):
|
||||
if not hasattr(os, "statvfs"):
|
||||
return
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import locale
|
||||
import platform
|
||||
import sys
|
||||
import sysconfig
|
||||
from test import support
|
||||
import time
|
||||
import unittest
|
||||
import locale
|
||||
import sysconfig
|
||||
import sys
|
||||
import platform
|
||||
|
||||
# Max year is only limited by the size of C int.
|
||||
SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4
|
||||
|
@ -345,6 +345,31 @@ class TimeTestCase(unittest.TestCase):
|
|||
self.assertGreater(t2, t1)
|
||||
self.assertAlmostEqual(dt, 0.1, delta=0.2)
|
||||
|
||||
def test_timestamp(self):
|
||||
import decimal
|
||||
calls = [
|
||||
(time.time,),
|
||||
(time.mktime, time.localtime()),
|
||||
]
|
||||
if hasattr(time, 'monotonic'):
|
||||
calls.append((time.monotonic,))
|
||||
if hasattr(time, 'wallclock'):
|
||||
calls.append((time.wallclock,))
|
||||
if hasattr(time, 'CLOCK_REALTIME'):
|
||||
if hasattr(time, 'clock_gettime'):
|
||||
calls.append((time.clock_gettime, time.CLOCK_REALTIME))
|
||||
if hasattr(time, 'clock_getres'):
|
||||
calls.append((time.clock_getres, time.CLOCK_REALTIME))
|
||||
for call in calls:
|
||||
func, *args = call
|
||||
|
||||
# test invalid timestamp
|
||||
for invalid in ("int", decimal.Context):
|
||||
self.assertRaises(ValueError, func, *args, timestamp=invalid)
|
||||
|
||||
for type in (int, float, decimal.Decimal):
|
||||
self.assertIsInstance(func(*args, timestamp=type), type)
|
||||
|
||||
def test_wallclock(self):
|
||||
t1 = time.wallclock()
|
||||
t2 = time.wallclock()
|
||||
|
|
|
@ -1702,6 +1702,12 @@ stat_float_times(PyObject* self, PyObject *args)
|
|||
int newval = -1;
|
||||
if (!PyArg_ParseTuple(args, "|i:stat_float_times", &newval))
|
||||
return NULL;
|
||||
if (PyErr_WarnEx(PyExc_DeprecationWarning,
|
||||
"os.stat_float_times() has been deprecated, "
|
||||
"use timestamp argument of os.stat() instead",
|
||||
1))
|
||||
return NULL;
|
||||
|
||||
if (newval == -1)
|
||||
/* Return old value */
|
||||
return PyBool_FromLong(_stat_float_times);
|
||||
|
@ -1711,9 +1717,12 @@ stat_float_times(PyObject* self, PyObject *args)
|
|||
}
|
||||
|
||||
static void
|
||||
fill_time(PyObject *v, int index, time_t sec, unsigned long nsec)
|
||||
fill_time(PyObject *v, int index, time_t sec, unsigned long nsec,
|
||||
int has_nsec, PyObject *timestamp)
|
||||
{
|
||||
PyObject *fval,*ival;
|
||||
_PyTime_t ts;
|
||||
|
||||
#if SIZEOF_TIME_T > SIZEOF_LONG
|
||||
ival = PyLong_FromLongLong((PY_LONG_LONG)sec);
|
||||
#else
|
||||
|
@ -1721,9 +1730,21 @@ fill_time(PyObject *v, int index, time_t sec, unsigned long nsec)
|
|||
#endif
|
||||
if (!ival)
|
||||
return;
|
||||
if (_stat_float_times) {
|
||||
fval = PyFloat_FromDouble(sec + 1e-9*nsec);
|
||||
} else {
|
||||
if (timestamp == NULL && _stat_float_times)
|
||||
timestamp = (PyObject*)&PyFloat_Type;
|
||||
if (timestamp != NULL) {
|
||||
ts.seconds = sec;
|
||||
if (has_nsec) {
|
||||
ts.numerator = nsec;
|
||||
ts.denominator = 1000000000;
|
||||
}
|
||||
else {
|
||||
ts.numerator = 0;
|
||||
ts.denominator = 1;
|
||||
}
|
||||
fval = _PyTime_Convert(&ts, timestamp);
|
||||
}
|
||||
else {
|
||||
fval = ival;
|
||||
Py_INCREF(fval);
|
||||
}
|
||||
|
@ -1734,9 +1755,14 @@ fill_time(PyObject *v, int index, time_t sec, unsigned long nsec)
|
|||
/* pack a system stat C structure into the Python stat tuple
|
||||
(used by posix_stat() and posix_fstat()) */
|
||||
static PyObject*
|
||||
_pystat_fromstructstat(STRUCT_STAT *st)
|
||||
_pystat_fromstructstat(STRUCT_STAT *st, PyObject *timestamp)
|
||||
{
|
||||
unsigned long ansec, mnsec, cnsec;
|
||||
int has_nsec;
|
||||
#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
|
||||
_PyTime_t ts;
|
||||
#endif
|
||||
|
||||
PyObject *v = PyStructSequence_New(&StatResultType);
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
|
@ -1768,20 +1794,24 @@ _pystat_fromstructstat(STRUCT_STAT *st)
|
|||
ansec = st->st_atim.tv_nsec;
|
||||
mnsec = st->st_mtim.tv_nsec;
|
||||
cnsec = st->st_ctim.tv_nsec;
|
||||
has_nsec = 1;
|
||||
#elif defined(HAVE_STAT_TV_NSEC2)
|
||||
ansec = st->st_atimespec.tv_nsec;
|
||||
mnsec = st->st_mtimespec.tv_nsec;
|
||||
cnsec = st->st_ctimespec.tv_nsec;
|
||||
has_nsec = 1;
|
||||
#elif defined(HAVE_STAT_NSEC)
|
||||
ansec = st->st_atime_nsec;
|
||||
mnsec = st->st_mtime_nsec;
|
||||
cnsec = st->st_ctime_nsec;
|
||||
has_nsec = 1;
|
||||
#else
|
||||
ansec = mnsec = cnsec = 0;
|
||||
has_nsec = 0;
|
||||
#endif
|
||||
fill_time(v, 7, st->st_atime, ansec);
|
||||
fill_time(v, 8, st->st_mtime, mnsec);
|
||||
fill_time(v, 9, st->st_ctime, cnsec);
|
||||
fill_time(v, 7, st->st_atime, ansec, has_nsec, timestamp);
|
||||
fill_time(v, 8, st->st_mtime, mnsec, has_nsec, timestamp);
|
||||
fill_time(v, 9, st->st_ctime, cnsec, has_nsec, timestamp);
|
||||
|
||||
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
|
||||
PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX,
|
||||
|
@ -1802,17 +1832,22 @@ _pystat_fromstructstat(STRUCT_STAT *st)
|
|||
#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
|
||||
{
|
||||
PyObject *val;
|
||||
unsigned long bsec,bnsec;
|
||||
bsec = (long)st->st_birthtime;
|
||||
ts.seconds = (long)st->st_birthtime;
|
||||
#ifdef HAVE_STAT_TV_NSEC2
|
||||
bnsec = st->st_birthtimespec.tv_nsec;
|
||||
ts.numerator = st->st_birthtimespec.tv_nsec;
|
||||
ts.denominator = 1000000000;
|
||||
#else
|
||||
bnsec = 0;
|
||||
ts.numerator = 0;
|
||||
ts.denominator = 1;
|
||||
#endif
|
||||
if (_stat_float_times) {
|
||||
val = PyFloat_FromDouble(bsec + 1e-9*bnsec);
|
||||
} else {
|
||||
val = PyLong_FromLong((long)bsec);
|
||||
if (timestamp == NULL) {
|
||||
if (_stat_float_times)
|
||||
val = _PyTime_Convert(&ts, (PyObject*)&PyFloat_Type);
|
||||
else
|
||||
val = _PyTime_Convert(&ts, (PyObject*)&PyLong_Type);
|
||||
}
|
||||
else {
|
||||
val = _PyTime_Convert(&ts, timestamp);
|
||||
}
|
||||
PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,
|
||||
val);
|
||||
|
@ -1832,7 +1867,7 @@ _pystat_fromstructstat(STRUCT_STAT *st)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
posix_do_stat(PyObject *self, PyObject *args,
|
||||
posix_do_stat(PyObject *self, PyObject *args, PyObject *kw,
|
||||
char *format,
|
||||
#ifdef __VMS
|
||||
int (*statfunc)(const char *, STRUCT_STAT *, ...),
|
||||
|
@ -1842,15 +1877,18 @@ posix_do_stat(PyObject *self, PyObject *args,
|
|||
char *wformat,
|
||||
int (*wstatfunc)(const wchar_t *, STRUCT_STAT *))
|
||||
{
|
||||
static char *kwlist[] = {"path", "timestamp", NULL};
|
||||
STRUCT_STAT st;
|
||||
PyObject *opath;
|
||||
char *path;
|
||||
int res;
|
||||
PyObject *result;
|
||||
PyObject *timestamp = NULL;
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
PyObject *po;
|
||||
if (PyArg_ParseTuple(args, wformat, &po)) {
|
||||
if (PyArg_ParseTupleAndKeywords(args, kw, wformat, kwlist,
|
||||
&po, ×tamp)) {
|
||||
wchar_t *wpath = PyUnicode_AsUnicode(po);
|
||||
if (wpath == NULL)
|
||||
return NULL;
|
||||
|
@ -1861,15 +1899,17 @@ posix_do_stat(PyObject *self, PyObject *args,
|
|||
|
||||
if (res != 0)
|
||||
return win32_error_object("stat", po);
|
||||
return _pystat_fromstructstat(&st);
|
||||
return _pystat_fromstructstat(&st, timestamp);
|
||||
}
|
||||
/* Drop the argument parsing error as narrow strings
|
||||
are also valid. */
|
||||
PyErr_Clear();
|
||||
timestamp = NULL;
|
||||
#endif
|
||||
|
||||
if (!PyArg_ParseTuple(args, format,
|
||||
PyUnicode_FSConverter, &opath))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, format, kwlist,
|
||||
PyUnicode_FSConverter, &opath,
|
||||
×tamp))
|
||||
return NULL;
|
||||
#ifdef MS_WINDOWS
|
||||
if (win32_warn_bytes_api()) {
|
||||
|
@ -1890,7 +1930,7 @@ posix_do_stat(PyObject *self, PyObject *args,
|
|||
#endif
|
||||
}
|
||||
else
|
||||
result = _pystat_fromstructstat(&st);
|
||||
result = _pystat_fromstructstat(&st, timestamp);
|
||||
|
||||
Py_DECREF(opath);
|
||||
return result;
|
||||
|
@ -3381,16 +3421,16 @@ posix_rmdir(PyObject *self, PyObject *args)
|
|||
|
||||
|
||||
PyDoc_STRVAR(posix_stat__doc__,
|
||||
"stat(path) -> stat result\n\n\
|
||||
"stat(path, timestamp=None) -> stat result\n\n\
|
||||
Perform a stat system call on the given path.");
|
||||
|
||||
static PyObject *
|
||||
posix_stat(PyObject *self, PyObject *args)
|
||||
posix_stat(PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
#ifdef MS_WINDOWS
|
||||
return posix_do_stat(self, args, "O&:stat", STAT, "U:stat", win32_stat_w);
|
||||
return posix_do_stat(self, args, kw, "O&|O:stat", STAT, "U|O:stat", win32_stat_w);
|
||||
#else
|
||||
return posix_do_stat(self, args, "O&:stat", STAT, NULL, NULL);
|
||||
return posix_do_stat(self, args, kw, "O&|O:stat", STAT, NULL, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -6118,11 +6158,12 @@ posix_setgroups(PyObject *self, PyObject *groups)
|
|||
|
||||
#if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
|
||||
static PyObject *
|
||||
wait_helper(pid_t pid, int status, struct rusage *ru)
|
||||
wait_helper(pid_t pid, int status, struct rusage *ru, PyObject *timestamp)
|
||||
{
|
||||
PyObject *result;
|
||||
static PyObject *struct_rusage;
|
||||
_Py_IDENTIFIER(struct_rusage);
|
||||
_PyTime_t ts;
|
||||
|
||||
if (pid == -1)
|
||||
return posix_error();
|
||||
|
@ -6146,10 +6187,17 @@ wait_helper(pid_t pid, int status, struct rusage *ru)
|
|||
#define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)
|
||||
#endif
|
||||
|
||||
ts.seconds = ru->ru_utime.tv_sec;
|
||||
ts.numerator = ru->ru_utime.tv_usec;
|
||||
ts.denominator = 1000000;
|
||||
PyStructSequence_SET_ITEM(result, 0,
|
||||
PyFloat_FromDouble(doubletime(ru->ru_utime)));
|
||||
_PyTime_Convert(&ts, timestamp));
|
||||
|
||||
ts.seconds = ru->ru_stime.tv_sec;
|
||||
ts.numerator = ru->ru_stime.tv_usec;
|
||||
ts.denominator = 1000000;
|
||||
PyStructSequence_SET_ITEM(result, 1,
|
||||
PyFloat_FromDouble(doubletime(ru->ru_stime)));
|
||||
_PyTime_Convert(&ts, timestamp));
|
||||
#define SET_INT(result, index, value)\
|
||||
PyStructSequence_SET_ITEM(result, index, PyLong_FromLong(value))
|
||||
SET_INT(result, 2, ru->ru_maxrss);
|
||||
|
@ -6179,51 +6227,55 @@ wait_helper(pid_t pid, int status, struct rusage *ru)
|
|||
|
||||
#ifdef HAVE_WAIT3
|
||||
PyDoc_STRVAR(posix_wait3__doc__,
|
||||
"wait3(options) -> (pid, status, rusage)\n\n\
|
||||
"wait3(options[, timestamp=float]) -> (pid, status, rusage)\n\n\
|
||||
Wait for completion of a child process.");
|
||||
|
||||
static PyObject *
|
||||
posix_wait3(PyObject *self, PyObject *args)
|
||||
posix_wait3(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static char *kwlist[] = {"options", "timestamp", NULL};
|
||||
pid_t pid;
|
||||
int options;
|
||||
struct rusage ru;
|
||||
WAIT_TYPE status;
|
||||
WAIT_STATUS_INT(status) = 0;
|
||||
PyObject *timestamp = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:wait3", &options))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|O:wait3", kwlist, &options, ×tamp))
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
pid = wait3(&status, options, &ru);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
return wait_helper(pid, WAIT_STATUS_INT(status), &ru);
|
||||
return wait_helper(pid, WAIT_STATUS_INT(status), &ru, timestamp);
|
||||
}
|
||||
#endif /* HAVE_WAIT3 */
|
||||
|
||||
#ifdef HAVE_WAIT4
|
||||
PyDoc_STRVAR(posix_wait4__doc__,
|
||||
"wait4(pid, options) -> (pid, status, rusage)\n\n\
|
||||
"wait4(pid, options[, timestamp=float]) -> (pid, status, rusage)\n\n\
|
||||
Wait for completion of a given child process.");
|
||||
|
||||
static PyObject *
|
||||
posix_wait4(PyObject *self, PyObject *args)
|
||||
posix_wait4(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static char *kwlist[] = {"pid", "options", "timestamp", NULL};
|
||||
pid_t pid;
|
||||
int options;
|
||||
struct rusage ru;
|
||||
WAIT_TYPE status;
|
||||
WAIT_STATUS_INT(status) = 0;
|
||||
PyObject *timestamp = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:wait4", &pid, &options))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, _Py_PARSE_PID "i|O:wait4", kwlist, &pid, &options, ×tamp))
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
pid = wait4(pid, &status, options, &ru);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
return wait_helper(pid, WAIT_STATUS_INT(status), &ru);
|
||||
return wait_helper(pid, WAIT_STATUS_INT(status), &ru, timestamp);
|
||||
}
|
||||
#endif /* HAVE_WAIT4 */
|
||||
|
||||
|
@ -6350,20 +6402,20 @@ posix_wait(PyObject *self, PyObject *noargs)
|
|||
|
||||
|
||||
PyDoc_STRVAR(posix_lstat__doc__,
|
||||
"lstat(path) -> stat result\n\n\
|
||||
"lstat(path, timestamp=None) -> stat result\n\n\
|
||||
Like stat(path), but do not follow symbolic links.");
|
||||
|
||||
static PyObject *
|
||||
posix_lstat(PyObject *self, PyObject *args)
|
||||
posix_lstat(PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
#ifdef HAVE_LSTAT
|
||||
return posix_do_stat(self, args, "O&:lstat", lstat, NULL, NULL);
|
||||
return posix_do_stat(self, args, kw, "O&|O:lstat", lstat, NULL, NULL);
|
||||
#else /* !HAVE_LSTAT */
|
||||
#ifdef MS_WINDOWS
|
||||
return posix_do_stat(self, args, "O&:lstat", win32_lstat, "U:lstat",
|
||||
return posix_do_stat(self, args, kw, "O&|O:lstat", win32_lstat, "U|O:lstat",
|
||||
win32_lstat_w);
|
||||
#else
|
||||
return posix_do_stat(self, args, "O&:lstat", STAT, NULL, NULL);
|
||||
return posix_do_stat(self, args, "kw, O&|O:lstat", STAT, NULL, NULL);
|
||||
#endif
|
||||
#endif /* !HAVE_LSTAT */
|
||||
}
|
||||
|
@ -7322,16 +7374,19 @@ done:
|
|||
#endif
|
||||
|
||||
PyDoc_STRVAR(posix_fstat__doc__,
|
||||
"fstat(fd) -> stat result\n\n\
|
||||
"fstat(fd, timestamp=None) -> stat result\n\n\
|
||||
Like stat(), but for an open file descriptor.");
|
||||
|
||||
static PyObject *
|
||||
posix_fstat(PyObject *self, PyObject *args)
|
||||
posix_fstat(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static char *kwlist[] = {"fd", "timestamp", NULL};
|
||||
int fd;
|
||||
STRUCT_STAT st;
|
||||
int res;
|
||||
if (!PyArg_ParseTuple(args, "i:fstat", &fd))
|
||||
PyObject *timestamp = NULL;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|O:fstat", kwlist,
|
||||
&fd, ×tamp))
|
||||
return NULL;
|
||||
#ifdef __VMS
|
||||
/* on OpenVMS we must ensure that all bytes are written to the file */
|
||||
|
@ -7350,7 +7405,7 @@ posix_fstat(PyObject *self, PyObject *args)
|
|||
#endif
|
||||
}
|
||||
|
||||
return _pystat_fromstructstat(&st);
|
||||
return _pystat_fromstructstat(&st, timestamp);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_isatty__doc__,
|
||||
|
@ -9634,22 +9689,25 @@ posix_fchownat(PyObject *self, PyObject *args)
|
|||
|
||||
#ifdef HAVE_FSTATAT
|
||||
PyDoc_STRVAR(posix_fstatat__doc__,
|
||||
"fstatat(dirfd, path, flags=0) -> stat result\n\n\
|
||||
"fstatat(dirfd, path, flags=0, timestamp=None) -> stat result\n\n\
|
||||
Like stat() but if path is relative, it is taken as relative to dirfd.\n\
|
||||
flags is optional and may be 0 or AT_SYMLINK_NOFOLLOW.\n\
|
||||
If path is relative and dirfd is the special value AT_FDCWD, then path\n\
|
||||
is interpreted relative to the current working directory.");
|
||||
|
||||
static PyObject *
|
||||
posix_fstatat(PyObject *self, PyObject *args)
|
||||
posix_fstatat(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static char *kwlist[] = {"dirfd", "path", "flags", "timestamp", NULL};
|
||||
PyObject *opath;
|
||||
char *path;
|
||||
STRUCT_STAT st;
|
||||
int dirfd, res, flags = 0;
|
||||
PyObject *timestamp = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iO&|i:fstatat",
|
||||
&dirfd, PyUnicode_FSConverter, &opath, &flags))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO&|iO:fstatat", kwlist,
|
||||
&dirfd, PyUnicode_FSConverter, &opath,
|
||||
&flags, ×tamp))
|
||||
return NULL;
|
||||
path = PyBytes_AsString(opath);
|
||||
|
||||
|
@ -9660,7 +9718,7 @@ posix_fstatat(PyObject *self, PyObject *args)
|
|||
if (res != 0)
|
||||
return posix_error();
|
||||
|
||||
return _pystat_fromstructstat(&st);
|
||||
return _pystat_fromstructstat(&st, timestamp);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -10524,7 +10582,7 @@ static PyMethodDef posix_methods[] = {
|
|||
#ifdef HAVE_FDOPENDIR
|
||||
{"flistdir", posix_flistdir, METH_VARARGS, posix_flistdir__doc__},
|
||||
#endif
|
||||
{"lstat", posix_lstat, METH_VARARGS, posix_lstat__doc__},
|
||||
{"lstat", (PyCFunction)posix_lstat, METH_VARARGS | METH_KEYWORDS, posix_lstat__doc__},
|
||||
{"mkdir", posix_mkdir, METH_VARARGS, posix_mkdir__doc__},
|
||||
#ifdef HAVE_NICE
|
||||
{"nice", posix_nice, METH_VARARGS, posix_nice__doc__},
|
||||
|
@ -10544,7 +10602,8 @@ static PyMethodDef posix_methods[] = {
|
|||
{"rename", posix_rename, METH_VARARGS, posix_rename__doc__},
|
||||
{"replace", posix_replace, METH_VARARGS, posix_replace__doc__},
|
||||
{"rmdir", posix_rmdir, METH_VARARGS, posix_rmdir__doc__},
|
||||
{"stat", posix_stat, METH_VARARGS, posix_stat__doc__},
|
||||
{"stat", (PyCFunction)posix_stat,
|
||||
METH_VARARGS | METH_KEYWORDS, posix_stat__doc__},
|
||||
{"stat_float_times", stat_float_times, METH_VARARGS, stat_float_times__doc__},
|
||||
#if defined(HAVE_SYMLINK) && !defined(MS_WINDOWS)
|
||||
{"symlink", posix_symlink, METH_VARARGS, posix_symlink__doc__},
|
||||
|
@ -10705,10 +10764,12 @@ static PyMethodDef posix_methods[] = {
|
|||
{"wait", posix_wait, METH_NOARGS, posix_wait__doc__},
|
||||
#endif /* HAVE_WAIT */
|
||||
#ifdef HAVE_WAIT3
|
||||
{"wait3", posix_wait3, METH_VARARGS, posix_wait3__doc__},
|
||||
{"wait3", (PyCFunction)posix_wait3,
|
||||
METH_VARARGS | METH_KEYWORDS, posix_wait3__doc__},
|
||||
#endif /* HAVE_WAIT3 */
|
||||
#ifdef HAVE_WAIT4
|
||||
{"wait4", posix_wait4, METH_VARARGS, posix_wait4__doc__},
|
||||
{"wait4", (PyCFunction)posix_wait4,
|
||||
METH_VARARGS | METH_KEYWORDS, posix_wait4__doc__},
|
||||
#endif /* HAVE_WAIT4 */
|
||||
#if defined(HAVE_WAITID) && !defined(__APPLE__)
|
||||
{"waitid", posix_waitid, METH_VARARGS, posix_waitid__doc__},
|
||||
|
@ -10759,7 +10820,8 @@ static PyMethodDef posix_methods[] = {
|
|||
{"sendfile", (PyCFunction)posix_sendfile, METH_VARARGS | METH_KEYWORDS,
|
||||
posix_sendfile__doc__},
|
||||
#endif
|
||||
{"fstat", posix_fstat, METH_VARARGS, posix_fstat__doc__},
|
||||
{"fstat", (PyCFunction)posix_fstat, METH_VARARGS | METH_KEYWORDS,
|
||||
posix_fstat__doc__},
|
||||
{"isatty", posix_isatty, METH_VARARGS, posix_isatty__doc__},
|
||||
#ifdef HAVE_PIPE
|
||||
{"pipe", posix_pipe, METH_NOARGS, posix_pipe__doc__},
|
||||
|
@ -10894,7 +10956,8 @@ static PyMethodDef posix_methods[] = {
|
|||
{"fchownat", posix_fchownat, METH_VARARGS, posix_fchownat__doc__},
|
||||
#endif /* HAVE_FCHOWNAT */
|
||||
#ifdef HAVE_FSTATAT
|
||||
{"fstatat", posix_fstatat, METH_VARARGS, posix_fstatat__doc__},
|
||||
{"fstatat", (PyCFunction)posix_fstatat, METH_VARARGS | METH_KEYWORDS,
|
||||
posix_fstatat__doc__},
|
||||
#endif
|
||||
#ifdef HAVE_FUTIMESAT
|
||||
{"futimesat", posix_futimesat, METH_VARARGS, posix_futimesat__doc__},
|
||||
|
|
|
@ -40,24 +40,30 @@
|
|||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) || defined(HAVE_CLOCK)
|
||||
# define HAVE_PYCLOCK
|
||||
#endif
|
||||
|
||||
/* Forward declarations */
|
||||
static int floatsleep(double);
|
||||
static double floattime(void);
|
||||
|
||||
static PyObject *
|
||||
time_time(PyObject *self, PyObject *unused)
|
||||
time_time(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
double secs;
|
||||
secs = floattime();
|
||||
if (secs == 0.0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
static char *kwlist[] = {"timestamp", NULL};
|
||||
PyObject *timestamp = NULL;
|
||||
_PyTime_t ts;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:time", kwlist,
|
||||
×tamp))
|
||||
return NULL;
|
||||
}
|
||||
return PyFloat_FromDouble(secs);
|
||||
|
||||
_PyTime_get(&ts);
|
||||
return _PyTime_Convert(&ts, timestamp);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(time_doc,
|
||||
"time() -> floating point number\n\
|
||||
"time(timestamp=float) -> floating point number\n\
|
||||
\n\
|
||||
Return the current time in seconds since the Epoch.\n\
|
||||
Fractions of a second may be present if the system clock provides them.");
|
||||
|
@ -72,65 +78,91 @@ Fractions of a second may be present if the system clock provides them.");
|
|||
#endif
|
||||
#endif
|
||||
|
||||
static PyObject *
|
||||
pyclock(void)
|
||||
static int
|
||||
pyclock(_PyTime_t *ts)
|
||||
{
|
||||
clock_t value;
|
||||
value = clock();
|
||||
if (value == (clock_t)-1) {
|
||||
clock_t processor_time;
|
||||
processor_time = clock();
|
||||
if (processor_time == (clock_t)-1) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"the processor time used is not available "
|
||||
"or its value cannot be represented");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
return PyFloat_FromDouble((double)value / CLOCKS_PER_SEC);
|
||||
ts->seconds = 0;
|
||||
assert(sizeof(clock_t) <= sizeof(_PyTime_fraction_t));
|
||||
ts->numerator = Py_SAFE_DOWNCAST(processor_time,
|
||||
clock_t, _PyTime_fraction_t);
|
||||
ts->denominator = CLOCKS_PER_SEC;
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_CLOCK */
|
||||
|
||||
#if defined(MS_WINDOWS) && !defined(__BORLANDC__)
|
||||
/* Win32 has better clock replacement; we have our own version, due to Mark
|
||||
Hammond and Tim Peters */
|
||||
static PyObject *
|
||||
win32_clock(int fallback)
|
||||
static int
|
||||
win32_clock(_PyTime_t *ts, int fallback)
|
||||
{
|
||||
static LONGLONG cpu_frequency = 0;
|
||||
static LONGLONG ctrStart;
|
||||
static LONGLONG start;
|
||||
LARGE_INTEGER now;
|
||||
double diff;
|
||||
LONGLONG dt;
|
||||
|
||||
if (cpu_frequency == 0) {
|
||||
LARGE_INTEGER freq;
|
||||
QueryPerformanceCounter(&now);
|
||||
ctrStart = now.QuadPart;
|
||||
start = now.QuadPart;
|
||||
if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) {
|
||||
/* Unlikely to happen - this works on all intel
|
||||
machines at least! Revert to clock() */
|
||||
if (fallback)
|
||||
return pyclock();
|
||||
else
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
if (fallback) {
|
||||
return pyclock(ts);
|
||||
}
|
||||
else {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
cpu_frequency = freq.QuadPart;
|
||||
}
|
||||
QueryPerformanceCounter(&now);
|
||||
diff = (double)(now.QuadPart - ctrStart);
|
||||
return PyFloat_FromDouble(diff / (double)cpu_frequency);
|
||||
dt = now.QuadPart - start;
|
||||
|
||||
ts->seconds = 0;
|
||||
assert(sizeof(LONGLONG) <= sizeof(_PyTime_fraction_t));
|
||||
ts->numerator = Py_SAFE_DOWNCAST(dt,
|
||||
LONGLONG, _PyTime_fraction_t);
|
||||
ts->denominator = Py_SAFE_DOWNCAST(cpu_frequency,
|
||||
LONGLONG, _PyTime_fraction_t);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) || defined(HAVE_CLOCK)
|
||||
static PyObject *
|
||||
time_clock(PyObject *self, PyObject *unused)
|
||||
time_clock(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static char *kwlist[] = {"timestamp", NULL};
|
||||
_PyTime_t ts;
|
||||
PyObject *timestamp = NULL;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:clock", kwlist,
|
||||
×tamp))
|
||||
return NULL;
|
||||
|
||||
#if defined(MS_WINDOWS) && !defined(__BORLANDC__)
|
||||
return win32_clock(1);
|
||||
if (win32_clock(&ts, 1) == -1)
|
||||
return NULL;
|
||||
#else
|
||||
return pyclock();
|
||||
if (pyclock(&ts) == -1)
|
||||
return NULL;
|
||||
#endif
|
||||
return _PyTime_Convert(&ts, timestamp);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(clock_doc,
|
||||
"clock() -> floating point number\n\
|
||||
"clock(timestamp=float) -> floating point number\n\
|
||||
\n\
|
||||
Return the CPU time or real time since the start of the process or since\n\
|
||||
the first call to clock(). This has as much precision as the system\n\
|
||||
|
@ -139,13 +171,17 @@ records.");
|
|||
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
static PyObject *
|
||||
time_clock_gettime(PyObject *self, PyObject *args)
|
||||
time_clock_gettime(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static char *kwlist[] = {"clk_id", "timestamp", NULL};
|
||||
PyObject *timestamp = NULL;
|
||||
int ret;
|
||||
clockid_t clk_id;
|
||||
struct timespec tp;
|
||||
_PyTime_t ts;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|O:clock_gettime", kwlist,
|
||||
&clk_id, ×tamp))
|
||||
return NULL;
|
||||
|
||||
ret = clock_gettime((clockid_t)clk_id, &tp);
|
||||
|
@ -153,25 +189,31 @@ time_clock_gettime(PyObject *self, PyObject *args)
|
|||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
|
||||
ts.seconds = tp.tv_sec;
|
||||
ts.numerator = tp.tv_nsec;
|
||||
ts.denominator = 1000000000;
|
||||
return _PyTime_Convert(&ts, timestamp);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(clock_gettime_doc,
|
||||
"clock_gettime(clk_id) -> floating point number\n\
|
||||
"clock_gettime(clk_id, timestamp=float) -> floating point number\n\
|
||||
\n\
|
||||
Return the time of the specified clock clk_id.");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CLOCK_GETRES
|
||||
static PyObject *
|
||||
time_clock_getres(PyObject *self, PyObject *args)
|
||||
time_clock_getres(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static char *kwlist[] = {"clk_id", "timestamp", NULL};
|
||||
PyObject *timestamp = NULL;
|
||||
int ret;
|
||||
clockid_t clk_id;
|
||||
struct timespec tp;
|
||||
_PyTime_t ts;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:clock_getres", &clk_id))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|O:clock_getres", kwlist,
|
||||
&clk_id, ×tamp))
|
||||
return NULL;
|
||||
|
||||
ret = clock_getres((clockid_t)clk_id, &tp);
|
||||
|
@ -179,12 +221,14 @@ time_clock_getres(PyObject *self, PyObject *args)
|
|||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
|
||||
ts.seconds = tp.tv_sec;
|
||||
ts.numerator = tp.tv_nsec;
|
||||
ts.denominator = 1000000000;
|
||||
return _PyTime_Convert(&ts, timestamp);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(clock_getres_doc,
|
||||
"clock_getres(clk_id) -> floating point number\n\
|
||||
"clock_getres(clk_id, timestamp=float) -> floating point number\n\
|
||||
\n\
|
||||
Return the resolution (precision) of the specified clock clk_id.");
|
||||
#endif
|
||||
|
@ -707,10 +751,19 @@ not present, current time as returned by localtime() is used.");
|
|||
|
||||
#ifdef HAVE_MKTIME
|
||||
static PyObject *
|
||||
time_mktime(PyObject *self, PyObject *tup)
|
||||
time_mktime(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static char *kwlist[] = {"t", "timestamp", NULL};
|
||||
PyObject *timestamp = NULL;
|
||||
PyObject *tup;
|
||||
struct tm buf;
|
||||
time_t tt;
|
||||
_PyTime_t ts;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:mktime", kwlist,
|
||||
&tup, ×tamp))
|
||||
return NULL;
|
||||
|
||||
if (!gettmarg(tup, &buf))
|
||||
return NULL;
|
||||
buf.tm_wday = -1; /* sentinel; original value ignored */
|
||||
|
@ -722,7 +775,10 @@ time_mktime(PyObject *self, PyObject *tup)
|
|||
"mktime argument out of range");
|
||||
return NULL;
|
||||
}
|
||||
return PyFloat_FromDouble((double)tt);
|
||||
ts.seconds = tt;
|
||||
ts.numerator = 0;
|
||||
ts.denominator = 1;
|
||||
return _PyTime_Convert(&ts, timestamp);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(mktime_doc,
|
||||
|
@ -768,12 +824,14 @@ the local timezone used by methods such as localtime, but this behaviour\n\
|
|||
should not be relied on.");
|
||||
#endif /* HAVE_WORKING_TZSET */
|
||||
|
||||
static PyObject *
|
||||
time_wallclock(PyObject *self, PyObject *unused)
|
||||
static int
|
||||
pywallclock(_PyTime_t *ts)
|
||||
{
|
||||
#if defined(MS_WINDOWS) && !defined(__BORLANDC__)
|
||||
return win32_clock(1);
|
||||
#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
||||
return win32_clock(ts, 1);
|
||||
#else
|
||||
|
||||
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
||||
static int clk_index = 0;
|
||||
clockid_t clk_ids[] = {
|
||||
#ifdef CLOCK_MONOTONIC_RAW
|
||||
|
@ -793,20 +851,41 @@ time_wallclock(PyObject *self, PyObject *unused)
|
|||
clockid_t clk_id = clk_ids[clk_index];
|
||||
ret = clock_gettime(clk_id, &tp);
|
||||
if (ret == 0)
|
||||
return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
|
||||
{
|
||||
ts->seconds = tp.tv_sec;
|
||||
ts->numerator = tp.tv_nsec;
|
||||
ts->denominator = 1000000000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
clk_index++;
|
||||
if (Py_ARRAY_LENGTH(clk_ids) <= clk_index)
|
||||
clk_index = -1;
|
||||
}
|
||||
return time_time(self, NULL);
|
||||
#else
|
||||
return time_time(self, NULL);
|
||||
#endif /* defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) */
|
||||
|
||||
_PyTime_get(ts);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
time_wallclock(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static char *kwlist[] = {"timestamp", NULL};
|
||||
PyObject *timestamp = NULL;
|
||||
_PyTime_t ts;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:wallclock", kwlist,
|
||||
×tamp))
|
||||
return NULL;
|
||||
if (pywallclock(&ts))
|
||||
return NULL;
|
||||
return _PyTime_Convert(&ts, timestamp);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(wallclock_doc,
|
||||
"wallclock() -> float\n\
|
||||
"wallclock(timestamp=float)\n\
|
||||
\n\
|
||||
Return the current time in fractions of a second to the system's best\n\
|
||||
ability. Use this when the most accurate representation of wall-clock is\n\
|
||||
|
@ -821,11 +900,11 @@ calls is valid.");
|
|||
|
||||
#ifdef HAVE_PYTIME_MONOTONIC
|
||||
static PyObject *
|
||||
time_monotonic(PyObject *self, PyObject *unused)
|
||||
time_monotonic(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
#if defined(MS_WINDOWS) && !defined(__BORLANDC__)
|
||||
return win32_clock(0);
|
||||
#else
|
||||
static char *kwlist[] = {"timestamp", NULL};
|
||||
PyObject *timestamp = NULL;
|
||||
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
||||
static int clk_index = 0;
|
||||
clockid_t clk_ids[] = {
|
||||
#ifdef CLOCK_MONOTONIC_RAW
|
||||
|
@ -835,12 +914,28 @@ time_monotonic(PyObject *self, PyObject *unused)
|
|||
};
|
||||
int ret;
|
||||
struct timespec tp;
|
||||
#endif
|
||||
_PyTime_t ts;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:monotonic", kwlist,
|
||||
×tamp))
|
||||
return NULL;
|
||||
|
||||
#if defined(MS_WINDOWS) && !defined(__BORLANDC__)
|
||||
if (win32_clock(&ts, 0) == -1)
|
||||
return NULL;
|
||||
return _PyTime_Convert(&ts, timestamp);
|
||||
#else
|
||||
while (0 <= clk_index) {
|
||||
clockid_t clk_id = clk_ids[clk_index];
|
||||
ret = clock_gettime(clk_id, &tp);
|
||||
if (ret == 0)
|
||||
return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
|
||||
{
|
||||
ts.seconds = tp.tv_sec;
|
||||
ts.numerator = tp.tv_nsec;
|
||||
ts.denominator = 1000000000;
|
||||
return _PyTime_Convert(&ts, timestamp);
|
||||
}
|
||||
|
||||
clk_index++;
|
||||
if (Py_ARRAY_LENGTH(clk_ids) <= clk_index)
|
||||
|
@ -968,15 +1063,19 @@ PyInit_timezone(PyObject *m) {
|
|||
|
||||
|
||||
static PyMethodDef time_methods[] = {
|
||||
{"time", time_time, METH_NOARGS, time_doc},
|
||||
#if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) || defined(HAVE_CLOCK)
|
||||
{"clock", time_clock, METH_NOARGS, clock_doc},
|
||||
{"time", (PyCFunction)time_time,
|
||||
METH_VARARGS | METH_KEYWORDS, time_doc},
|
||||
#ifdef HAVE_PYCLOCK
|
||||
{"clock", (PyCFunction)time_clock,
|
||||
METH_VARARGS | METH_KEYWORDS, clock_doc},
|
||||
#endif
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
{"clock_gettime", time_clock_gettime, METH_VARARGS, clock_gettime_doc},
|
||||
{"clock_gettime", (PyCFunction)time_clock_gettime,
|
||||
METH_VARARGS | METH_KEYWORDS, clock_gettime_doc},
|
||||
#endif
|
||||
#ifdef HAVE_CLOCK_GETRES
|
||||
{"clock_getres", time_clock_getres, METH_VARARGS, clock_getres_doc},
|
||||
{"clock_getres", (PyCFunction)time_clock_getres,
|
||||
METH_VARARGS | METH_KEYWORDS, clock_getres_doc},
|
||||
#endif
|
||||
{"sleep", time_sleep, METH_VARARGS, sleep_doc},
|
||||
{"gmtime", time_gmtime, METH_VARARGS, gmtime_doc},
|
||||
|
@ -984,10 +1083,12 @@ static PyMethodDef time_methods[] = {
|
|||
{"asctime", time_asctime, METH_VARARGS, asctime_doc},
|
||||
{"ctime", time_ctime, METH_VARARGS, ctime_doc},
|
||||
#ifdef HAVE_MKTIME
|
||||
{"mktime", time_mktime, METH_O, mktime_doc},
|
||||
{"mktime", (PyCFunction)time_mktime,
|
||||
METH_VARARGS | METH_KEYWORDS, mktime_doc},
|
||||
#endif
|
||||
#ifdef HAVE_PYTIME_MONOTONIC
|
||||
{"monotonic", time_monotonic, METH_NOARGS, monotonic_doc},
|
||||
{"monotonic", (PyCFunction)time_monotonic,
|
||||
METH_VARARGS | METH_KEYWORDS, monotonic_doc},
|
||||
#endif
|
||||
#ifdef HAVE_STRFTIME
|
||||
{"strftime", time_strftime, METH_VARARGS, strftime_doc},
|
||||
|
@ -996,7 +1097,8 @@ static PyMethodDef time_methods[] = {
|
|||
#ifdef HAVE_WORKING_TZSET
|
||||
{"tzset", time_tzset, METH_NOARGS, tzset_doc},
|
||||
#endif
|
||||
{"wallclock", time_wallclock, METH_NOARGS, wallclock_doc},
|
||||
{"wallclock", (PyCFunction)time_wallclock,
|
||||
METH_VARARGS | METH_KEYWORDS, wallclock_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
@ -1081,15 +1183,6 @@ PyInit_time(void)
|
|||
return m;
|
||||
}
|
||||
|
||||
static double
|
||||
floattime(void)
|
||||
{
|
||||
_PyTime_timeval t;
|
||||
_PyTime_gettimeofday(&t);
|
||||
return (double)t.tv_sec + t.tv_usec*0.000001;
|
||||
}
|
||||
|
||||
|
||||
/* Implement floatsleep() for various platforms.
|
||||
When interrupted (or when another error occurs), return -1 and
|
||||
set an exception; else return 0. */
|
||||
|
|
341
Python/pytime.c
341
Python/pytime.c
|
@ -18,24 +18,36 @@
|
|||
extern int ftime(struct timeb *);
|
||||
#endif
|
||||
|
||||
#define MICROSECONDS 1000000
|
||||
|
||||
void
|
||||
_PyTime_gettimeofday(_PyTime_timeval *tp)
|
||||
_PyTime_get(_PyTime_t *ts)
|
||||
{
|
||||
#ifdef MS_WINDOWS
|
||||
FILETIME system_time;
|
||||
ULARGE_INTEGER large;
|
||||
ULONGLONG microseconds;
|
||||
ULONGLONG value;
|
||||
|
||||
GetSystemTimeAsFileTime(&system_time);
|
||||
large.u.LowPart = system_time.dwLowDateTime;
|
||||
large.u.HighPart = system_time.dwHighDateTime;
|
||||
/* 11,644,473,600,000,000: number of microseconds between
|
||||
/* 116,444,736,000,000,000: number of 100 ns between
|
||||
the 1st january 1601 and the 1st january 1970 (369 years + 89 leap
|
||||
days). */
|
||||
microseconds = large.QuadPart / 10 - 11644473600000000;
|
||||
tp->tv_sec = microseconds / 1000000;
|
||||
tp->tv_usec = microseconds % 1000000;
|
||||
value = large.QuadPart - 116444736000000000;
|
||||
ts->seconds = 0;
|
||||
ts->numerator = value;
|
||||
ts->denominator = (_PyTime_fraction_t)10000000;
|
||||
#else
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
struct timeval tv;
|
||||
int err;
|
||||
#endif
|
||||
#if defined(HAVE_FTIME)
|
||||
struct timeb t;
|
||||
#endif
|
||||
|
||||
/* There are three ways to get the time:
|
||||
(1) gettimeofday() -- resolution in microseconds
|
||||
(2) ftime() -- resolution in milliseconds
|
||||
|
@ -47,29 +59,324 @@ _PyTime_gettimeofday(_PyTime_timeval *tp)
|
|||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
#ifdef GETTIMEOFDAY_NO_TZ
|
||||
if (gettimeofday(tp) == 0)
|
||||
return;
|
||||
err = gettimeofday(&tv);
|
||||
#else /* !GETTIMEOFDAY_NO_TZ */
|
||||
if (gettimeofday(tp, (struct timezone *)NULL) == 0)
|
||||
return;
|
||||
err = gettimeofday(&tv, (struct timezone *)NULL);
|
||||
#endif /* !GETTIMEOFDAY_NO_TZ */
|
||||
if (err == 0)
|
||||
{
|
||||
ts->seconds = tv.tv_sec;
|
||||
ts->numerator = tv.tv_usec;
|
||||
ts->denominator = MICROSECONDS;
|
||||
return;
|
||||
}
|
||||
#endif /* !HAVE_GETTIMEOFDAY */
|
||||
|
||||
#if defined(HAVE_FTIME)
|
||||
{
|
||||
struct timeb t;
|
||||
ftime(&t);
|
||||
tp->tv_sec = t.time;
|
||||
tp->tv_usec = t.millitm * 1000;
|
||||
}
|
||||
ts->seconds = t.time;
|
||||
ts->numerator = t.millitm;
|
||||
ts->denominator = 1000;
|
||||
#else /* !HAVE_FTIME */
|
||||
tp->tv_sec = time(NULL);
|
||||
tp->tv_usec = 0;
|
||||
ts->seconds = time(NULL);
|
||||
ts->numerator = 0;
|
||||
ts->denominator = 1;
|
||||
#endif /* !HAVE_FTIME */
|
||||
|
||||
#endif /* MS_WINDOWS */
|
||||
}
|
||||
|
||||
void
|
||||
_PyTime_gettimeofday(_PyTime_timeval *tv)
|
||||
{
|
||||
_PyTime_t ts;
|
||||
_PyTime_fraction_t k;
|
||||
time_t sec;
|
||||
|
||||
_PyTime_get(&ts);
|
||||
tv->tv_sec = ts.seconds;
|
||||
if (ts.numerator) {
|
||||
if (ts.numerator > ts.denominator) {
|
||||
sec = Py_SAFE_DOWNCAST(ts.numerator / ts.denominator,
|
||||
_PyTime_fraction_t, time_t);
|
||||
/* ignore integer overflow because _PyTime_gettimeofday() has
|
||||
no return value */
|
||||
tv->tv_sec += sec;
|
||||
ts.numerator = ts.numerator % ts.denominator;
|
||||
}
|
||||
if (MICROSECONDS >= ts.denominator) {
|
||||
k = (_PyTime_fraction_t)MICROSECONDS / ts.denominator;
|
||||
tv->tv_usec = (long)(ts.numerator * k);
|
||||
}
|
||||
else {
|
||||
k = ts.denominator / (_PyTime_fraction_t)MICROSECONDS;
|
||||
tv->tv_usec = (long)(ts.numerator / k);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tv->tv_usec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
_PyLong_FromTime_t(time_t value)
|
||||
{
|
||||
#if SIZEOF_TIME_T <= SIZEOF_LONG
|
||||
return PyLong_FromLong(value);
|
||||
#else
|
||||
assert(sizeof(time_t) <= sizeof(PY_LONG_LONG));
|
||||
return PyLong_FromLongLong(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HAVE_LONG_LONG)
|
||||
# define _PyLong_FromTimeFraction_t PyLong_FromLongLong
|
||||
#else
|
||||
# define _PyLong_FromTimeFraction_t PyLong_FromSize_t
|
||||
#endif
|
||||
|
||||
/* Convert a timestamp to a PyFloat object */
|
||||
static PyObject*
|
||||
_PyTime_AsFloat(_PyTime_t *ts)
|
||||
{
|
||||
double d;
|
||||
d = (double)ts->seconds;
|
||||
d += (double)ts->numerator / (double)ts->denominator;
|
||||
return PyFloat_FromDouble(d);
|
||||
}
|
||||
|
||||
/* Convert a timestamp to a PyLong object */
|
||||
static PyObject*
|
||||
_PyTime_AsLong(_PyTime_t *ts)
|
||||
{
|
||||
PyObject *a, *b, *c;
|
||||
|
||||
a = _PyLong_FromTime_t(ts->seconds);
|
||||
if (a == NULL)
|
||||
return NULL;
|
||||
b = _PyLong_FromTimeFraction_t(ts->numerator / ts->denominator);
|
||||
if (b == NULL)
|
||||
{
|
||||
Py_DECREF(a);
|
||||
return NULL;
|
||||
}
|
||||
c = PyNumber_Add(a, b);
|
||||
Py_DECREF(a);
|
||||
Py_DECREF(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Convert a timestamp to a decimal.Decimal object */
|
||||
static PyObject*
|
||||
_PyTime_AsDecimal(_PyTime_t *ts)
|
||||
{
|
||||
static PyObject* module = NULL;
|
||||
static PyObject* decimal = NULL;
|
||||
static PyObject* exponent_context = NULL;
|
||||
static PyObject* context = NULL;
|
||||
/* exponent cache, dictionary of:
|
||||
int (denominator) => Decimal (1/denominator) */
|
||||
static PyObject* exponent_cache = NULL;
|
||||
PyObject *t = NULL;
|
||||
PyObject *key, *exponent, *quantized;
|
||||
_Py_IDENTIFIER(quantize);
|
||||
_Py_IDENTIFIER(__truediv__);
|
||||
|
||||
if (!module) {
|
||||
module = PyImport_ImportModuleNoBlock("decimal");
|
||||
if (module == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!decimal) {
|
||||
decimal = PyObject_GetAttrString(module, "Decimal");
|
||||
if (decimal == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (context == NULL)
|
||||
{
|
||||
/* Use 12 decimal digits to store 10,000 years in seconds + 9
|
||||
decimal digits for the floating part in nanoseconds + 1 decimal
|
||||
digit to round correctly.
|
||||
|
||||
context = decimal.Context(22, rounding=decimal.ROUND_HALF_EVEN)
|
||||
exponent_context = decimal.Context(1, rounding=decimal.ROUND_HALF_EVEN)
|
||||
*/
|
||||
PyObject *context_class, *rounding;
|
||||
context_class = PyObject_GetAttrString(module, "Context");
|
||||
if (context_class == NULL)
|
||||
return NULL;
|
||||
rounding = PyObject_GetAttrString(module, "ROUND_HALF_EVEN");
|
||||
if (rounding == NULL)
|
||||
{
|
||||
Py_DECREF(context_class);
|
||||
return NULL;
|
||||
}
|
||||
context = PyObject_CallFunction(context_class, "iO", 22, rounding);
|
||||
if (context == NULL)
|
||||
{
|
||||
Py_DECREF(context_class);
|
||||
Py_DECREF(rounding);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
exponent_context = PyObject_CallFunction(context_class, "iO", 1, rounding);
|
||||
Py_DECREF(context_class);
|
||||
Py_DECREF(rounding);
|
||||
if (exponent_context == NULL)
|
||||
{
|
||||
Py_CLEAR(context);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* t = decimal.Decimal(value) */
|
||||
if (ts->seconds) {
|
||||
PyObject *f = _PyLong_FromTime_t(ts->seconds);
|
||||
t = PyObject_CallFunction(decimal, "O", f);
|
||||
Py_CLEAR(f);
|
||||
}
|
||||
else {
|
||||
t = PyObject_CallFunction(decimal, "iO", 0, context);
|
||||
}
|
||||
if (t == NULL)
|
||||
return NULL;
|
||||
|
||||
if (ts->numerator)
|
||||
{
|
||||
/* t += decimal.Decimal(numerator, ctx) / decimal.Decimal(denominator, ctx) */
|
||||
PyObject *a, *b, *c, *d, *x;
|
||||
|
||||
x = _PyLong_FromTimeFraction_t(ts->numerator);
|
||||
if (x == NULL)
|
||||
goto error;
|
||||
a = PyObject_CallFunction(decimal, "OO", x, context);
|
||||
Py_CLEAR(x);
|
||||
if (a == NULL)
|
||||
goto error;
|
||||
|
||||
x = _PyLong_FromTimeFraction_t(ts->denominator);
|
||||
if (x == NULL)
|
||||
{
|
||||
Py_DECREF(a);
|
||||
goto error;
|
||||
}
|
||||
b = PyObject_CallFunction(decimal, "OO", x, context);
|
||||
Py_CLEAR(x);
|
||||
if (b == NULL)
|
||||
{
|
||||
Py_DECREF(a);
|
||||
goto error;
|
||||
}
|
||||
|
||||
c = _PyObject_CallMethodId(a, &PyId___truediv__, "OO",
|
||||
b, context);
|
||||
Py_DECREF(a);
|
||||
Py_DECREF(b);
|
||||
if (c == NULL)
|
||||
goto error;
|
||||
|
||||
d = PyNumber_Add(t, c);
|
||||
Py_DECREF(c);
|
||||
if (d == NULL)
|
||||
goto error;
|
||||
Py_DECREF(t);
|
||||
t = d;
|
||||
}
|
||||
|
||||
if (exponent_cache == NULL) {
|
||||
exponent_cache = PyDict_New();
|
||||
if (exponent_cache == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
key = _PyLong_FromTimeFraction_t(ts->denominator);
|
||||
if (key == NULL)
|
||||
goto error;
|
||||
exponent = PyDict_GetItem(exponent_cache, key);
|
||||
if (exponent == NULL) {
|
||||
/* exponent = decimal.Decimal(1) / decimal.Decimal(resolution) */
|
||||
PyObject *one, *denominator;
|
||||
|
||||
one = PyObject_CallFunction(decimal, "i", 1);
|
||||
if (one == NULL) {
|
||||
Py_DECREF(key);
|
||||
goto error;
|
||||
}
|
||||
|
||||
denominator = PyObject_CallFunction(decimal, "O", key);
|
||||
if (denominator == NULL) {
|
||||
Py_DECREF(key);
|
||||
Py_DECREF(one);
|
||||
goto error;
|
||||
}
|
||||
|
||||
exponent = _PyObject_CallMethodId(one, &PyId___truediv__, "OO",
|
||||
denominator, exponent_context);
|
||||
Py_DECREF(one);
|
||||
Py_DECREF(denominator);
|
||||
if (exponent == NULL) {
|
||||
Py_DECREF(key);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (PyDict_SetItem(exponent_cache, key, exponent) < 0) {
|
||||
Py_DECREF(key);
|
||||
Py_DECREF(exponent);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(key);
|
||||
}
|
||||
|
||||
/* t = t.quantize(exponent, None, context) */
|
||||
quantized = _PyObject_CallMethodId(t, &PyId_quantize, "OOO",
|
||||
exponent, Py_None, context);
|
||||
if (quantized == NULL)
|
||||
goto error;
|
||||
Py_DECREF(t);
|
||||
t = quantized;
|
||||
|
||||
return t;
|
||||
|
||||
error:
|
||||
Py_XDECREF(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
_PyTime_Convert(_PyTime_t *ts, PyObject *format)
|
||||
{
|
||||
assert(ts->denominator != 0);
|
||||
|
||||
if (format == NULL || (PyTypeObject *)format == &PyFloat_Type)
|
||||
return _PyTime_AsFloat(ts);
|
||||
if ((PyTypeObject *)format == &PyLong_Type)
|
||||
return _PyTime_AsLong(ts);
|
||||
|
||||
if (PyType_Check(format))
|
||||
{
|
||||
PyObject *module, *name;
|
||||
_Py_IDENTIFIER(__name__);
|
||||
_Py_IDENTIFIER(__module__);
|
||||
|
||||
module = _PyObject_GetAttrId(format, &PyId___module__);
|
||||
name = _PyObject_GetAttrId(format, &PyId___name__);
|
||||
if (module != NULL && PyUnicode_Check(module)
|
||||
&& name != NULL && PyUnicode_Check(name))
|
||||
{
|
||||
if (PyUnicode_CompareWithASCIIString(module, "decimal") == 0
|
||||
&& PyUnicode_CompareWithASCIIString(name, "Decimal") == 0)
|
||||
return _PyTime_AsDecimal(ts);
|
||||
}
|
||||
else
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_ValueError, "Unknown timestamp format: %R", format);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
_PyTime_Init()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue