Skip to content

Commit c3b4c45

Browse files
committed
pythongh-110850: Add PyTime_t C API
Add PyTime_t API: * PyTime_t type. * PyTime_MIN and PyTime_MAX constants. * PyTime_AsSecondsDouble(), PyTime_GetMonotonicClock(), PyTime_GetPerfCounter() and PyTime_GetSystemClock() functions.
1 parent 7218bac commit c3b4c45

23 files changed

+345
-190
lines changed

Doc/c-api/time.rst

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
.. highlight:: c
2+
3+
PyTime API
4+
==========
5+
6+
.. versionadded:: 3.13
7+
8+
PyTime API
9+
----------
10+
11+
The PyTime_t API is written to use timestamp and timeout values stored in
12+
various formats and to read clocks.
13+
14+
The :c:type:`PyTime_t` type is an integer to support directly common arithmetic
15+
operations such as ``t1 + t2``.
16+
17+
The PyTime_t API supports a resolution of ``1`` nanosecond. The
18+
:c:type:`PyTime_t` type is signed to support negative timestamps. The supported
19+
range is around [-292.3 years; +292.3 years]. Using the Unix epoch (January
20+
1st, 1970), the supported date range is around [1677-09-21; 2262-04-11].
21+
22+
Time formats:
23+
24+
* Seconds.
25+
* Seconds as a floating pointer number (C :c:type:`double`).
26+
* Milliseconds (10\ :sup:`-3` seconds).
27+
* Microseconds (10\ :sup:`-6` seconds).
28+
* 100 nanoseconds (10\ :sup:`-7` seconds), used on Windows.
29+
* Nanoseconds (10\ :sup:`-9` seconds).
30+
* :c:expr:`timeval` structure, 1 microsecond (10\ :sup:`-6` seconds).
31+
* :c:expr:`timespec` structure, 1 nanosecond (10\ :sup:`-9` seconds).
32+
33+
Integer overflows are detected and raise :exc:`OverflowError`. Conversion to a
34+
resolution larger than 1 nanosecond is rounded correctly with the requested
35+
rounding mode. Available rounding modes:
36+
37+
* Round towards minus infinity (-inf). For example, used to read a clock.
38+
* Round towards infinity (+inf). For example, used for timeout to wait "at
39+
least" N seconds.
40+
* Round to nearest with ties going to nearest even integer. For example, used
41+
to round from a Python float.
42+
* Round away from zero. For example, used for timeout.
43+
44+
Some functions clamp the result in the range [PyTime_MIN; PyTime_MAX]. The
45+
caller doesn't have to handle errors and so doesn't need to hold the GIL to
46+
handle exceptions. For example, ``_PyTime_Add(t1, t2)`` computes ``t1+t2`` and
47+
clamps the result on overflow.
48+
49+
Clocks:
50+
51+
* System clock
52+
* Monotonic clock
53+
* Performance counter
54+
55+
Internally, operations like ``(t * k / q)`` with integers are implemented in a
56+
way to reduce the risk of integer overflow. Such operation is used to convert a
57+
clock value expressed in ticks with a frequency to PyTime_t, like
58+
``QueryPerformanceCounter()`` with ``QueryPerformanceFrequency()`` on Windows.
59+
60+
61+
Types
62+
-----
63+
64+
.. c:type:: PyTime_t
65+
66+
Timestamp type with subsecond precision: 64-bit signed integer.
67+
68+
This type can be used to store a duration. Indirectly, it can be used to
69+
store a date relative to a reference date, such as the UNIX epoch.
70+
71+
72+
Constants
73+
---------
74+
75+
.. c:var:: PyTime_t PyTime_MIN
76+
77+
Minimum value of the :c:type:`PyTime_t` type.
78+
:c:macro`PyTime_MIN` nanoseconds is around -292.3 years.
79+
80+
.. c:var:: PyTime_t PyTime_MAX
81+
82+
Maximum value of the :c:type:`PyTime_t` type.
83+
:c:macro`PyTime_MAX` nanoseconds is around +292.3 years.
84+
85+
86+
Functions
87+
---------
88+
89+
.. c:function:: double PyTime_AsSecondsDouble(PyTime_t t)
90+
91+
Convert a timestamp to a number of seconds as a C :c:type:`double`.
92+
93+
The function cannot fail.
94+
95+
96+
.. c:function:: PyTime_t PyTime_GetMonotonicClock(void)
97+
98+
Get the time of a monotonic clock, i.e. a clock that cannot go backwards.
99+
The clock is not affected by system clock updates. The reference point of
100+
the returned value is undefined, so that only the difference between the
101+
results of consecutive calls is valid.
102+
103+
If reading the clock fails, silently ignore the error and return 0.
104+
105+
On integer overflow, silently ignore the overflow and clamp the clock to
106+
the [PyTime_MIN; PyTime_MAX] range.
107+
108+
See also the :func:`time.monotonic` function.
109+
110+
.. c:function:: PyTime_t PyTime_GetPerfCounter(void)
111+
112+
Get the performance counter: clock with the highest available resolution to
113+
measure a short duration.
114+
115+
If reading the clock fails, silently ignore the error and return 0.
116+
117+
On integer overflow, silently ignore the overflow and clamp the time to the
118+
[PyTime_MIN; PyTime_MAX] range.
119+
120+
See also the :func:`time.perf_counter` function.
121+
122+
123+
.. c:function:: PyTime_t PyTime_GetSystemClock(void)
124+
125+
Get the current time from the system clock.
126+
127+
If reading the clock fails, silently ignore the error and return ``0``.
128+
129+
On integer overflow, silently ignore the overflow and clamp the clock to
130+
the [PyTime_MIN; PyTime_MAX] range.
131+
132+
See also the :func:`time.time` function.

Doc/c-api/utilities.rst

+1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ and parsing function arguments and constructing Python values from C values.
2020
hash.rst
2121
reflection.rst
2222
codec.rst
23+
time.rst
2324
perfmaps.rst

Doc/whatsnew/3.13.rst

+10
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,16 @@ New Features
11811181
:exc:`KeyError` if the key missing.
11821182
(Contributed by Stefan Behnel and Victor Stinner in :gh:`111262`.)
11831183

1184+
* Add PyTime_t C API:
1185+
1186+
* :c:type:`PyTime_t` type.
1187+
* :c:var:`PyTime_MIN` and :c:var:`PyTime_MAX` constants.
1188+
* :c:func:`PyTime_AsSecondsDouble`, :c:func:`PyTime_GetMonotonicClock`,
1189+
:c:func:`PyTime_GetPerfCounter` and :c:func:`PyTime_GetSystemClock`
1190+
functions.
1191+
1192+
(Contributed by Victor Stinner in :gh:`110850`.)
1193+
11841194

11851195
Porting to Python 3.13
11861196
----------------------

Include/Python.h

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
#include "weakrefobject.h"
9898
#include "structseq.h"
9999
#include "cpython/picklebufobject.h"
100+
#include "cpython/pytime.h"
100101
#include "codecs.h"
101102
#include "pyerrors.h"
102103
#include "pythread.h"

Include/cpython/pytime.h

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// The PyTime_t API is written to use timestamp and timeout values stored in
2+
// various formats and to read clocks.
3+
//
4+
// The PyTime_t type is an integer to support directly common arithmetic
5+
// operations like t1 + t2.
6+
//
7+
// The PyTime_t API supports a resolution of 1 nanosecond. The PyTime_t type
8+
// is signed to support negative timestamps. The supported range is around
9+
// [-292.3 years; +292.3 years]. Using the Unix epoch (January 1st, 1970), the
10+
// supported date range is around [1677-09-21; 2262-04-11].
11+
//
12+
// Formats:
13+
//
14+
// * seconds
15+
// * seconds as a floating pointer number (C double)
16+
// * milliseconds (10^-3 seconds)
17+
// * microseconds (10^-6 seconds)
18+
// * 100 nanoseconds (10^-7 seconds)
19+
// * nanoseconds (10^-9 seconds)
20+
// * timeval structure, 1 microsecond resolution (10^-6 seconds)
21+
// * timespec structure, 1 nanosecond resolution (10^-9 seconds)
22+
//
23+
// Integer overflows are detected and raise OverflowError. Conversion to a
24+
// resolution worse than 1 nanosecond is rounded correctly with the requested
25+
// rounding mode. There are 4 rounding modes: floor (towards -inf), ceiling
26+
// (towards +inf), half even and up (away from zero).
27+
//
28+
// Some functions clamp the result in the range [PyTime_MIN; PyTime_MAX], so
29+
// the caller doesn't have to handle errors and doesn't need to hold the GIL.
30+
// For example, _PyTime_Add(t1, t2) computes t1+t2 and clamp the result on
31+
// overflow.
32+
//
33+
// Clocks:
34+
//
35+
// * System clock
36+
// * Monotonic clock
37+
// * Performance counter
38+
//
39+
// Operations like (t * k / q) with integers are implemented in a way to reduce
40+
// the risk of integer overflow. Such operation is used to convert a clock
41+
// value expressed in ticks with a frequency to PyTime_t, like
42+
// QueryPerformanceCounter() with QueryPerformanceFrequency().
43+
44+
#ifndef Py_LIMITED_API
45+
#ifndef Py_PYTIME_H
46+
#define Py_PYTIME_H
47+
#ifdef __cplusplus
48+
extern "C" {
49+
#endif
50+
51+
// PyTime_t: Python timestamp with subsecond precision. It can be used to store
52+
// a duration, and so indirectly a date relative to a reference date, such as
53+
// the UNIX epoch.
54+
typedef int64_t PyTime_t;
55+
56+
// PyTime_MIN nanoseconds is around -292.3 years
57+
#define PyTime_MIN INT64_MIN
58+
59+
// PyTime_MAX nanoseconds is around +292.3 years
60+
#define PyTime_MAX INT64_MAX
61+
62+
// Convert a timestamp to a number of seconds as a C double.
63+
// The function cannot fail.
64+
PyAPI_FUNC(double) PyTime_AsSecondsDouble(PyTime_t t);
65+
66+
// Get the time of a monotonic clock, i.e. a clock that cannot go backwards.
67+
// The clock is not affected by system clock updates. The reference point of
68+
// the returned value is undefined, so that only the difference between the
69+
// results of consecutive calls is valid.
70+
//
71+
// If reading the clock fails, silently ignore the error and return 0.
72+
//
73+
// On integer overflow, silently ignore the overflow and clamp the time to the
74+
// [PyTime_MIN; PyTime_MAX] range.
75+
PyAPI_FUNC(PyTime_t) PyTime_GetMonotonicClock(void);
76+
77+
// Get the performance counter: clock with the highest available resolution to
78+
// measure a short duration.
79+
//
80+
// If reading the clock fails, silently ignore the error and return 0.
81+
//
82+
// On integer overflow, silently ignore the overflow and clamp the time to the
83+
// [PyTime_MIN; PyTime_MAX] range.
84+
PyAPI_FUNC(PyTime_t) PyTime_GetPerfCounter(void);
85+
86+
// Get the current time from the system clock.
87+
//
88+
// If reading the clock fails, silently ignore the error and return 0.
89+
//
90+
// On integer overflow, silently ignore the overflow and clamp the time to the
91+
// [PyTime_MIN; PyTime_MAX] range.
92+
PyAPI_FUNC(PyTime_t) PyTime_GetSystemClock(void);
93+
94+
#ifdef __cplusplus
95+
}
96+
#endif
97+
#endif /* Py_PYTIME_H */
98+
#endif /* Py_LIMITED_API */

0 commit comments

Comments
 (0)