diff -r 555f5fe53341 Doc/library/time.rst --- a/Doc/library/time.rst Tue Apr 03 09:16:46 2012 +0200 +++ b/Doc/library/time.rst Tue Apr 03 13:52:43 2012 +0200 @@ -136,6 +136,8 @@ The module defines the following functio :c:func:`QueryPerformanceCounter`. The resolution is typically better than one microsecond. + See also :func:`time.highres` and :func:`os.times`. + .. function:: clock_getres(clk_id) @@ -220,6 +222,32 @@ The module defines the following functio Nonzero if a DST timezone is defined. +.. function:: get_clock_info(name) + + Get information on the specified clock. Supported clocks: + + * ``'clock'``: :func:`time.clock` + * ``'highres'``: :func:`time.highres` + * ``'steady'``: :func:`time.monotonic` + * ``'time'``: :func:`time.time` + + Return a dictionary with the following keys: + + * Mandatory keys + + * ``'function'`` (:class:`str`): name of the underlying C function used + to get the clock value + * ``'is_monotonic'`` (:class:`bool`): ``True`` if the clock cannot go + backward, ``False`` otherwise + * ``'resolution'`` (:class:`float`): Clock resolution in seconds + + * Optional keys + + * ``'accuracy'`` (:class:`float`): Clock accuracy in seconds + * ``'is_adjusted'`` (:class:`bool`): ``True`` if the clock can be + adjusted (e.g. by a NTP daemon) + + .. function:: gmtime([secs]) Convert a time expressed in seconds since the epoch to a :class:`struct_time` in @@ -230,6 +258,23 @@ The module defines the following functio function. +.. function:: highres() + + .. index:: + single: benchmarking + + Clock with the highest available resolution. Monotonic clock, or falls back + to the system clock if no monotonic clock is available. It may be less + stable than :func:`steady` clock. + + Use ``time.get_clock_info('highres')['is_monotonic']`` to check if the clock + is monotonic. + + See also :func:`time.clock`, :func:`time.steady` and :func:`os.times`. + + .. versionadded:: 3.3 + + .. function:: localtime([secs]) Like :func:`gmtime` but converts to local time. If *secs* is not provided or @@ -249,24 +294,6 @@ The module defines the following functio The earliest date for which it can generate a time is platform-dependent. -.. function:: steady(strict=False) - - .. index:: - single: benchmarking - - Return the current time as a floating point number expressed in seconds. - This clock advances at a steady rate relative to real time and it may not be - adjusted. The reference point of the returned value is undefined so only the - difference of consecutive calls is valid. - - If available, a monotonic clock is used. By default, - the function falls back to another clock if the monotonic clock failed or is - not available. If *strict* is True, raise an :exc:`OSError` on error or - :exc:`NotImplementedError` if no monotonic clock is available. - - .. versionadded:: 3.3 - - .. function:: sleep(secs) Suspend execution for the given number of seconds. The argument may be a @@ -277,6 +304,23 @@ The module defines the following functio amount because of the scheduling of other activity in the system. +.. function:: steady() + + Most steady available clock. Use a monotonic clock, or falls back to the + system clock if no monotonic clock is available. + + Return the current time as a floating point number expressed in seconds. + The reference point of the returned value is undefined so only the + difference of consecutive calls is valid. + + Use ``time.get_clock_info('steady')['is_monotonic']`` to check if the + clock is monotonic. + + If you need a higher resolution clock, use :func:`time.highres`. + + .. versionadded:: 3.3 + + .. function:: strftime(format[, t]) Convert a tuple or :class:`struct_time` representing a time as returned by diff -r 555f5fe53341 Include/pytime.h --- a/Include/pytime.h Tue Apr 03 09:16:46 2012 +0200 +++ b/Include/pytime.h Tue Apr 03 13:52:43 2012 +0200 @@ -22,11 +22,29 @@ typedef struct { } _PyTime_timeval; #endif +/* Structure used by time.get_clock_info() */ +typedef struct { + /* mandatory */ + const char *function; + double resolution; + int is_monotonic; + int is_steady; + /* optional */ + double accuracy; /* -1.0 if unknown */ + int is_adjusted; /* -1 if unknown */ +} _Py_clock_info_t; + /* Similar to POSIX gettimeofday but cannot fail. If system gettimeofday * fails or is not available, fall back to lower resolution clocks. */ PyAPI_FUNC(void) _PyTime_gettimeofday(_PyTime_timeval *tp); +/* Similar to _PyTime_gettimeofday() but retrieve also information on the + * clock used to get the current time. */ +PyAPI_FUNC(void) _PyTime_gettimeofday_info( + _PyTime_timeval *tp, + _Py_clock_info_t *info); + #define _PyTime_ADD_SECONDS(tv, interval) \ do { \ tv.tv_usec += (long) (((long) interval - interval) * 1000000); \ diff -r 555f5fe53341 Lib/test/test_time.py --- a/Lib/test/test_time.py Tue Apr 03 09:16:46 2012 +0200 +++ b/Lib/test/test_time.py Tue Apr 03 13:52:43 2012 +0200 @@ -342,24 +342,19 @@ class TimeTestCase(unittest.TestCase): pass self.assertEqual(time.strftime('%Z', tt), tzname) - def test_steady(self): - t1 = time.steady() - time.sleep(0.1) - t2 = time.steady() - dt = t2 - t1 - # may fail if the system clock was changed - self.assertGreater(t2, t1) - self.assertAlmostEqual(dt, 0.1, delta=0.2) + def test_monotonic(self): + info = time.get_clock_info('steady') - def test_steady_strict(self): - try: - t1 = time.steady(strict=True) - except OSError as err: - self.skipTest("the monotonic clock failed: %s" % err) - except NotImplementedError: - self.skipTest("no monotonic clock available") - t2 = time.steady(strict=True) - self.assertGreaterEqual(t2, t1) + if info['is_monotonic']: + t1 = time.steady() + time.sleep(0.1) + t2 = time.steady() + dt = t2 - t1 + self.assertGreater(t2, t1) + self.assertAlmostEqual(dt, 0.1, delta=0.2) + else: + # just check that it does not raise an OSError + time.steady() def test_localtime_failure(self): # Issue #13847: check for localtime() failure @@ -378,6 +373,28 @@ class TimeTestCase(unittest.TestCase): self.assertRaises(OSError, time.localtime, invalid_time_t) self.assertRaises(OSError, time.ctime, invalid_time_t) + def test_get_clock_info(self): + for name in ('clock', 'highres', 'steady', 'time'): + info = time.get_clock_info(name) + self.assertIsInstance(info, dict) + self.assertIsInstance(info['function'], str) + self.assertNotEqual(info['function'], '') + self.assertIsInstance(info['is_monotonic'], bool) + self.assertIsInstance(info['resolution'], float) + # 0 < resolution <= 1.0 + self.assertGreater(info['resolution'], 0) + self.assertLessEqual(info['resolution'], 1) + if 'accuracy' in info: + self.assertIsInstance(info['accuracy'], float) + # 0 < accuracy <= 1.0 + self.assertGreater(info['accuracy'], 0) + self.assertLessEqual(info['accuracy'], 1) + if 'is_adjusted' in info: + self.assertIsInstance(info['is_adjusted'], bool) + + self.assertRaises(ValueError, time.get_clock_info, 'xxx') + + class TestLocale(unittest.TestCase): def setUp(self): self.oldloc = locale.setlocale(locale.LC_ALL) diff -r 555f5fe53341 Modules/timemodule.c --- a/Modules/timemodule.c Tue Apr 03 09:16:46 2012 +0200 +++ b/Modules/timemodule.c Tue Apr 03 13:52:43 2012 +0200 @@ -45,12 +45,16 @@ /* Forward declarations */ static int floatsleep(double); -static PyObject* floattime(void); +static PyObject* floattime(_Py_clock_info_t *info); + +#ifdef MS_WINDOWS +static OSVERSIONINFOEX winver; +#endif static PyObject * time_time(PyObject *self, PyObject *unused) { - return floattime(); + return floattime(NULL); } PyDoc_STRVAR(time_doc, @@ -70,7 +74,7 @@ Fractions of a second may be present if #endif static PyObject * -pyclock(void) +pyclock(_Py_clock_info_t *info) { clock_t value; value = clock(); @@ -80,6 +84,13 @@ pyclock(void) "or its value cannot be represented"); return NULL; } + if (info) { + info->function = "clock()"; + info->resolution = 1.0 / (double)CLOCKS_PER_SEC; + info->accuracy = info->resolution; + info->is_monotonic = 1; + info->is_adjusted = 0; + } return PyFloat_FromDouble((double)value / CLOCKS_PER_SEC); } #endif /* HAVE_CLOCK */ @@ -88,7 +99,7 @@ pyclock(void) /* Win32 has better clock replacement; we have our own version, due to Mark Hammond and Tim Peters */ static PyObject * -win32_clock(int fallback) +win32_clock(_Py_clock_info_t *info) { static LONGLONG cpu_frequency = 0; static LONGLONG ctrStart; @@ -102,15 +113,19 @@ win32_clock(int fallback) 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); + return pyclock(info); } cpu_frequency = freq.QuadPart; } QueryPerformanceCounter(&now); diff = (double)(now.QuadPart - ctrStart); + if (info) { + info->function = "QueryPerformanceCounter()"; + info->resolution = 1.0 / (double)cpu_frequency; + info->accuracy = info->resolution; + info->is_monotonic = 1; + info->is_adjusted = 0; + } return PyFloat_FromDouble(diff / (double)cpu_frequency); } #endif @@ -120,9 +135,9 @@ static PyObject * time_clock(PyObject *self, PyObject *unused) { #if defined(MS_WINDOWS) && !defined(__BORLANDC__) - return win32_clock(1); + return win32_clock(NULL); #else - return pyclock(); + return pyclock(NULL); #endif } @@ -789,11 +804,82 @@ the local timezone used by methods such should not be relied on."); #endif /* HAVE_WORKING_TZSET */ +#if defined(MS_WINDOWS) static PyObject* -steady_clock(int strict) +win32_get_ticks(_Py_clock_info_t *info) +{ + static ULONGLONG (*GetTickCount64) (void) = NULL; + static ULONGLONG (CALLBACK *Py_GetTickCount64)(void); + static int has_getickcount64 = 0; + + if (has_getickcount64 == -1) { + /* GetTickCount64() was added to Windows Vista */ + if (winver.dwMajorVersion >= 6) { + HINSTANCE hKernel32; + hKernel32 = GetModuleHandleW(L"KERNEL32"); + *(FARPROC*)&Py_GetTickCount64 = GetProcAddress(hKernel32, + "GetTickCount64"); + has_getickcount64 = (Py_GetTickCount64 != NULL); + } + else + has_getickcount64 = 0; + } + + if (has_getickcount64) { + ULONGLONG ticks; + ticks = Py_GetTickCount64(); + if (info) { + DWORD timeAdjustment, timeIncrement; + BOOL isTimeAdjustmentDisabled; + info->function = "GetTickCount64()"; + info->is_monotonic = 1; + info->resolution = 1e-3; + (void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled); + info->accuracy = timeIncrement * 1e-7; + info->is_adjusted = 0; + } + return PyFloat_FromDouble((double)ticks * 1e-3); + } + else { + static DWORD last_ticks; + static int has_last_ticks = 0; + static DWORD n_overflow = 0; + DWORD ticks; + double result; + + ticks = GetTickCount(); + if (has_last_ticks && ticks < last_ticks) + n_overflow++; + last_ticks = ticks; + has_last_ticks = 1; + + result = ldexp(n_overflow, 32); + result += ticks; + result *= 1e-3; + + if (info) { + DWORD timeAdjustment, timeIncrement; + BOOL isTimeAdjustmentDisabled; + info->function = "GetTickCount()"; + info->is_monotonic = 1; + info->resolution = 1e-3; + (void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled); + info->accuracy = timeIncrement * 1e-7; + info->is_adjusted = 0; + } + return PyFloat_FromDouble(result); + } +} +#endif + +static PyObject* +steady_clock(int highres, _Py_clock_info_t *info) { #if defined(MS_WINDOWS) && !defined(__BORLANDC__) - return win32_clock(!strict); + if (highres) + return win32_clock(info); + else + return win32_get_ticks(info); #elif defined(__APPLE__) static mach_timebase_info_data_t timebase; uint64_t time; @@ -807,87 +893,187 @@ steady_clock(int strict) time = mach_absolute_time(); secs = (double)time * timebase.numer / timebase.denom * 1e-9; - + if (info) { + info->function = "mach_absolute_time()"; + info->resolution = 1e-9; + info->is_monotonic = 1; + info->is_adjusted = 0; + } return PyFloat_FromDouble(secs); #elif defined(HAVE_CLOCK_GETTIME) - static int steady_clk_index = 0; - static int monotonic_clk_index = 0; - int *clk_index; - clockid_t steady_clk_ids[] = { -#ifdef CLOCK_MONOTONIC_RAW - CLOCK_MONOTONIC_RAW, + static int clk_index = 0; + clockid_t clk_ids[] = { +#ifdef CLOCK_HIGHRES + CLOCK_HIGHRES, #endif CLOCK_MONOTONIC, - CLOCK_REALTIME }; - clockid_t monotonic_clk_ids[] = { -#ifdef CLOCK_MONOTONIC_RAW - CLOCK_MONOTONIC_RAW, -#endif - CLOCK_MONOTONIC - }; - clockid_t *clk_ids; - int clk_ids_len; int ret; struct timespec tp; - if (strict) { - clk_index = &monotonic_clk_index; - clk_ids = monotonic_clk_ids; - clk_ids_len = Py_ARRAY_LENGTH(monotonic_clk_ids); + while (0 <= clk_index) { + clockid_t clk_id = clk_ids[clk_index]; + ret = clock_gettime(clk_id, &tp); + if (ret == 0) { + if (info) { + struct timespec res; +#ifdef CLOCK_HIGHRES + if (clk_id == CLOCK_HIGHRES) { + info->function = "clock_gettime(CLOCK_HIGHRES)"; + info->is_monotonic = 1; + info->is_adjusted = 0; + } + else +#endif + if (clk_id == CLOCK_MONOTONIC) { + info->function = "clock_gettime(CLOCK_MONOTONIC)"; + info->is_monotonic = 1; +#if defined(linux) || defined(__linux) || defined(__linux__) + info->is_adjusted = 1; +#endif + } + else { + assert(clk_id == CLOCK_REALTIME); + info->function = "clock_gettime(CLOCK_REALTIME)"; + info->is_monotonic = 0; + info->is_adjusted = 1; + } + info->resolution = 1e-9; + if (clock_getres(clk_id, &res) != 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + info->accuracy = res.tv_sec + res.tv_nsec * 1e-9; + } + return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); + } + + clk_index++; + if (Py_ARRAY_LENGTH(clk_ids) <= clk_index) + clk_index = -1; } - else { - clk_index = &steady_clk_index; - clk_ids = steady_clk_ids; - clk_ids_len = Py_ARRAY_LENGTH(steady_clk_ids); - } - - 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); - - (*clk_index)++; - if (clk_ids_len <= *clk_index) - (*clk_index) = -1; - } - if (strict) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - return floattime(); + return floattime(info); #else - if (strict) { - PyErr_SetString(PyExc_NotImplementedError, - "no steady clock available on your platform"); - return NULL; - } - return floattime(); + return floattime(info); #endif } static PyObject * -time_steady(PyObject *self, PyObject *args, PyObject *kwargs) +time_highres(PyObject *self, PyObject *unused) { - static char *kwlist[] = {"strict", NULL}; - int strict = 0; + return steady_clock(1, NULL); +} - if (!PyArg_ParseTupleAndKeywords( - args, kwargs, "|i:steady", kwlist, - &strict)) +PyDoc_STRVAR(highres_doc, +"highres() -> float\n\ +\n\ +Clock with the highest available resolution."); + +static PyObject * +time_get_clock_info(PyObject *self, PyObject *args) +{ + char *name; + PyObject *dict, *obj; + int err; + _Py_clock_info_t info; + + if (!PyArg_ParseTuple(args, "s:get_clock_info", &name)) return NULL; - return steady_clock(strict); + info.accuracy = -1.0; + info.is_adjusted = -1; + + if (strcmp(name, "clock") == 0) { +#if defined(MS_WINDOWS) && !defined(__BORLANDC__) + obj = win32_clock(&info); +#else + obj = pyclock(&info); +#endif + } + else if (strcmp(name, "highres") == 0) + obj = steady_clock(1, &info); + else if (strcmp(name, "steady") == 0) + obj = steady_clock(0, &info); + else if (strcmp(name, "time") == 0) + obj = floattime(&info); + else { + PyErr_SetString(PyExc_ValueError, "unknown clock"); + return NULL; + } + if (obj == NULL) + return NULL; + Py_DECREF(obj); + + dict = PyDict_New(); + if (dict == NULL) + return NULL; + + obj = PyUnicode_FromString(info.function); + if (obj == NULL) + goto error; + err = PyDict_SetItemString(dict, "function", obj); + Py_DECREF(obj); + if (err) + goto error; + + obj = PyFloat_FromDouble(info.resolution); + if (obj == NULL) + goto error; + err = PyDict_SetItemString(dict, "resolution", obj); + Py_DECREF(obj); + if (err) + goto error; + + obj = PyBool_FromLong(info.is_monotonic); + if (obj == NULL) + goto error; + err = PyDict_SetItemString(dict, "is_monotonic", obj); + Py_DECREF(obj); + if (err) + goto error; + + if (info.accuracy != -1.0) { + obj = PyFloat_FromDouble(info.accuracy); + if (obj == NULL) + goto error; + err = PyDict_SetItemString(dict, "accuracy", obj); + Py_DECREF(obj); + if (err) + goto error; + } + + if (info.is_adjusted != -1) { + obj = PyBool_FromLong(info.is_adjusted); + if (obj == NULL) + goto error; + err = PyDict_SetItemString(dict, "is_adjusted", obj); + Py_DECREF(obj); + if (err) + goto error; + } + + return dict; + +error: + Py_DECREF(dict); + return NULL; } -PyDoc_STRVAR(steady_doc, -"steady(strict=False) -> float\n\ +PyDoc_STRVAR(get_clock_info_doc, +"get_clock_info(name: str) -> dict\n\ \n\ -Return the current time as a floating point number expressed in seconds.\n\ -This clock advances at a steady rate relative to real time and it may not\n\ -be adjusted. The reference point of the returned value is undefined so only\n\ -the difference of consecutive calls is valid."); +Get information of the specified clock."); + +static PyObject * +time_steady(PyObject *self, PyObject *unused) +{ + return steady_clock(0, NULL); +} + +PyDoc_STRVAR(monotonic_doc, +"steady() -> float\n\ +\n\ +Most steady available clock."); static void @@ -1024,8 +1210,6 @@ static PyMethodDef time_methods[] = { #ifdef HAVE_MKTIME {"mktime", time_mktime, METH_O, mktime_doc}, #endif - {"steady", (PyCFunction)time_steady, METH_VARARGS|METH_KEYWORDS, - steady_doc}, #ifdef HAVE_STRFTIME {"strftime", time_strftime, METH_VARARGS, strftime_doc}, #endif @@ -1033,6 +1217,9 @@ static PyMethodDef time_methods[] = { #ifdef HAVE_WORKING_TZSET {"tzset", time_tzset, METH_NOARGS, tzset_doc}, #endif + {"steady", time_steady, METH_NOARGS, monotonic_doc}, + {"highres", time_highres, METH_NOARGS, highres_doc}, + {"get_clock_info", time_get_clock_info, METH_VARARGS, get_clock_info_doc}, {NULL, NULL} /* sentinel */ }; @@ -1110,6 +1297,15 @@ PyInit_time(void) if (!initialized) { PyStructSequence_InitType(&StructTimeType, &struct_time_type_desc); + +#ifdef MS_WINDOWS + winver.dwOSVersionInfoSize = sizeof(winver); + if (!GetVersionEx((OSVERSIONINFO*)&winver)) { + Py_DECREF(m); + PyErr_SetFromWindowsErr(0); + return NULL; + } +#endif } Py_INCREF(&StructTimeType); PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType); @@ -1118,7 +1314,7 @@ PyInit_time(void) } static PyObject* -floattime(void) +floattime(_Py_clock_info_t *info) { _PyTime_timeval t; #ifdef HAVE_CLOCK_GETTIME @@ -1129,10 +1325,23 @@ floattime(void) because it would require to link Python to the rt (real-time) library, at least on Linux */ ret = clock_gettime(CLOCK_REALTIME, &tp); - if (ret == 0) + if (ret == 0) { + if (info) { + struct timespec res; + info->function = "clock_gettime(CLOCK_REALTIME)"; + info->is_monotonic = 0; + info->is_adjusted = 1; + info->resolution = 1e-9; + if (clock_getres(CLOCK_REALTIME, &res) != 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + info->accuracy = res.tv_sec + res.tv_nsec * 1e-9; + } return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); + } #endif - _PyTime_gettimeofday(&t); + _PyTime_gettimeofday_info(&t, info); return PyFloat_FromDouble((double)t.tv_sec + t.tv_usec * 1e-6); } diff -r 555f5fe53341 Python/pytime.c --- a/Python/pytime.c Tue Apr 03 09:16:46 2012 +0200 +++ b/Python/pytime.c Tue Apr 03 13:52:43 2012 +0200 @@ -18,8 +18,8 @@ extern int ftime(struct timeb *); #endif -void -_PyTime_gettimeofday(_PyTime_timeval *tp) +static void +pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info) { #ifdef MS_WINDOWS FILETIME system_time; @@ -35,6 +35,20 @@ _PyTime_gettimeofday(_PyTime_timeval *tp microseconds = large.QuadPart / 10 - 11644473600000000; tp->tv_sec = microseconds / 1000000; tp->tv_usec = microseconds % 1000000; + if (info) { + DWORD timeAdjustment, timeIncrement; + BOOL isTimeAdjustmentDisabled; + + info->function = "GetSystemTimeAsFileTime()"; + info->resolution = 1e-7; + info->is_monotonic = 0; + (void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled); + info->accuracy = timeIncrement * 1e-7; + if (isTimeAdjustmentDisabled) + info->is_adjusted = 0; + else + info->is_adjusted = 1; + } #else /* There are three ways to get the time: (1) gettimeofday() -- resolution in microseconds @@ -47,11 +61,25 @@ _PyTime_gettimeofday(_PyTime_timeval *tp #ifdef HAVE_GETTIMEOFDAY #ifdef GETTIMEOFDAY_NO_TZ - if (gettimeofday(tp) == 0) + if (gettimeofday(tp) == 0) { + if (info) { + info->function = "gettimeofday()"; + info->resolution = 1e-6; + info->is_monotonic = 0; + info->is_adjusted = 1; + } return; + } #else /* !GETTIMEOFDAY_NO_TZ */ - if (gettimeofday(tp, (struct timezone *)NULL) == 0) + if (gettimeofday(tp, (struct timezone *)NULL) == 0) { + if (info) { + info->function = "gettimeofday()"; + info->resolution = 1e-6; + info->is_monotonic = 0; + info->is_adjusted = 1; + } return; + } #endif /* !GETTIMEOFDAY_NO_TZ */ #endif /* !HAVE_GETTIMEOFDAY */ @@ -61,15 +89,41 @@ _PyTime_gettimeofday(_PyTime_timeval *tp ftime(&t); tp->tv_sec = t.time; tp->tv_usec = t.millitm * 1000; + if (info) { + info->function = "ftime()"; + info->resolution = 1e-3; + info->is_monotonic = 0; + info->is_adjusted = 1; + } } #else /* !HAVE_FTIME */ tp->tv_sec = time(NULL); tp->tv_usec = 0; + if (info) { + info->function = "time()"; + info->resolution = 1; + info->is_monotonic = 0; + info->is_adjusted = 1; + /* all platforms provide at least a resolution of 1 second */ + info->accuracy = 1; + } #endif /* !HAVE_FTIME */ #endif /* MS_WINDOWS */ } +void +_PyTime_gettimeofday(_PyTime_timeval *tp) +{ + pygettimeofday(tp, NULL); +} + +void +_PyTime_gettimeofday_info(_PyTime_timeval *tp, _Py_clock_info_t *info) +{ + pygettimeofday(tp, info); +} + static void error_time_t_overflow(void) {