PEP 410
diff --git a/Python/pytime.c b/Python/pytime.c
index bec1c71..8679bcc 100644
--- a/Python/pytime.c
+++ b/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,30 +59,325 @@
 
 #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()
 {
     /* Do nothing.  Needed to force linking. */