blob: 8679bcc2cdeb0ab8dc7f5a2c2e1ab60a0e52fef9 [file] [log] [blame]
#include "Python.h"
#ifdef MS_WINDOWS
#include <windows.h>
#endif
#if defined(__APPLE__) && defined(HAVE_GETTIMEOFDAY) && defined(HAVE_FTIME)
/*
* _PyTime_gettimeofday falls back to ftime when getttimeofday fails because the latter
* might fail on some platforms. This fallback is unwanted on MacOSX because
* that makes it impossible to use a binary build on OSX 10.4 on earlier
* releases of the OS. Therefore claim we don't support ftime.
*/
# undef HAVE_FTIME
#endif
#if defined(HAVE_FTIME) && !defined(MS_WINDOWS)
#include <sys/timeb.h>
extern int ftime(struct timeb *);
#endif
#define MICROSECONDS 1000000
void
_PyTime_get(_PyTime_t *ts)
{
#ifdef MS_WINDOWS
FILETIME system_time;
ULARGE_INTEGER large;
ULONGLONG value;
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). */
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
(3) time() -- resolution in seconds
In all cases the return value in a timeval struct.
Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
fail, so we fall back on ftime() or time().
Note: clock resolution does not imply clock accuracy! */
#ifdef HAVE_GETTIMEOFDAY
#ifdef GETTIMEOFDAY_NO_TZ
err = gettimeofday(&tv);
#else /* !GETTIMEOFDAY_NO_TZ */
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)
ftime(&t);
ts->seconds = t.time;
ts->numerator = t.millitm;
ts->denominator = 1000;
#else /* !HAVE_FTIME */
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()
{
/* Do nothing. Needed to force linking. */
}