cpython/Modules/timemodule.c

/* Time module */

#include "Python.h"
#include "pycore_fileutils.h"     // _Py_BEGIN_SUPPRESS_IPH
#include "pycore_moduleobject.h"  // _PyModule_GetState()
#include "pycore_namespace.h"     // _PyNamespace_New()
#include "pycore_runtime.h"       // _Py_ID()
#include "pycore_time.h"          // _PyTimeFraction

#include <time.h>                 // clock()
#ifdef HAVE_SYS_TIMES_H
#  include <sys/times.h>          // times()
#endif
#ifdef HAVE_SYS_TYPES_H
#  include <sys/types.h>
#endif
#if defined(HAVE_SYS_RESOURCE_H)
#  include <sys/resource.h>       // getrusage(RUSAGE_SELF)
#endif
#ifdef QUICKWIN
# include <io.h>
#endif
#if defined(HAVE_PTHREAD_H)
#  include <pthread.h>            // pthread_getcpuclockid()
#endif
#if defined(_AIX)
#   include <sys/thread.h>
#endif
#if defined(__WATCOMC__) && !defined(__QNX__)
#  include <i86.h>
#else
#  ifdef MS_WINDOWS
#    ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#    endif
#    include <windows.h>
#  endif /* MS_WINDOWS */
#endif /* !__WATCOMC__ || __QNX__ */

#ifdef _Py_MEMORY_SANITIZER
#  include <sanitizer/msan_interface.h>
#endif

#ifdef _MSC_VER
#define _Py_timezone
#define _Py_daylight
#define _Py_tzname
#else
#define _Py_timezone
#define _Py_daylight
#define _Py_tzname
#endif

#if defined(__APPLE__ ) && defined(__has_builtin)
#  if __has_builtin(__builtin_available)
#define HAVE_CLOCK_GETTIME_RUNTIME
#  endif
#endif
#ifndef HAVE_CLOCK_GETTIME_RUNTIME
#define HAVE_CLOCK_GETTIME_RUNTIME
#endif


#define SEC_TO_NS


/*[clinic input]
module time
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a668a08771581f36]*/


/* Forward declarations */
static int pysleep(PyTime_t timeout);


time_module_state;

static inline time_module_state*
get_time_state(PyObject *module)
{}


static PyObject*
_PyFloat_FromPyTime(PyTime_t t)
{}


static PyObject *
time_time(PyObject *self, PyObject *unused)
{}


PyDoc_STRVAR(time_doc,
"time() -> 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.");

static PyObject *
time_time_ns(PyObject *self, PyObject *unused)
{}

PyDoc_STRVAR(time_ns_doc,
"time_ns() -> int\n\
\n\
Return the current time in nanoseconds since the Epoch.");

#ifdef HAVE_CLOCK

#ifndef CLOCKS_PER_SEC
#  ifdef CLK_TCK
#define CLOCKS_PER_SEC
#  else
#define CLOCKS_PER_SEC
#  endif
#endif

static int
py_clock(time_module_state *state, PyTime_t *tp, _Py_clock_info_t *info)
{}
#endif /* HAVE_CLOCK */


#ifdef HAVE_CLOCK_GETTIME

#ifdef __APPLE__
/*
 * The clock_* functions will be removed from the module
 * dict entirely when the C API is not available.
 */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
#endif

static int
time_clockid_converter(PyObject *obj, clockid_t *p)
{}

/*[python input]

class clockid_t_converter(CConverter):
    type = "clockid_t"
    converter = 'time_clockid_converter'

[python start generated code]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=53867111501f46c8]*/


/*[clinic input]
time.clock_gettime

    clk_id: clockid_t
    /

Return the time of the specified clock clk_id as a float.
[clinic start generated code]*/

static PyObject *
time_clock_gettime_impl(PyObject *module, clockid_t clk_id)
/*[clinic end generated code: output=832b9ebc03328020 input=7e89fcc42ca15e5d]*/
{}

/*[clinic input]
time.clock_gettime_ns

    clk_id: clockid_t
    /

Return the time of the specified clock clk_id as nanoseconds (int).
[clinic start generated code]*/

static PyObject *
time_clock_gettime_ns_impl(PyObject *module, clockid_t clk_id)
/*[clinic end generated code: output=4a045c3a36e60044 input=aabc248db8c8e3e5]*/
{}
#endif   /* HAVE_CLOCK_GETTIME */

#ifdef HAVE_CLOCK_SETTIME
static PyObject *
time_clock_settime(PyObject *self, PyObject *args)
{}

PyDoc_STRVAR(clock_settime_doc,
"clock_settime(clk_id, time)\n\
\n\
Set the time of the specified clock clk_id.");

static PyObject *
time_clock_settime_ns(PyObject *self, PyObject *args)
{}

PyDoc_STRVAR(clock_settime_ns_doc,
"clock_settime_ns(clk_id, time)\n\
\n\
Set the time of the specified clock clk_id with nanoseconds.");
#endif   /* HAVE_CLOCK_SETTIME */

#ifdef HAVE_CLOCK_GETRES
static PyObject *
time_clock_getres(PyObject *self, PyObject *args)
{}

PyDoc_STRVAR(clock_getres_doc,
"clock_getres(clk_id) -> floating-point number\n\
\n\
Return the resolution (precision) of the specified clock clk_id.");

#ifdef __APPLE__
#pragma clang diagnostic pop
#endif

#endif   /* HAVE_CLOCK_GETRES */

#ifdef HAVE_PTHREAD_GETCPUCLOCKID
static PyObject *
time_pthread_getcpuclockid(PyObject *self, PyObject *args)
{}

PyDoc_STRVAR(pthread_getcpuclockid_doc,
"pthread_getcpuclockid(thread_id) -> int\n\
\n\
Return the clk_id of a thread's CPU time clock.");
#endif /* HAVE_PTHREAD_GETCPUCLOCKID */

static PyObject *
time_sleep(PyObject *self, PyObject *timeout_obj)
{}

PyDoc_STRVAR(sleep_doc,
"sleep(seconds)\n\
\n\
Delay execution for a given number of seconds.  The argument may be\n\
a floating-point number for subsecond precision.");

static PyStructSequence_Field struct_time_type_fields[] =;

static PyStructSequence_Desc struct_time_type_desc =;

#if defined(MS_WINDOWS)
#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
  #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
#endif

static DWORD timer_flags = (DWORD)-1;
#endif

static PyObject *
tmtotuple(time_module_state *state, struct tm *p
#ifndef HAVE_STRUCT_TM_TM_ZONE
        , const char *zone, time_t gmtoff
#endif
)
{}

/* Parse arg tuple that can contain an optional float-or-None value;
   format needs to be "|O:name".
   Returns non-zero on success (parallels PyArg_ParseTuple).
*/
static int
parse_time_t_args(PyObject *args, const char *format, time_t *pwhen)
{}

static PyObject *
time_gmtime(PyObject *module, PyObject *args)
{}

#ifndef HAVE_TIMEGM
static time_t
timegm(struct tm *p)
{
    /* XXX: the following implementation will not work for tm_year < 1970.
       but it is likely that platforms that don't have timegm do not support
       negative timestamps anyways. */
    return p->tm_sec + p->tm_min*60 + p->tm_hour*3600 + p->tm_yday*86400 +
        (p->tm_year-70)*31536000 + ((p->tm_year-69)/4)*86400 -
        ((p->tm_year-1)/100)*86400 + ((p->tm_year+299)/400)*86400;
}
#endif

PyDoc_STRVAR(gmtime_doc,
"gmtime([seconds]) -> (tm_year, tm_mon, tm_mday, tm_hour, tm_min,\n\
                       tm_sec, tm_wday, tm_yday, tm_isdst)\n\
\n\
Convert seconds since the Epoch to a time tuple expressing UTC (a.k.a.\n\
GMT).  When 'seconds' is not passed in, convert the current time instead.\n\
\n\
If the platform supports the tm_gmtoff and tm_zone, they are available as\n\
attributes only.");

static PyObject *
time_localtime(PyObject *module, PyObject *args)
{}

#if defined(__linux__) && !defined(__GLIBC__)
static const char *utc_string = NULL;
#endif

PyDoc_STRVAR(localtime_doc,
"localtime([seconds]) -> (tm_year,tm_mon,tm_mday,tm_hour,tm_min,\n\
                          tm_sec,tm_wday,tm_yday,tm_isdst)\n\
\n\
Convert seconds since the Epoch to a time tuple expressing local time.\n\
When 'seconds' is not passed in, convert the current time instead.");

/* Convert 9-item tuple to tm structure.  Return 1 on success, set
 * an exception and return 0 on error.
 */
static int
gettmarg(time_module_state *state, PyObject *args,
         struct tm *p, const char *format)
{}

/* Check values of the struct tm fields before it is passed to strftime() and
 * asctime().  Return 1 if all values are valid, otherwise set an exception
 * and returns 0.
 */
static int
checktm(struct tm* buf)
{}

#ifdef MS_WINDOWS
   /* wcsftime() doesn't format correctly time zones, see issue #10653 */
#  undef HAVE_WCSFTIME
#endif
#define STRFTIME_FORMAT_CODES

#ifdef HAVE_STRFTIME
#ifdef HAVE_WCSFTIME
#define time_char
#define format_time
#define time_strlen
#else
#define time_char
#define format_time
#define time_strlen
#endif

static PyObject *
time_strftime(PyObject *module, PyObject *args)
{}

#undef time_char
#undef format_time
PyDoc_STRVAR(strftime_doc,
"strftime(format[, tuple]) -> string\n\
\n\
Convert a time tuple to a string according to a format specification.\n\
See the library reference manual for formatting codes. When the time tuple\n\
is not present, current time as returned by localtime() is used.\n\
\n" STRFTIME_FORMAT_CODES);
#endif /* HAVE_STRFTIME */

static PyObject *
time_strptime(PyObject *self, PyObject *args)
{}


PyDoc_STRVAR(strptime_doc,
"strptime(string, format) -> struct_time\n\
\n\
Parse a string to a time tuple according to a format specification.\n\
See the library reference manual for formatting codes (same as\n\
strftime()).\n\
\n" STRFTIME_FORMAT_CODES);

static PyObject *
_asctime(struct tm *timeptr)
{}

static PyObject *
time_asctime(PyObject *module, PyObject *args)
{}

PyDoc_STRVAR(asctime_doc,
"asctime([tuple]) -> string\n\
\n\
Convert a time tuple to a string, e.g. 'Sat Jun 06 16:26:11 1998'.\n\
When the time tuple is not present, current time as returned by localtime()\n\
is used.");

static PyObject *
time_ctime(PyObject *self, PyObject *args)
{}

PyDoc_STRVAR(ctime_doc,
"ctime(seconds) -> string\n\
\n\
Convert a time in seconds since the Epoch to a string in local time.\n\
This is equivalent to asctime(localtime(seconds)). When the time tuple is\n\
not present, current time as returned by localtime() is used.");

#ifdef HAVE_MKTIME
static PyObject *
time_mktime(PyObject *module, PyObject *tm_tuple)
{}

PyDoc_STRVAR(mktime_doc,
"mktime(tuple) -> floating-point number\n\
\n\
Convert a time tuple in local time to seconds since the Epoch.\n\
Note that mktime(gmtime(0)) will not generally return zero for most\n\
time zones; instead the returned value will either be equal to that\n\
of the timezone or altzone attributes on the time module.");
#endif /* HAVE_MKTIME */

#ifdef HAVE_WORKING_TZSET
static int init_timezone(PyObject *module);

static PyObject *
time_tzset(PyObject *self, PyObject *unused)
{}

PyDoc_STRVAR(tzset_doc,
"tzset()\n\
\n\
Initialize, or reinitialize, the local timezone to the value stored in\n\
os.environ['TZ']. The TZ environment variable should be specified in\n\
standard Unix timezone format as documented in the tzset man page\n\
(eg. 'US/Eastern', 'Europe/Amsterdam'). Unknown timezones will silently\n\
fall back to UTC. If the TZ environment variable is not set, the local\n\
timezone is set to the systems best guess of wallclock time.\n\
Changing the TZ environment variable without calling tzset *may* change\n\
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_monotonic(PyObject *self, PyObject *unused)
{}

PyDoc_STRVAR(monotonic_doc,
"monotonic() -> float\n\
\n\
Monotonic clock, cannot go backward.");

static PyObject *
time_monotonic_ns(PyObject *self, PyObject *unused)
{}

PyDoc_STRVAR(monotonic_ns_doc,
"monotonic_ns() -> int\n\
\n\
Monotonic clock, cannot go backward, as nanoseconds.");


static PyObject *
time_perf_counter(PyObject *self, PyObject *unused)
{}

PyDoc_STRVAR(perf_counter_doc,
"perf_counter() -> float\n\
\n\
Performance counter for benchmarking.");


static PyObject *
time_perf_counter_ns(PyObject *self, PyObject *unused)
{}

PyDoc_STRVAR(perf_counter_ns_doc,
"perf_counter_ns() -> int\n\
\n\
Performance counter for benchmarking as nanoseconds.");


// gh-115714: Don't use times() on WASI.
#if defined(HAVE_TIMES) && !defined(__wasi__)
static int
process_time_times(time_module_state *state, PyTime_t *tp,
                   _Py_clock_info_t *info)
{}
#endif


static int
py_process_time(time_module_state *state, PyTime_t *tp,
                _Py_clock_info_t *info)
{}

static PyObject *
time_process_time(PyObject *module, PyObject *unused)
{}

PyDoc_STRVAR(process_time_doc,
"process_time() -> float\n\
\n\
Process time for profiling: sum of the kernel and user-space CPU time.");

static PyObject *
time_process_time_ns(PyObject *module, PyObject *unused)
{}

PyDoc_STRVAR(process_time_ns_doc,
"process_time() -> int\n\
\n\
Process time for profiling as nanoseconds:\n\
sum of the kernel and user-space CPU time.");


#if defined(MS_WINDOWS)
#define HAVE_THREAD_TIME
static int
_PyTime_GetThreadTimeWithInfo(PyTime_t *tp, _Py_clock_info_t *info)
{
    HANDLE thread;
    FILETIME creation_time, exit_time, kernel_time, user_time;
    ULARGE_INTEGER large;
    PyTime_t ktime, utime;
    BOOL ok;

    thread =  GetCurrentThread();
    ok = GetThreadTimes(thread, &creation_time, &exit_time,
                        &kernel_time, &user_time);
    if (!ok) {
        PyErr_SetFromWindowsErr(0);
        return -1;
    }

    if (info) {
        info->implementation = "GetThreadTimes()";
        info->resolution = 1e-7;
        info->monotonic = 1;
        info->adjustable = 0;
    }

    large.u.LowPart = kernel_time.dwLowDateTime;
    large.u.HighPart = kernel_time.dwHighDateTime;
    ktime = large.QuadPart;

    large.u.LowPart = user_time.dwLowDateTime;
    large.u.HighPart = user_time.dwHighDateTime;
    utime = large.QuadPart;

    /* ktime and utime have a resolution of 100 nanoseconds */
    *tp = (ktime + utime) * 100;
    return 0;
}

#elif defined(_AIX)
#define HAVE_THREAD_TIME
static int
_PyTime_GetThreadTimeWithInfo(PyTime_t *tp, _Py_clock_info_t *info)
{
    /* bpo-40192: On AIX, thread_cputime() is preferred: it has nanosecond
       resolution, whereas clock_gettime(CLOCK_THREAD_CPUTIME_ID)
       has a resolution of 10 ms. */
    thread_cputime_t tc;
    if (thread_cputime(-1, &tc) != 0) {
        PyErr_SetFromErrno(PyExc_OSError);
        return -1;
    }

    if (info) {
        info->implementation = "thread_cputime()";
        info->monotonic = 1;
        info->adjustable = 0;
        info->resolution = 1e-9;
    }
    *tp = (tc.stime + tc.utime);
    return 0;
}

#elif defined(__sun) && defined(__SVR4)
#define HAVE_THREAD_TIME
static int
_PyTime_GetThreadTimeWithInfo(PyTime_t *tp, _Py_clock_info_t *info)
{
    /* bpo-35455: On Solaris, CLOCK_THREAD_CPUTIME_ID clock is not always
       available; use gethrvtime() to substitute this functionality. */
    if (info) {
        info->implementation = "gethrvtime()";
        info->resolution = 1e-9;
        info->monotonic = 1;
        info->adjustable = 0;
    }
    *tp = gethrvtime();
    return 0;
}

/* CLOCK_THREAD_CPUTIME_ID is broken on NetBSD: the result of clock_gettime()
 * includes the sleeping time, that defeats the purpose of the clock.
 * Also, clock_getres() does not support it.
 * https://github.com/python/cpython/issues/123978
 * https://gnats.netbsd.org/57512
 */
#elif defined(HAVE_CLOCK_GETTIME) && \
      defined(CLOCK_THREAD_CPUTIME_ID) && \
      !defined(__EMSCRIPTEN__) && !defined(__wasi__) && \
      !defined(__NetBSD__)
#define HAVE_THREAD_TIME

#if defined(__APPLE__) && _Py__has_attribute(availability)
static int
_PyTime_GetThreadTimeWithInfo(PyTime_t *tp, _Py_clock_info_t *info)
     __attribute__((availability(macos, introduced=10.12)))
     __attribute__((availability(ios, introduced=10.0)))
     __attribute__((availability(tvos, introduced=10.0)))
     __attribute__((availability(watchos, introduced=3.0)));
#endif

static int
_PyTime_GetThreadTimeWithInfo(PyTime_t *tp, _Py_clock_info_t *info)
{}
#endif

#ifdef HAVE_THREAD_TIME
#ifdef __APPLE__
/*
 * The clock_* functions will be removed from the module
 * dict entirely when the C API is not available.
 */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
#endif

static PyObject *
time_thread_time(PyObject *self, PyObject *unused)
{}

PyDoc_STRVAR(thread_time_doc,
"thread_time() -> float\n\
\n\
Thread time for profiling: sum of the kernel and user-space CPU time.");

static PyObject *
time_thread_time_ns(PyObject *self, PyObject *unused)
{}

PyDoc_STRVAR(thread_time_ns_doc,
"thread_time() -> int\n\
\n\
Thread time for profiling as nanoseconds:\n\
sum of the kernel and user-space CPU time.");

#ifdef __APPLE__
#pragma clang diagnostic pop
#endif

#endif


static PyObject *
time_get_clock_info(PyObject *module, PyObject *args)
{}

PyDoc_STRVAR(get_clock_info_doc,
"get_clock_info(name: str) -> dict\n\
\n\
Get information of the specified clock.");

#ifndef HAVE_DECL_TZNAME
static void
get_zone(char *zone, int n, struct tm *p)
{}

static time_t
get_gmtoff(time_t t, struct tm *p)
{}
#endif // !HAVE_DECL_TZNAME

static int
init_timezone(PyObject *m)
{}


// Include Argument Clinic code after defining converters such as
// time_clockid_converter().
#include "clinic/timemodule.c.h"

static PyMethodDef time_methods[] =;


PyDoc_STRVAR(module_doc,
"This module provides various functions to manipulate time values.\n\
\n\
There are two standard representations of time.  One is the number\n\
of seconds since the Epoch, in UTC (a.k.a. GMT).  It may be an integer\n\
or a floating-point number (to represent fractions of seconds).\n\
The epoch is the point where the time starts, the return value of time.gmtime(0).\n\
It is January 1, 1970, 00:00:00 (UTC) on all platforms.\n\
\n\
The other representation is a tuple of 9 integers giving local time.\n\
The tuple items are:\n\
  year (including century, e.g. 1998)\n\
  month (1-12)\n\
  day (1-31)\n\
  hours (0-23)\n\
  minutes (0-59)\n\
  seconds (0-59)\n\
  weekday (0-6, Monday is 0)\n\
  Julian day (day in the year, 1-366)\n\
  DST (Daylight Savings Time) flag (-1, 0 or 1)\n\
If the DST flag is 0, the time is given in the regular time zone;\n\
if it is 1, the time is given in the DST time zone;\n\
if it is -1, mktime() should guess based on the date and time.\n");


static int
time_exec(PyObject *module)
{}


static int
time_module_traverse(PyObject *module, visitproc visit, void *arg)
{}


static int
time_module_clear(PyObject *module)
{}


static void
time_module_free(void *module)
{}


static struct PyModuleDef_Slot time_slots[] =;

static struct PyModuleDef timemodule =;

PyMODINIT_FUNC
PyInit_time(void)
{}


// time.sleep() implementation.
// On error, raise an exception and return -1.
// On success, return 0.
static int
pysleep(PyTime_t timeout)
{}