mirror of
https://github.com/python/cpython.git
synced 2025-07-19 17:25:54 +00:00
PEP 410
This commit is contained in:
parent
6f91ce74a0
commit
ccd5715a14
9 changed files with 814 additions and 174 deletions
343
Python/pytime.c
343
Python/pytime.c
|
@ -18,24 +18,36 @@
|
|||
extern int ftime(struct timeb *);
|
||||
#endif
|
||||
|
||||
#define MICROSECONDS 1000000
|
||||
|
||||
void
|
||||
_PyTime_gettimeofday(_PyTime_timeval *tp)
|
||||
_PyTime_get(_PyTime_t *ts)
|
||||
{
|
||||
#ifdef MS_WINDOWS
|
||||
FILETIME system_time;
|
||||
ULARGE_INTEGER large;
|
||||
ULONGLONG microseconds;
|
||||
ULONGLONG value;
|
||||
|
||||
GetSystemTimeAsFileTime(&system_time);
|
||||
large.u.LowPart = system_time.dwLowDateTime;
|
||||
large.u.HighPart = system_time.dwHighDateTime;
|
||||
/* 11,644,473,600,000,000: number of microseconds between
|
||||
/* 116,444,736,000,000,000: number of 100 ns between
|
||||
the 1st january 1601 and the 1st january 1970 (369 years + 89 leap
|
||||
days). */
|
||||
microseconds = large.QuadPart / 10 - 11644473600000000;
|
||||
tp->tv_sec = microseconds / 1000000;
|
||||
tp->tv_usec = microseconds % 1000000;
|
||||
value = large.QuadPart - 116444736000000000;
|
||||
ts->seconds = 0;
|
||||
ts->numerator = value;
|
||||
ts->denominator = (_PyTime_fraction_t)10000000;
|
||||
#else
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
struct timeval tv;
|
||||
int err;
|
||||
#endif
|
||||
#if defined(HAVE_FTIME)
|
||||
struct timeb t;
|
||||
#endif
|
||||
|
||||
/* There are three ways to get the time:
|
||||
(1) gettimeofday() -- resolution in microseconds
|
||||
(2) ftime() -- resolution in milliseconds
|
||||
|
@ -47,29 +59,324 @@ _PyTime_gettimeofday(_PyTime_timeval *tp)
|
|||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
#ifdef GETTIMEOFDAY_NO_TZ
|
||||
if (gettimeofday(tp) == 0)
|
||||
return;
|
||||
err = gettimeofday(&tv);
|
||||
#else /* !GETTIMEOFDAY_NO_TZ */
|
||||
if (gettimeofday(tp, (struct timezone *)NULL) == 0)
|
||||
return;
|
||||
err = gettimeofday(&tv, (struct timezone *)NULL);
|
||||
#endif /* !GETTIMEOFDAY_NO_TZ */
|
||||
if (err == 0)
|
||||
{
|
||||
ts->seconds = tv.tv_sec;
|
||||
ts->numerator = tv.tv_usec;
|
||||
ts->denominator = MICROSECONDS;
|
||||
return;
|
||||
}
|
||||
#endif /* !HAVE_GETTIMEOFDAY */
|
||||
|
||||
#if defined(HAVE_FTIME)
|
||||
{
|
||||
struct timeb t;
|
||||
ftime(&t);
|
||||
tp->tv_sec = t.time;
|
||||
tp->tv_usec = t.millitm * 1000;
|
||||
}
|
||||
ftime(&t);
|
||||
ts->seconds = t.time;
|
||||
ts->numerator = t.millitm;
|
||||
ts->denominator = 1000;
|
||||
#else /* !HAVE_FTIME */
|
||||
tp->tv_sec = time(NULL);
|
||||
tp->tv_usec = 0;
|
||||
ts->seconds = time(NULL);
|
||||
ts->numerator = 0;
|
||||
ts->denominator = 1;
|
||||
#endif /* !HAVE_FTIME */
|
||||
|
||||
#endif /* MS_WINDOWS */
|
||||
}
|
||||
|
||||
void
|
||||
_PyTime_gettimeofday(_PyTime_timeval *tv)
|
||||
{
|
||||
_PyTime_t ts;
|
||||
_PyTime_fraction_t k;
|
||||
time_t sec;
|
||||
|
||||
_PyTime_get(&ts);
|
||||
tv->tv_sec = ts.seconds;
|
||||
if (ts.numerator) {
|
||||
if (ts.numerator > ts.denominator) {
|
||||
sec = Py_SAFE_DOWNCAST(ts.numerator / ts.denominator,
|
||||
_PyTime_fraction_t, time_t);
|
||||
/* ignore integer overflow because _PyTime_gettimeofday() has
|
||||
no return value */
|
||||
tv->tv_sec += sec;
|
||||
ts.numerator = ts.numerator % ts.denominator;
|
||||
}
|
||||
if (MICROSECONDS >= ts.denominator) {
|
||||
k = (_PyTime_fraction_t)MICROSECONDS / ts.denominator;
|
||||
tv->tv_usec = (long)(ts.numerator * k);
|
||||
}
|
||||
else {
|
||||
k = ts.denominator / (_PyTime_fraction_t)MICROSECONDS;
|
||||
tv->tv_usec = (long)(ts.numerator / k);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tv->tv_usec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
_PyLong_FromTime_t(time_t value)
|
||||
{
|
||||
#if SIZEOF_TIME_T <= SIZEOF_LONG
|
||||
return PyLong_FromLong(value);
|
||||
#else
|
||||
assert(sizeof(time_t) <= sizeof(PY_LONG_LONG));
|
||||
return PyLong_FromLongLong(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HAVE_LONG_LONG)
|
||||
# define _PyLong_FromTimeFraction_t PyLong_FromLongLong
|
||||
#else
|
||||
# define _PyLong_FromTimeFraction_t PyLong_FromSize_t
|
||||
#endif
|
||||
|
||||
/* Convert a timestamp to a PyFloat object */
|
||||
static PyObject*
|
||||
_PyTime_AsFloat(_PyTime_t *ts)
|
||||
{
|
||||
double d;
|
||||
d = (double)ts->seconds;
|
||||
d += (double)ts->numerator / (double)ts->denominator;
|
||||
return PyFloat_FromDouble(d);
|
||||
}
|
||||
|
||||
/* Convert a timestamp to a PyLong object */
|
||||
static PyObject*
|
||||
_PyTime_AsLong(_PyTime_t *ts)
|
||||
{
|
||||
PyObject *a, *b, *c;
|
||||
|
||||
a = _PyLong_FromTime_t(ts->seconds);
|
||||
if (a == NULL)
|
||||
return NULL;
|
||||
b = _PyLong_FromTimeFraction_t(ts->numerator / ts->denominator);
|
||||
if (b == NULL)
|
||||
{
|
||||
Py_DECREF(a);
|
||||
return NULL;
|
||||
}
|
||||
c = PyNumber_Add(a, b);
|
||||
Py_DECREF(a);
|
||||
Py_DECREF(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Convert a timestamp to a decimal.Decimal object */
|
||||
static PyObject*
|
||||
_PyTime_AsDecimal(_PyTime_t *ts)
|
||||
{
|
||||
static PyObject* module = NULL;
|
||||
static PyObject* decimal = NULL;
|
||||
static PyObject* exponent_context = NULL;
|
||||
static PyObject* context = NULL;
|
||||
/* exponent cache, dictionary of:
|
||||
int (denominator) => Decimal (1/denominator) */
|
||||
static PyObject* exponent_cache = NULL;
|
||||
PyObject *t = NULL;
|
||||
PyObject *key, *exponent, *quantized;
|
||||
_Py_IDENTIFIER(quantize);
|
||||
_Py_IDENTIFIER(__truediv__);
|
||||
|
||||
if (!module) {
|
||||
module = PyImport_ImportModuleNoBlock("decimal");
|
||||
if (module == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!decimal) {
|
||||
decimal = PyObject_GetAttrString(module, "Decimal");
|
||||
if (decimal == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (context == NULL)
|
||||
{
|
||||
/* Use 12 decimal digits to store 10,000 years in seconds + 9
|
||||
decimal digits for the floating part in nanoseconds + 1 decimal
|
||||
digit to round correctly.
|
||||
|
||||
context = decimal.Context(22, rounding=decimal.ROUND_HALF_EVEN)
|
||||
exponent_context = decimal.Context(1, rounding=decimal.ROUND_HALF_EVEN)
|
||||
*/
|
||||
PyObject *context_class, *rounding;
|
||||
context_class = PyObject_GetAttrString(module, "Context");
|
||||
if (context_class == NULL)
|
||||
return NULL;
|
||||
rounding = PyObject_GetAttrString(module, "ROUND_HALF_EVEN");
|
||||
if (rounding == NULL)
|
||||
{
|
||||
Py_DECREF(context_class);
|
||||
return NULL;
|
||||
}
|
||||
context = PyObject_CallFunction(context_class, "iO", 22, rounding);
|
||||
if (context == NULL)
|
||||
{
|
||||
Py_DECREF(context_class);
|
||||
Py_DECREF(rounding);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
exponent_context = PyObject_CallFunction(context_class, "iO", 1, rounding);
|
||||
Py_DECREF(context_class);
|
||||
Py_DECREF(rounding);
|
||||
if (exponent_context == NULL)
|
||||
{
|
||||
Py_CLEAR(context);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* t = decimal.Decimal(value) */
|
||||
if (ts->seconds) {
|
||||
PyObject *f = _PyLong_FromTime_t(ts->seconds);
|
||||
t = PyObject_CallFunction(decimal, "O", f);
|
||||
Py_CLEAR(f);
|
||||
}
|
||||
else {
|
||||
t = PyObject_CallFunction(decimal, "iO", 0, context);
|
||||
}
|
||||
if (t == NULL)
|
||||
return NULL;
|
||||
|
||||
if (ts->numerator)
|
||||
{
|
||||
/* t += decimal.Decimal(numerator, ctx) / decimal.Decimal(denominator, ctx) */
|
||||
PyObject *a, *b, *c, *d, *x;
|
||||
|
||||
x = _PyLong_FromTimeFraction_t(ts->numerator);
|
||||
if (x == NULL)
|
||||
goto error;
|
||||
a = PyObject_CallFunction(decimal, "OO", x, context);
|
||||
Py_CLEAR(x);
|
||||
if (a == NULL)
|
||||
goto error;
|
||||
|
||||
x = _PyLong_FromTimeFraction_t(ts->denominator);
|
||||
if (x == NULL)
|
||||
{
|
||||
Py_DECREF(a);
|
||||
goto error;
|
||||
}
|
||||
b = PyObject_CallFunction(decimal, "OO", x, context);
|
||||
Py_CLEAR(x);
|
||||
if (b == NULL)
|
||||
{
|
||||
Py_DECREF(a);
|
||||
goto error;
|
||||
}
|
||||
|
||||
c = _PyObject_CallMethodId(a, &PyId___truediv__, "OO",
|
||||
b, context);
|
||||
Py_DECREF(a);
|
||||
Py_DECREF(b);
|
||||
if (c == NULL)
|
||||
goto error;
|
||||
|
||||
d = PyNumber_Add(t, c);
|
||||
Py_DECREF(c);
|
||||
if (d == NULL)
|
||||
goto error;
|
||||
Py_DECREF(t);
|
||||
t = d;
|
||||
}
|
||||
|
||||
if (exponent_cache == NULL) {
|
||||
exponent_cache = PyDict_New();
|
||||
if (exponent_cache == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
key = _PyLong_FromTimeFraction_t(ts->denominator);
|
||||
if (key == NULL)
|
||||
goto error;
|
||||
exponent = PyDict_GetItem(exponent_cache, key);
|
||||
if (exponent == NULL) {
|
||||
/* exponent = decimal.Decimal(1) / decimal.Decimal(resolution) */
|
||||
PyObject *one, *denominator;
|
||||
|
||||
one = PyObject_CallFunction(decimal, "i", 1);
|
||||
if (one == NULL) {
|
||||
Py_DECREF(key);
|
||||
goto error;
|
||||
}
|
||||
|
||||
denominator = PyObject_CallFunction(decimal, "O", key);
|
||||
if (denominator == NULL) {
|
||||
Py_DECREF(key);
|
||||
Py_DECREF(one);
|
||||
goto error;
|
||||
}
|
||||
|
||||
exponent = _PyObject_CallMethodId(one, &PyId___truediv__, "OO",
|
||||
denominator, exponent_context);
|
||||
Py_DECREF(one);
|
||||
Py_DECREF(denominator);
|
||||
if (exponent == NULL) {
|
||||
Py_DECREF(key);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (PyDict_SetItem(exponent_cache, key, exponent) < 0) {
|
||||
Py_DECREF(key);
|
||||
Py_DECREF(exponent);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(key);
|
||||
}
|
||||
|
||||
/* t = t.quantize(exponent, None, context) */
|
||||
quantized = _PyObject_CallMethodId(t, &PyId_quantize, "OOO",
|
||||
exponent, Py_None, context);
|
||||
if (quantized == NULL)
|
||||
goto error;
|
||||
Py_DECREF(t);
|
||||
t = quantized;
|
||||
|
||||
return t;
|
||||
|
||||
error:
|
||||
Py_XDECREF(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
_PyTime_Convert(_PyTime_t *ts, PyObject *format)
|
||||
{
|
||||
assert(ts->denominator != 0);
|
||||
|
||||
if (format == NULL || (PyTypeObject *)format == &PyFloat_Type)
|
||||
return _PyTime_AsFloat(ts);
|
||||
if ((PyTypeObject *)format == &PyLong_Type)
|
||||
return _PyTime_AsLong(ts);
|
||||
|
||||
if (PyType_Check(format))
|
||||
{
|
||||
PyObject *module, *name;
|
||||
_Py_IDENTIFIER(__name__);
|
||||
_Py_IDENTIFIER(__module__);
|
||||
|
||||
module = _PyObject_GetAttrId(format, &PyId___module__);
|
||||
name = _PyObject_GetAttrId(format, &PyId___name__);
|
||||
if (module != NULL && PyUnicode_Check(module)
|
||||
&& name != NULL && PyUnicode_Check(name))
|
||||
{
|
||||
if (PyUnicode_CompareWithASCIIString(module, "decimal") == 0
|
||||
&& PyUnicode_CompareWithASCIIString(name, "Decimal") == 0)
|
||||
return _PyTime_AsDecimal(ts);
|
||||
}
|
||||
else
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_ValueError, "Unknown timestamp format: %R", format);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
_PyTime_Init()
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue