cpython: f8409b3d6449 (original) (raw)
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -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)
+
+.. 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.
+
.. 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
isFalse
. Set - the timestamp argument to get another :ref:`timestamp type
- `. + On some Unix systems (such as Linux), the following attributes may also be available:
@@ -2044,6 +2055,9 @@ Files and Directories Availability: Unix, Windows.
+ .. 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.
+
.. function:: statvfs(path)
@@ -2859,27 +2876,39 @@ written in Python, such as a mail server
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
.[](#l1.91)
: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.
- -.. 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.[](#l1.120)
--- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -95,6 +95,14 @@ An explanation of some terminology and c | local time | | | +-------------------------+-------------------------+-------------------------+ +.. _timestamp-types: + +* Python supports the following timestamp types: +
-.. function:: clock()
+.. function:: clock(timestamp=float)
.. index::
single: CPU time
@@ -136,16 +144,27 @@ The module defines the following functio
: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)
+ + +.. 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 functio
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
- It returns a floating point number by default, for compatibility with
- :func:
time
, set the timestamp argument to get another :ref:`timestamp - type
.[](#l2.70) +[](#l2.71) If the input value cannot be represented as a valid time, either[](#l2.72) :exc:
OverflowErroror :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 functio
: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.[](#l2.102)
+ .. data:: timezone @@ -546,13 +573,16 @@ The module defines the following functio ('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.
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -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
: + - :func:
~time.clock_getres
, :func:~time.monotonic
, :func:~time.time
and - :func:
~time.wallclock
- and :func:
~os.stat
(st_atime
,st_ctime
andst_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[](#l3.26) +<timestamp-types>
.
+
+Example::
+
+
+:func:os.stat_float_times
has been deprecated, use timestamp argument of
+os.stat
instead.
+
+
Other Language Changes
======================
--- a/Include/pytime.h +++ b/Include/pytime.h @@ -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 { [](#l4.13) ((tv_end.tv_sec - tv_start.tv_sec) + [](#l4.14) (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);
--- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -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.TestCa warnings.simplefilter("ignore", DeprecationWarning) self.check_stat_attributes(fname)
- def test_stat_timestamp(self):
# test deprecation[](#l5.16)
with warnings.catch_warnings():[](#l5.17)
warnings.simplefilter("error", DeprecationWarning)[](#l5.18)
self.assertRaises(DeprecationWarning, os.stat_float_times, False)[](#l5.19)
with warnings.catch_warnings():[](#l5.21)
warnings.simplefilter("ignore", DeprecationWarning)[](#l5.22)
old_value = os.stat_float_times()[](#l5.23)
try:[](#l5.24)
# test invalid timestamp types[](#l5.25)
self.assertRaises(ValueError, os.stat, self.fname,[](#l5.26)
timestamp="abc")[](#l5.27)
self.assertRaises(ValueError, os.stat, self.fname,[](#l5.28)
timestamp=decimal.Context)[](#l5.29)
for float_times in (False, True):[](#l5.31)
os.stat_float_times(float_times)[](#l5.32)
t = os.stat(self.fname).st_mtime[](#l5.33)
if float_times:[](#l5.34)
self.assertIsInstance(t, float)[](#l5.35)
else:[](#l5.36)
self.assertIsInstance(t, int)[](#l5.37)
for type in (int, float, decimal.Decimal):[](#l5.39)
t = os.stat(self.fname, timestamp=type).st_mtime[](#l5.40)
self.assertIsInstance(t, type)[](#l5.41)
finally:[](#l5.42)
os.stat_float_times(old_value)[](#l5.43)
+ def test_statvfs_attributes(self): if not hasattr(os, "statvfs"): return
--- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -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[](#l6.23)
calls = [[](#l6.24)
(time.time,),[](#l6.25)
(time.mktime, time.localtime()),[](#l6.26)
][](#l6.27)
if hasattr(time, 'monotonic'):[](#l6.28)
calls.append((time.monotonic,))[](#l6.29)
if hasattr(time, 'wallclock'):[](#l6.30)
calls.append((time.wallclock,))[](#l6.31)
if hasattr(time, 'CLOCK_REALTIME'):[](#l6.32)
if hasattr(time, 'clock_gettime'):[](#l6.33)
calls.append((time.clock_gettime, time.CLOCK_REALTIME))[](#l6.34)
if hasattr(time, 'clock_getres'):[](#l6.35)
calls.append((time.clock_getres, time.CLOCK_REALTIME))[](#l6.36)
for call in calls:[](#l6.37)
func, *args = call[](#l6.38)
# test invalid timestamp[](#l6.40)
for invalid in ("int", decimal.Context):[](#l6.41)
self.assertRaises(ValueError, func, *args, timestamp=invalid)[](#l6.42)
for type in (int, float, decimal.Decimal):[](#l6.44)
self.assertIsInstance(func(*args, timestamp=type), type)[](#l6.45)
+ def test_wallclock(self): t1 = time.wallclock() t2 = time.wallclock()
--- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1702,6 +1702,12 @@ stat_float_times(PyObject* self, PyObjec 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, "[](#l7.8)
"use timestamp argument of os.stat() instead",[](#l7.9)
1))[](#l7.10)
return NULL;[](#l7.11)
+ if (newval == -1) /* Return old value / return PyBool_FromLong(_stat_float_times); @@ -1711,9 +1717,12 @@ stat_float_times(PyObject self, PyObjec } 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)[](#l7.22)
+ #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 #endif if (!ival) return;
- if (timestamp == NULL && _stat_float_times)
timestamp = (PyObject*)&PyFloat_Type;[](#l7.38)
- if (timestamp != NULL) {
ts.seconds = sec;[](#l7.40)
if (has_nsec) {[](#l7.41)
ts.numerator = nsec;[](#l7.42)
ts.denominator = 1000000000;[](#l7.43)
}[](#l7.44)
else {[](#l7.45)
ts.numerator = 0;[](#l7.46)
ts.denominator = 1;[](#l7.47)
}[](#l7.48)
fval = _PyTime_Convert(&ts, timestamp);[](#l7.49)
- }
- else { fval = ival; Py_INCREF(fval); } @@ -1734,9 +1755,14 @@ fill_time(PyObject v, int index, time_t / 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
+#endif + PyObject v = PyStructSequence_New(&StatResultType); if (v == NULL) return NULL; @@ -1768,20 +1794,24 @@ static PyObject ansec = st->st_atim.tv_nsec; mnsec = st->st_mtim.tv_nsec; cnsec = st->st_ctim.tv_nsec;
#elif defined(HAVE_STAT_TV_NSEC2) ansec = st->st_atimespec.tv_nsec; mnsec = st->st_mtimespec.tv_nsec; cnsec = st->st_ctimespec.tv_nsec;
#elif defined(HAVE_STAT_NSEC) ansec = st->st_atime_nsec; mnsec = st->st_mtime_nsec; cnsec = st->st_ctime_nsec;
#else ansec = mnsec = cnsec = 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, @@ -1801,21 +1831,26 @@ static PyObject* #endif #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME {
PyObject *val;[](#l7.104)
unsigned long bsec,bnsec;[](#l7.105)
bsec = (long)st->st_birthtime;[](#l7.106)
PyObject *val;[](#l7.107)
ts.seconds = (long)st->st_birthtime;[](#l7.108)
bnsec = st->st_birthtimespec.tv_nsec;[](#l7.110)
ts.numerator = st->st_birthtimespec.tv_nsec;[](#l7.111)
ts.denominator = 1000000000;[](#l7.112)
bnsec = 0;[](#l7.114)
if (_stat_float_times) {[](#l7.116)
val = PyFloat_FromDouble(bsec + 1e-9*bnsec);[](#l7.117)
} else {[](#l7.118)
val = PyLong_FromLong((long)bsec);[](#l7.119)
}[](#l7.120)
PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,[](#l7.121)
val);[](#l7.122)
ts.numerator = 0;[](#l7.123)
ts.denominator = 1;[](#l7.124)
if (timestamp == NULL) {[](#l7.126)
if (_stat_float_times)[](#l7.127)
val = _PyTime_Convert(&ts, (PyObject*)&PyFloat_Type);[](#l7.128)
else[](#l7.129)
val = _PyTime_Convert(&ts, (PyObject*)&PyLong_Type);[](#l7.130)
}[](#l7.131)
else {[](#l7.132)
val = _PyTime_Convert(&ts, timestamp);[](#l7.133)
}[](#l7.134)
PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,[](#l7.135)
}val);[](#l7.136)
#endif #ifdef HAVE_STRUCT_STAT_ST_FLAGS @@ -1832,7 +1867,7 @@ static PyObject* } 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 * 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_ParseTupleAndKeywords(args, kw, wformat, kwlist,
&po, ×tamp)) {[](#l7.165) wchar_t *wpath = PyUnicode_AsUnicode(po);[](#l7.166) if (wpath == NULL)[](#l7.167) return NULL;[](#l7.168)
@@ -1861,15 +1899,17 @@ posix_do_stat(PyObject *self, PyObject * if (res != 0) return win32_error_object("stat", po);
return _pystat_fromstructstat(&st);[](#l7.173)
} /* Drop the argument parsing error as narrow strings are also valid. */ PyErr_Clear(); -#endif -return _pystat_fromstructstat(&st, timestamp);[](#l7.174)
- if (!PyArg_ParseTupleAndKeywords(args, kw, format, kwlist,
PyUnicode_FSConverter, &opath,[](#l7.187)
×tamp))[](#l7.188) return NULL;[](#l7.189)
#ifdef MS_WINDOWS if (win32_warn_bytes_api()) { @@ -1890,7 +1930,7 @@ posix_do_stat(PyObject *self, PyObject * #endif } else
result = _pystat_fromstructstat(&st);[](#l7.196)
result = _pystat_fromstructstat(&st, timestamp);[](#l7.197)
Py_DECREF(opath); return result; @@ -3381,16 +3421,16 @@ posix_rmdir(PyObject *self, PyObject *ar PyDoc_STRVAR(posix_stat__doc__, -"stat(path) -> stat result\n\n[](#l7.205) +"stat(path, timestamp=None) -> stat result\n\n[](#l7.206) 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
#endif } @@ -6118,11 +6158,12 @@ posix_setgroups(PyObject *self, PyObject #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);
if (pid == -1) return posix_error(); @@ -6146,10 +6187,17 @@ wait_helper(pid_t pid, int status, struc #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)));[](#l7.244)
_PyTime_Convert(&ts, timestamp));[](#l7.245)
- 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)));[](#l7.251)
_PyTime_Convert(&ts, timestamp));[](#l7.252)
#define SET_INT(result, index, value)[](#l7.253) 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, struc #ifdef HAVE_WAIT3 PyDoc_STRVAR(posix_wait3__doc__, -"wait3(options) -> (pid, status, rusage)\n\n[](#l7.260) +"wait3(options[, timestamp=float]) -> (pid, status, rusage)\n\n[](#l7.261) 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; -
- 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
} #endif /* HAVE_WAIT3 */ #ifdef HAVE_WAIT4 PyDoc_STRVAR(posix_wait4__doc__, -"wait4(pid, options) -> (pid, status, rusage)\n\n[](#l7.293) +"wait4(pid, options[, timestamp=float]) -> (pid, status, rusage)\n\n[](#l7.294) 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; -
- 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
} #endif /* HAVE_WAIT4 */ @@ -6350,20 +6402,20 @@ posix_wait(PyObject *self, PyObject *noa PyDoc_STRVAR(posix_lstat__doc__, -"lstat(path) -> stat result\n\n[](#l7.328) +"lstat(path, timestamp=None) -> stat result\n\n[](#l7.329) 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
#else /* !HAVE_LSTAT */ #ifdef MS_WINDOWS
#endif #endif /* !HAVE_LSTAT */ } @@ -7322,16 +7374,19 @@ done: #endif PyDoc_STRVAR(posix_fstat__doc__, -"fstat(fd) -> stat result\n\n[](#l7.354) +"fstat(fd, timestamp=None) -> stat result\n\n[](#l7.355) Like stat(), but for an open file descriptor."); static PyObject * -posix_fstat(PyObject *self, PyObject *args) -{ +posix_fstat(PyObject *self, PyObject *args, PyObject *kwargs) +{
- PyObject *timestamp = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|O:fstat", kwlist,
&fd, ×tamp))[](#l7.370) return NULL;[](#l7.371)
#ifdef __VMS /* on OpenVMS we must ensure that all bytes are written to the file */ @@ -7350,7 +7405,7 @@ posix_fstat(PyObject *self, PyObject *ar #endif }
} PyDoc_STRVAR(posix_isatty__doc__, @@ -9634,22 +9689,25 @@ posix_fchownat(PyObject *self, PyObject #ifdef HAVE_FSTATAT PyDoc_STRVAR(posix_fstatat__doc__, -"fstatat(dirfd, path, flags=0) -> stat result\n\n[](#l7.387) +"fstatat(dirfd, path, flags=0, timestamp=None) -> stat result\n\n[](#l7.388) Like stat() but if path is relative, it is taken as relative to dirfd.\n[](#l7.389) flags is optional and may be 0 or AT_SYMLINK_NOFOLLOW.\n[](#l7.390) If path is relative and dirfd is the special value AT_FDCWD, then path\n[](#l7.391) 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; -
- if (!PyArg_ParseTuple(args, "iO&|i:fstatat",
&dirfd, PyUnicode_FSConverter, &opath, &flags))[](#l7.406)
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO&|iO:fstatat", kwlist,
&dirfd, PyUnicode_FSConverter, &opath,[](#l7.410)
path = PyBytes_AsString(opath); @@ -9660,7 +9718,7 @@ posix_fstatat(PyObject *self, PyObject * if (res != 0) return posix_error();&flags, ×tamp))[](#l7.411) return NULL;[](#l7.412)
} #endif @@ -10524,7 +10582,7 @@ static PyMethodDef posix_methods[] = { #ifdef HAVE_FDOPENDIR {"flistdir", posix_flistdir, METH_VARARGS, posix_flistdir__doc__}, #endif
- {"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", (PyCFunction)posix_stat,
{"stat_float_times", stat_float_times, METH_VARARGS, stat_float_times__doc__},METH_VARARGS | METH_KEYWORDS, posix_stat__doc__},[](#l7.439)
#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
#endif /* HAVE_WAIT3 */ #ifdef HAVE_WAIT4
#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", (PyCFunction)posix_fstat, METH_VARARGS | METH_KEYWORDS,
{"isatty", posix_isatty, METH_VARARGS, posix_isatty__doc__},posix_fstat__doc__},[](#l7.464)
#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", (PyCFunction)posix_fstatat, METH_VARARGS | METH_KEYWORDS,
posix_fstatat__doc__},[](#l7.474)
#endif #ifdef HAVE_FUTIMESAT {"futimesat", posix_futimesat, METH_VARARGS, posix_futimesat__doc__},
--- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -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) {
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:time", kwlist,
×tamp))[](#l8.28) return NULL;[](#l8.29)
} PyDoc_STRVAR(time_doc, -"time() -> floating point number\n[](#l8.38) +"time(timestamp=float) -> floating point number\n[](#l8.39) \n[](#l8.40) Return the current time in seconds since the Epoch.\n[](#l8.41) 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 #endif #endif -static PyObject * -pyclock(void) +static int +pyclock(_PyTime_t *ts) {
- 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;[](#l8.61)
- ts->seconds = 0;
- assert(sizeof(clock_t) <= sizeof(_PyTime_fraction_t));
- ts->numerator = Py_SAFE_DOWNCAST(processor_time,
clock_t, _PyTime_fraction_t);[](#l8.68)
- 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;
if (cpu_frequency == 0) { LARGE_INTEGER freq; QueryPerformanceCounter(&now);
ctrStart = now.QuadPart;[](#l8.92)
start = now.QuadPart;[](#l8.93) if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) {[](#l8.94) /* Unlikely to happen - this works on all intel[](#l8.95) machines at least! Revert to clock() */[](#l8.96)
if (fallback)[](#l8.97)
return pyclock();[](#l8.98)
else[](#l8.99)
return PyErr_SetFromWindowsErr(0);[](#l8.100)
if (fallback) {[](#l8.101)
return pyclock(ts);[](#l8.102)
}[](#l8.103)
else {[](#l8.104)
PyErr_SetFromWindowsErr(0);[](#l8.105)
return -1;[](#l8.106)
} QueryPerformanceCounter(&now);}[](#l8.107) }[](#l8.108) cpu_frequency = freq.QuadPart;[](#l8.109)
- ts->seconds = 0;
- assert(sizeof(LONGLONG) <= sizeof(_PyTime_fraction_t));
- ts->numerator = Py_SAFE_DOWNCAST(dt,
LONGLONG, _PyTime_fraction_t);[](#l8.119)
- ts->denominator = Py_SAFE_DOWNCAST(cpu_frequency,
LONGLONG, _PyTime_fraction_t);[](#l8.121)
- 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) {
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:clock", kwlist,
×tamp))[](#l8.136)
return NULL;[](#l8.137)
+ #if defined(MS_WINDOWS) && !defined(BORLANDC)
} PyDoc_STRVAR(clock_doc, -"clock() -> floating point number\n[](#l8.152) +"clock(timestamp=float) -> floating point number\n[](#l8.153) \n[](#l8.154) Return the CPU time or real time since the start of the process or since\n[](#l8.155) the first call to clock(). This has as much precision as the system\n[](#l8.156) @@ -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_ParseTupleAndKeywords(args, kwargs, "i|O:clock_gettime", kwlist,
&clk_id, ×tamp))[](#l8.173) return NULL;[](#l8.174)
ret = clock_gettime((clockid_t)clk_id, &tp); @@ -153,25 +189,31 @@ time_clock_gettime(PyObject *self, PyObj PyErr_SetFromErrno(PyExc_IOError); return NULL; } -
- 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[](#l8.190) +"clock_gettime(clk_id, timestamp=float) -> floating point number\n[](#l8.191) \n[](#l8.192) 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_ParseTupleAndKeywords(args, kwargs, "i|O:clock_getres", kwlist,
&clk_id, ×tamp))[](#l8.210) return NULL;[](#l8.211)
ret = clock_getres((clockid_t)clk_id, &tp); @@ -179,12 +221,14 @@ time_clock_getres(PyObject *self, PyObje PyErr_SetFromErrno(PyExc_IOError); return NULL; } -
- 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[](#l8.227) +"clock_getres(clk_id, timestamp=float) -> floating point number\n[](#l8.228) \n[](#l8.229) Return the resolution (precision) of the specified clock clk_id."); #endif @@ -707,10 +751,19 @@ not present, current time as returned by #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))[](#l8.247)
return NULL;[](#l8.248)
+ if (!gettmarg(tup, &buf)) return NULL; buf.tm_wday = -1; /* sentinel; original value ignored */ @@ -722,7 +775,10 @@ time_mktime(PyObject *self, PyObject *tu "mktime argument out of range"); return NULL; }
} PyDoc_STRVAR(mktime_doc, @@ -768,12 +824,14 @@ the local timezone used by methods such 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)
-#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+#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 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);[](#l8.288)
{[](#l8.289)
ts->seconds = tp.tv_sec;[](#l8.290)
ts->numerator = tp.tv_nsec;[](#l8.291)
ts->denominator = 1000000000;[](#l8.292)
return 0;[](#l8.293)
}[](#l8.294)
clk_index++; if (Py_ARRAY_LENGTH(clk_ids) <= clk_index) clk_index = -1; }
+#endif /* defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) */ +
#endif } +static PyObject * +time_wallclock(PyObject *self, PyObject *args, PyObject *kwargs) +{
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:wallclock", kwlist,
×tamp))[](#l8.318)
return NULL;[](#l8.319)
- if (pywallclock(&ts))
return NULL;[](#l8.321)
- return _PyTime_Convert(&ts, timestamp);
+} + PyDoc_STRVAR(wallclock_doc, -"wallclock() -> float\n[](#l8.326) +"wallclock(timestamp=float)\n[](#l8.327) \n[](#l8.328) Return the current time in fractions of a second to the system's best\n[](#l8.329) ability. Use this when the most accurate representation of wall-clock is\n[](#l8.330) @@ -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)
+#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 }; int ret; struct timespec tp; +#endif
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:monotonic", kwlist,
×tamp))[](#l8.355)
return NULL;[](#l8.356)
+ +#if defined(MS_WINDOWS) && !defined(BORLANDC)
+#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);[](#l8.367)
{[](#l8.368)
ts.seconds = tp.tv_sec;[](#l8.369)
ts.numerator = tp.tv_nsec;[](#l8.370)
ts.denominator = 1000000000;[](#l8.371)
return _PyTime_Convert(&ts, timestamp);[](#l8.372)
}[](#l8.373)
clk_index++; if (Py_ARRAY_LENGTH(clk_ids) <= clk_index) @@ -968,15 +1063,19 @@ PyInit_timezone(PyObject *m) { static PyMethodDef time_methods[] = {
-#if (defined(MS_WINDOWS) && !defined(BORLANDC)) || defined(HAVE_CLOCK)
#endif #ifdef HAVE_CLOCK_GETTIME
- {"clock_gettime", (PyCFunction)time_clock_gettime,
METH_VARARGS | METH_KEYWORDS, clock_gettime_doc},[](#l8.393)
#endif #ifdef HAVE_CLOCK_GETRES
- {"clock_getres", (PyCFunction)time_clock_getres,
METH_VARARGS | METH_KEYWORDS, clock_getres_doc},[](#l8.398)
#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
#endif #ifdef HAVE_PYTIME_MONOTONIC
#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", (PyCFunction)time_wallclock,
{NULL, NULL} /* sentinel */ }; @@ -1081,15 +1183,6 @@ PyInit_time(void) return m; } -static double -floattime(void) -{METH_VARARGS | METH_KEYWORDS, wallclock_doc},[](#l8.423)
-} - - /* Implement floatsleep() for various platforms. When interrupted (or when another error occurs), return -1 and set an exception; else return 0. */
--- a/Python/pytime.c +++ b/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;
GetSystemTimeAsFileTime(&system_time); large.u.LowPart = system_time.dwLowDateTime; large.u.HighPart = system_time.dwHighDateTime;
- /* 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
+#endif +#if defined(HAVE_FTIME)
+#endif + /* There are three ways to get the time: (1) gettimeofday() -- resolution in microseconds (2) ftime() -- resolution in milliseconds @@ -47,30 +59,325 @@ void #ifdef HAVE_GETTIMEOFDAY #ifdef GETTIMEOFDAY_NO_TZ
#else /* !GETTIMEOFDAY_NO_TZ */
+#endif /* !GETTIMEOFDAY_NO_TZ */
- if (err == 0)
- {
ts->seconds = tv.tv_sec;[](#l9.59)
ts->numerator = tv.tv_usec;[](#l9.60)
ts->denominator = MICROSECONDS;[](#l9.61) return;[](#l9.62)
-#endif /* !GETTIMEOFDAY_NO_TZ */
#endif /* !HAVE_GETTIMEOFDAY */ #if defined(HAVE_FTIME)
- {
struct timeb t;[](#l9.69)
ftime(&t);[](#l9.70)
tp->tv_sec = t.time;[](#l9.71)
tp->tv_usec = t.millitm * 1000;[](#l9.72)
- }
#endif /* !HAVE_FTIME / #endif / MS_WINDOWS */ } void +_PyTime_gettimeofday(_PyTime_timeval *tv) +{
- _PyTime_get(&ts);
- tv->tv_sec = ts.seconds;
- if (ts.numerator) {
if (ts.numerator > ts.denominator) {[](#l9.99)
sec = Py_SAFE_DOWNCAST(ts.numerator / ts.denominator,[](#l9.100)
_PyTime_fraction_t, time_t);[](#l9.101)
/* ignore integer overflow because _PyTime_gettimeofday() has[](#l9.102)
no return value */[](#l9.103)
tv->tv_sec += sec;[](#l9.104)
ts.numerator = ts.numerator % ts.denominator;[](#l9.105)
}[](#l9.106)
if (MICROSECONDS >= ts.denominator) {[](#l9.107)
k = (_PyTime_fraction_t)MICROSECONDS / ts.denominator;[](#l9.108)
tv->tv_usec = (long)(ts.numerator * k);[](#l9.109)
}[](#l9.110)
else {[](#l9.111)
k = ts.denominator / (_PyTime_fraction_t)MICROSECONDS;[](#l9.112)
tv->tv_usec = (long)(ts.numerator / k);[](#l9.113)
}[](#l9.114)
- }
- else {
tv->tv_usec = 0;[](#l9.117)
- }
+} + +static PyObject* +_PyLong_FromTime_t(time_t value) +{ +#if SIZEOF_TIME_T <= SIZEOF_LONG
+#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) +{
- a = _PyLong_FromTime_t(ts->seconds);
- if (a == NULL)
return NULL;[](#l9.156)
- b = _PyLong_FromTimeFraction_t(ts->numerator / ts->denominator);
- if (b == NULL)
- {
Py_DECREF(a);[](#l9.160)
return NULL;[](#l9.161)
- }
- 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) */[](#l9.178)
- static PyObject* exponent_cache = NULL;
- PyObject *t = NULL;
- PyObject *key, *exponent, *quantized;
- _Py_IDENTIFIER(quantize);
- _Py_IDENTIFIER(truediv);
- if (!module) {
module = PyImport_ImportModuleNoBlock("decimal");[](#l9.186)
if (module == NULL)[](#l9.187)
return NULL;[](#l9.188)
- }
- if (!decimal) {
decimal = PyObject_GetAttrString(module, "Decimal");[](#l9.192)
if (decimal == NULL)[](#l9.193)
return NULL;[](#l9.194)
- }
- if (context == NULL)
- {
/* Use 12 decimal digits to store 10,000 years in seconds + 9[](#l9.199)
decimal digits for the floating part in nanoseconds + 1 decimal[](#l9.200)
digit to round correctly.[](#l9.201)
context = decimal.Context(22, rounding=decimal.ROUND_HALF_EVEN)[](#l9.203)
exponent_context = decimal.Context(1, rounding=decimal.ROUND_HALF_EVEN)[](#l9.204)
*/[](#l9.205)
PyObject *context_class, *rounding;[](#l9.206)
context_class = PyObject_GetAttrString(module, "Context");[](#l9.207)
if (context_class == NULL)[](#l9.208)
return NULL;[](#l9.209)
rounding = PyObject_GetAttrString(module, "ROUND_HALF_EVEN");[](#l9.210)
if (rounding == NULL)[](#l9.211)
{[](#l9.212)
Py_DECREF(context_class);[](#l9.213)
return NULL;[](#l9.214)
}[](#l9.215)
context = PyObject_CallFunction(context_class, "iO", 22, rounding);[](#l9.216)
if (context == NULL)[](#l9.217)
{[](#l9.218)
Py_DECREF(context_class);[](#l9.219)
Py_DECREF(rounding);[](#l9.220)
return NULL;[](#l9.221)
}[](#l9.222)
exponent_context = PyObject_CallFunction(context_class, "iO", 1, rounding);[](#l9.224)
Py_DECREF(context_class);[](#l9.225)
Py_DECREF(rounding);[](#l9.226)
if (exponent_context == NULL)[](#l9.227)
{[](#l9.228)
Py_CLEAR(context);[](#l9.229)
return NULL;[](#l9.230)
}[](#l9.231)
- }
- /* t = decimal.Decimal(value) */
- if (ts->seconds) {
PyObject *f = _PyLong_FromTime_t(ts->seconds);[](#l9.236)
t = PyObject_CallFunction(decimal, "O", f);[](#l9.237)
Py_CLEAR(f);[](#l9.238)
- }
- else {
t = PyObject_CallFunction(decimal, "iO", 0, context);[](#l9.241)
- }
- if (t == NULL)
return NULL;[](#l9.244)
- if (ts->numerator)
- {
/* t += decimal.Decimal(numerator, ctx) / decimal.Decimal(denominator, ctx) */[](#l9.248)
PyObject *a, *b, *c, *d, *x;[](#l9.249)
x = _PyLong_FromTimeFraction_t(ts->numerator);[](#l9.251)
if (x == NULL)[](#l9.252)
goto error;[](#l9.253)
a = PyObject_CallFunction(decimal, "OO", x, context);[](#l9.254)
Py_CLEAR(x);[](#l9.255)
if (a == NULL)[](#l9.256)
goto error;[](#l9.257)
x = _PyLong_FromTimeFraction_t(ts->denominator);[](#l9.259)
if (x == NULL)[](#l9.260)
{[](#l9.261)
Py_DECREF(a);[](#l9.262)
goto error;[](#l9.263)
}[](#l9.264)
b = PyObject_CallFunction(decimal, "OO", x, context);[](#l9.265)
Py_CLEAR(x);[](#l9.266)
if (b == NULL)[](#l9.267)
{[](#l9.268)
Py_DECREF(a);[](#l9.269)
goto error;[](#l9.270)
}[](#l9.271)
c = _PyObject_CallMethodId(a, &PyId___truediv__, "OO",[](#l9.273)
b, context);[](#l9.274)
Py_DECREF(a);[](#l9.275)
Py_DECREF(b);[](#l9.276)
if (c == NULL)[](#l9.277)
goto error;[](#l9.278)
d = PyNumber_Add(t, c);[](#l9.280)
Py_DECREF(c);[](#l9.281)
if (d == NULL)[](#l9.282)
goto error;[](#l9.283)
Py_DECREF(t);[](#l9.284)
t = d;[](#l9.285)
- }
- if (exponent_cache == NULL) {
exponent_cache = PyDict_New();[](#l9.289)
if (exponent_cache == NULL)[](#l9.290)
goto error;[](#l9.291)
- }
- key = _PyLong_FromTimeFraction_t(ts->denominator);
- if (key == NULL)
goto error;[](#l9.296)
- exponent = PyDict_GetItem(exponent_cache, key);
- if (exponent == NULL) {
/* exponent = decimal.Decimal(1) / decimal.Decimal(resolution) */[](#l9.299)
PyObject *one, *denominator;[](#l9.300)
one = PyObject_CallFunction(decimal, "i", 1);[](#l9.302)
if (one == NULL) {[](#l9.303)
Py_DECREF(key);[](#l9.304)
goto error;[](#l9.305)
}[](#l9.306)
denominator = PyObject_CallFunction(decimal, "O", key);[](#l9.308)
if (denominator == NULL) {[](#l9.309)
Py_DECREF(key);[](#l9.310)
Py_DECREF(one);[](#l9.311)
goto error;[](#l9.312)
}[](#l9.313)
exponent = _PyObject_CallMethodId(one, &PyId___truediv__, "OO",[](#l9.315)
denominator, exponent_context);[](#l9.316)
Py_DECREF(one);[](#l9.317)
Py_DECREF(denominator);[](#l9.318)
if (exponent == NULL) {[](#l9.319)
Py_DECREF(key);[](#l9.320)
goto error;[](#l9.321)
}[](#l9.322)
if (PyDict_SetItem(exponent_cache, key, exponent) < 0) {[](#l9.324)
Py_DECREF(key);[](#l9.325)
Py_DECREF(exponent);[](#l9.326)
goto error;[](#l9.327)
}[](#l9.328)
Py_DECREF(key);[](#l9.329)
- }
- /* t = t.quantize(exponent, None, context) */
- quantized = _PyObject_CallMethodId(t, &PyId_quantize, "OOO",
exponent, Py_None, context);[](#l9.334)
- if (quantized == NULL)
goto error;[](#l9.336)
- Py_DECREF(t);
- t = quantized;
+} + +PyObject* +_PyTime_Convert(_PyTime_t *ts, PyObject *format) +{
- if (format == NULL || (PyTypeObject *)format == &PyFloat_Type)
return _PyTime_AsFloat(ts);[](#l9.353)
- if ((PyTypeObject *)format == &PyLong_Type)
return _PyTime_AsLong(ts);[](#l9.355)
- if (PyType_Check(format))
- {
PyObject *module, *name;[](#l9.359)
_Py_IDENTIFIER(__name__);[](#l9.360)
_Py_IDENTIFIER(__module__);[](#l9.361)
module = _PyObject_GetAttrId(format, &PyId___module__);[](#l9.363)
name = _PyObject_GetAttrId(format, &PyId___name__);[](#l9.364)
if (module != NULL && PyUnicode_Check(module)[](#l9.365)
&& name != NULL && PyUnicode_Check(name))[](#l9.366)
{[](#l9.367)
if (PyUnicode_CompareWithASCIIString(module, "decimal") == 0[](#l9.368)
&& PyUnicode_CompareWithASCIIString(name, "Decimal") == 0)[](#l9.369)
return _PyTime_AsDecimal(ts);[](#l9.370)
}[](#l9.371)
else[](#l9.372)
PyErr_Clear();[](#l9.373)
- }
+} + +void _PyTime_Init() { /* Do nothing. Needed to force linking. */