task: metadata: install: pip install -e .[test]
patch: diff --git a/CHANGES.rst b/CHANGES.rst
index 956c0a5..469c538 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,12 +4,6 @@
 4.3.1 (unreleased)
 ------------------
 
-- Change the default representation of ``Persistent`` objects to
-  include the representation of their OID and jar, if set. Also add
-  the ability for subclasses to implement ``_p_repr()`` instead of
-  overriding ``__repr__`` for better exception handling. See `issue 11
-  <https://github.com/zopefoundation/persistent/issues/11>`_.
-
 - Reach and maintain 100% test coverage.
 
 - Simplify ``__init__.py``, including removal of an attempted legacy
@@ -37,6 +31,15 @@
 - Remove some internal compatibility shims that are no longer
   necessary. See `PR 82 <https://github.com/zopefoundation/persistent/pull/82>`_.
 
+- Make the return value of ``TimeStamp.second()`` consistent across C
+  and Python implementations when the ``TimeStamp`` was created from 6
+  arguments with floating point seconds. Also make it match across
+  trips through ``TimeStamp.raw()``. Previously, the C version could
+  initially have erroneous rounding and too much false precision,
+  while the Python version could have too much precision. The raw/repr
+  values have not changed. See `issue 41
+  <https://github.com/zopefoundation/persistent/issues/41>`_.
+
 4.3.0 (2018-07-30)
 ------------------
 
diff --git a/docs/using.rst b/docs/using.rst
index 417b25e..5803d7e 100644
--- a/docs/using.rst
+++ b/docs/using.rst
@@ -1,10 +1,9 @@
-=============================================
- Using :mod:`persistent` in your application
-=============================================
+Using :mod:`persistent` in your application
+===========================================
 
 
 Inheriting from :class:`persistent.Persistent`
-==============================================
+----------------------------------------------
 
 The basic mechanism for making your application's objects persistent
 is mix-in interitance.  Instances whose classes derive from
@@ -15,7 +14,7 @@ they have been changed.
 
 
 Relationship to a Data Manager and its Cache
-============================================
+--------------------------------------------
 
 Except immediately after their creation, persistent objects are normally
 associated with a :term:`data manager` (also referred to as a :term:`jar`).
@@ -64,7 +63,7 @@ The examples below use a stub data manager class, and its stub cache class:
 
 
 Persistent objects without a Data Manager
-=========================================
+-----------------------------------------
 
 Before aersistent instance has been associtated with a a data manager (
 i.e., its ``_p_jar`` is still ``None``).
@@ -167,7 +166,7 @@ Try all sorts of different ways to change the object's state:
 
 
 Associating an Object with a Data Manager
-=========================================
+-----------------------------------------
 
 Once associated with a data manager, a persistent object's behavior changes:
 
@@ -220,7 +219,7 @@ control the state as described below, or use a
 :class:`~.PersistentList` or :class:`~.PersistentMapping`.
 
 Explicitly controlling ``_p_state``
-===================================
+-----------------------------------
 
 Persistent objects expose three methods for moving an object into and out
 of the "ghost" state::  :meth:`persistent.Persistent._p_activate`,
@@ -329,7 +328,7 @@ which is exactly the same as calling ``_p_activate``:
 
 
 The pickling protocol
-=====================
+---------------------
 
 Because persistent objects need to control how they are pickled and
 unpickled, the :class:`persistent.Persistent` base class overrides
@@ -383,7 +382,7 @@ The ``_p_serial`` attribute is not affected by calling setstate.
 
 
 Estimated Object Size
-=====================
+---------------------
 
 We can store a size estimation in ``_p_estimated_size``. Its default is 0.
 The size estimation can be used by a cache associated with the data manager
@@ -413,7 +412,7 @@ Of course, the estimated size must not be negative.
 
 
 Overriding the attribute protocol
-=================================
+---------------------------------
 
 Subclasses which override the attribute-management methods provided by
 :class:`persistent.Persistent`, but must obey some constraints:
@@ -449,24 +448,3 @@ Subclasses which override the attribute-management methods provided by
 :meth:`__getattr__`
   For the ``__getattr__`` method, the behavior is like that for regular Python
   classes and for earlier versions of ZODB 3.
-
-
-Implementing ``_p_repr``
-========================
-
-Subclasses can implement ``_p_repr`` to provide a custom
-representation. If this method raises an exception, the default
-representation will be used. The benefit of implementing ``_p_repr``
-instead of overriding ``__repr__`` is that it provides safer handling
-for objects that can't be activated because their persistent data is
-missing or their jar is closed.
-
-.. doctest::
-
-   >>> class P(Persistent):
-   ...    def _p_repr(self):
-   ...        return "Custom repr"
-
-   >>> p = P()
-   >>> print(repr(p))
-   Custom repr
diff --git a/persistent/cPersistence.c b/persistent/cPersistence.c
index 9e0f3ae..131dd71 100644
--- a/persistent/cPersistence.c
+++ b/persistent/cPersistence.c
@@ -1372,101 +1372,6 @@ Per_set_sticky(cPersistentObject *self, PyObject* value)
     return 0;
 }
 
-static PyObject*
-repr_format_exception(char* format)
-{
-    /* If an exception we should catch occurred, return a new
-       string of its repr. Otherwise, return NULL. */
-    PyObject *exc_t;
-    PyObject *exc_v;
-    PyObject *exc_tb;
-    PyObject *result = NULL;
-
-    if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_Exception))
-    {
-        PyErr_Fetch(&exc_t, &exc_v, &exc_tb);
-        PyErr_NormalizeException(&exc_t, &exc_v, &exc_tb);
-        PyErr_Clear();
-
-        result = PyUnicode_FromFormat(format, exc_v);
-        Py_DECREF(exc_t);
-        Py_DECREF(exc_v);
-        Py_DECREF(exc_tb);
-    }
-    return result;
-}
-
-static PyObject*
-repr_helper(PyObject *o, char* format)
-{
-    /* Returns a new reference, or NULL on error */
-    PyObject *result;
-
-    if (o)
-    {
-        result = PyUnicode_FromFormat(format, o);
-        if (!result)
-            result = repr_format_exception(format);
-    }
-    else
-    {
-        result = PyUnicode_FromString("");
-    }
-
-    return result;
-
-}
-
-static PyObject*
-Per_repr(cPersistentObject *self)
-{
-    PyObject *prepr = NULL;
-    PyObject *prepr_exc_str = NULL;
-
-    PyObject *oid_str = NULL;
-    PyObject *jar_str = NULL;
-    PyObject *result = NULL;
-
-    prepr = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "_p_repr");
-    if (prepr)
-    {
-        result = PyObject_CallFunctionObjArgs(prepr, self, NULL);
-        if (result)
-            goto cleanup;
-        else
-        {
-            prepr_exc_str = repr_format_exception(" _p_repr %R");
-            if (!prepr_exc_str)
-                goto cleanup;
-        }
-    }
-    else
-    {
-        PyErr_Clear();
-        prepr_exc_str = PyUnicode_FromString("");
-    }
-
-    oid_str = repr_helper(self->oid, " oid %R");
-    if (!oid_str)
-        goto cleanup;
-
-    jar_str = repr_helper(self->jar, " in %R");
-    if (!jar_str)
-        goto cleanup;
-
-    result = PyUnicode_FromFormat("<%s object at %p%S%S%S>",
-                                  Py_TYPE(self)->tp_name, self,
-                                  oid_str, jar_str, prepr_exc_str);
-
-cleanup:
-    Py_XDECREF(prepr);
-    Py_XDECREF(prepr_exc_str);
-    Py_XDECREF(oid_str);
-    Py_XDECREF(jar_str);
-
-    return result;
-}
-
 static PyGetSetDef Per_getsets[] = {
   {"_p_changed", (getter)Per_get_changed, (setter)Per_set_changed},
   {"_p_jar", (getter)Per_get_jar, (setter)Per_set_jar},
@@ -1549,7 +1454,7 @@ static PyTypeObject Pertype = {
   0,                                /* tp_getattr */
   0,                                /* tp_setattr */
   0,                                /* tp_compare */
-  (reprfunc)Per_repr,               /* tp_repr */
+  0,                                /* tp_repr */
   0,                                /* tp_as_number */
   0,                                /* tp_as_sequence */
   0,                                /* tp_as_mapping */
diff --git a/persistent/interfaces.py b/persistent/interfaces.py
index 61ed594..69b7bad 100644
--- a/persistent/interfaces.py
+++ b/persistent/interfaces.py
@@ -166,14 +166,6 @@ class IPersistent(Interface):
     these objects are invalidated, they immediately reload their state
     from their data manager, and are then in the saved state.
 
-    reprs
-
-    By default, persistent objects include the reprs of their
-    _p_oid and _p_jar, if any, in their repr. If a subclass implements
-    the optional method ``_p_repr``, it will be called and its results returned
-    instead of the default repr; if this method raises an exception, that
-    exception will be caught and its repr included in the default repr.
-
     """
 
     _p_jar = Attribute(
@@ -322,10 +314,10 @@ class IPersistent(Interface):
 
     def _p_getattr(name):
         """Test whether the base class must handle the name
-
+   
         The method unghostifies the object, if necessary.
         The method records the object access, if necessary.
-
+ 
         This method should be called by subclass __getattribute__
         implementations before doing anything else. If the method
         returns True, then __getattribute__ implementations must delegate
@@ -479,7 +471,7 @@ class IPickleCache(Interface):
         """ Perform an incremental garbage collection sweep.
 
         o Reduce number of non-ghosts to 'cache_size', if possible.
-
+        
         o Ghostify in LRU order.
 
         o Skip dirty or sticky objects.
@@ -513,7 +505,7 @@ class IPickleCache(Interface):
 
         If the object's '_p_jar' is not None, raise.
 
-        If 'oid' is already in the cache, raise.
+        If 'oid' is already in the cache, raise. 
         """
 
     def reify(to_reify):
@@ -544,7 +536,7 @@ class IPickleCache(Interface):
         o Any OID corresponding to a p-class will cause the corresponding
             p-class to be removed from the cache.
 
-        o For all other OIDs, ghostify the corrsponding object and
+        o For all other OIDs, ghostify the corrsponding object and 
             remove it from the ring.
         """
 
diff --git a/persistent/persistence.py b/persistent/persistence.py
index 8d72ce1..7bf0508 100644
--- a/persistent/persistence.py
+++ b/persistent/persistence.py
@@ -11,7 +11,7 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-
+import sys
 
 from zope.interface import implementer
 
@@ -20,13 +20,14 @@ from persistent.interfaces import GHOST
 from persistent.interfaces import UPTODATE
 from persistent.interfaces import CHANGED
 from persistent.interfaces import STICKY
-
+from persistent.interfaces import OID_TYPE
 from persistent.interfaces import SERIAL_TYPE
 from persistent.timestamp import TimeStamp
 from persistent.timestamp import _ZERO
 from persistent._compat import copy_reg
 from persistent._compat import intern
 
+from . import ring
 
 _INITIAL_SERIAL = _ZERO
 
@@ -557,39 +558,6 @@ class Persistent(object):
         if cache is not None:
             return cache.get(oid) is self
 
-    def __repr__(self):
-        p_repr_str = ''
-        p_repr = getattr(type(self), '_p_repr', None)
-        if p_repr is not None:
-            try:
-                return p_repr(self)
-            except Exception as e:
-                p_repr_str = ' _p_repr %r' % (e,)
-
-        oid = _OGA(self, '_Persistent__oid')
-        jar = _OGA(self, '_Persistent__jar')
-
-        oid_str = ''
-        jar_str = ''
-
-        if oid is not None:
-            try:
-                oid_str = ' oid %r' % (oid,)
-            except Exception as e:
-                oid_str = ' oid %r' % (e,)
-
-        if jar is not None:
-            try:
-                jar_str = ' in %r' % (jar,)
-            except Exception as e:
-                jar_str = ' in %r' % (e,)
-
-        return '<%s.%s object at 0x%x%s%s%s>' % (
-            type(self).__module__, type(self).__name__, id(self),
-            oid_str, jar_str, p_repr_str
-        )
-
-
 def _estimated_size_in_24_bits(value):
     if value > 1073741696:
         return 16777215
diff --git a/persistent/timestamp.py b/persistent/timestamp.py
index 5da8535..a031a72 100644
--- a/persistent/timestamp.py
+++ b/persistent/timestamp.py
@@ -53,6 +53,7 @@ class _UTC(datetime.tzinfo):
         return dt
 
 def _makeUTC(y, mo, d, h, mi, s):
+    s = round(s, 6) # microsecond precision, to match the C implementation
     usec, sec = math.modf(s)
     sec = int(sec)
     usec = int(usec * 1e6)
@@ -75,7 +76,7 @@ def _parseRaw(octets):
     day = a // (60 * 24) % 31 + 1
     month = a // (60 * 24 * 31) % 12 + 1
     year = a // (60 * 24 * 31 * 12) + 1900
-    second = round(b * _SCONV, 6) #microsecond precision
+    second = b * _SCONV
     return (year, month, day, hour, minute, second)
 
 
@@ -83,6 +84,7 @@ class pyTimeStamp(object):
     __slots__ = ('_raw', '_elements')
 
     def __init__(self, *args):
+        self._elements = None
         if len(args) == 1:
             raw = args[0]
             if not isinstance(raw, _RAWTYPE):
@@ -90,14 +92,18 @@ class pyTimeStamp(object):
             if len(raw) != 8:
                 raise TypeError('Raw must be 8 octets')
             self._raw = raw
-            self._elements = _parseRaw(raw)
         elif len(args) == 6:
             self._raw = _makeRaw(*args)
-            self._elements = args
+            # Note that we don't preserve the incoming arguments in self._elements,
+            # we derive them from the raw value. This is because the incoming
+            # seconds value could have more precision than would survive
+            # in the raw data, so we must be consistent.
         else:
             raise TypeError('Pass either a single 8-octet arg '
                             'or 5 integers and a float')
 
+        self._elements = _parseRaw(self._raw)
+
     def raw(self):
         return self._raw
 

problem_statement: pyTimeStamp and TimeStamp have different sub-second precision
I don't think this is correct:

```
>>> from persistent.timestamp import TimeStamp, pyTimeStamp
>>> ts1 = TimeStamp(2001, 2, 3, 4, 5, 6.123456789)
>>> ts2 = pyTimeStamp(2001, 2, 3, 4, 5, 6.123456789)
>>> ts1 == ts2
True
>>> ts1.second() == ts2.second()
False
>>> ts1.second()
6.1234567780047655
>>> ts2.second()
6.123456789
```

repo: zopefoundation/persistent
test_cmd: pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
test_patch: diff --git a/persistent/tests/test_persistence.py b/persistent/tests/test_persistence.py
index 9ded7e2..3ce52e7 100644
--- a/persistent/tests/test_persistence.py
+++ b/persistent/tests/test_persistence.py
@@ -11,31 +11,24 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
+import os
+import unittest
 
 import platform
-import re
 import sys
-import unittest
 
-import persistent
 from persistent._compat import copy_reg
 
+py_impl = getattr(platform, 'python_implementation', lambda: None)
+_is_pypy3 = py_impl() == 'PyPy' and sys.version_info[0] > 2
+_is_jython = py_impl() == 'Jython'
 
-_is_pypy3 = platform.python_implementation() == 'PyPy' and sys.version_info[0] > 2
-_is_jython = platform.python_implementation() == 'Jython'
-
-# pylint:disable=R0904,W0212,E1101
+#pylint: disable=R0904,W0212,E1101
 # pylint:disable=attribute-defined-outside-init,too-many-lines
-# pylint:disable=blacklisted-name,useless-object-inheritance
+# pylint:disable=blacklisted-name
 # Hundreds of unused jar and OID vars make this useless
 # pylint:disable=unused-variable
 
-def skipIfNoCExtension(o):
-    return unittest.skipIf(
-        persistent._cPersistence is None,
-        "The C extension is not available")(o)
-
-
 class _Persistent_Base(object):
 
     # py2/3 compat
@@ -1622,7 +1615,7 @@ class _Persistent_Base(object):
             def __setattr__(self, name, value):
                 raise AssertionError("Should not be called")
         inst = subclass()
-        self.assertEqual(object.__getattribute__(inst, '_v_setattr_called'), False)
+        self.assertEqual(object.__getattribute__(inst,'_v_setattr_called'), False)
 
     def test_can_set__p_attrs_if_subclass_denies_setattr(self):
         # ZODB defines a PersistentBroken subclass that only lets us
@@ -1671,7 +1664,7 @@ class _Persistent_Base(object):
         self.assertEqual(candidate._p_state, UPTODATE)
         cache.new_ghost(KEY, candidate)
 
-        self.assertIs(cache.get(KEY), candidate)
+        self.assertTrue(cache.get(KEY) is candidate)
         self.assertEqual(candidate._p_oid, KEY)
         self.assertEqual(candidate._p_state, GHOST)
         self.assertEqual(candidate.set_by_new, 1)
@@ -1692,192 +1685,11 @@ class _Persistent_Base(object):
         self.assertEqual(candidate._p_state, UPTODATE)
         cache.new_ghost(KEY, candidate)
 
-        self.assertIs(cache.get(KEY), candidate)
+        self.assertTrue(cache.get(KEY) is candidate)
         self.assertEqual(candidate._p_oid, KEY)
         self.assertEqual(candidate._p_state, GHOST)
         self.assertEqual(candidate.set_by_new, 1)
 
-    def _normalize_repr(self, r):
-        # Pure-python vs C
-        r = r.replace('persistent.persistence.Persistent', 'persistent.Persistent')
-        r = r.replace("persistent.tests.test_persistence.", '')
-        # addresses
-        r = re.sub(r'0x[0-9a-fA-F]*', '0xdeadbeef', r)
-        # Python 3.7 removed the trailing , in exception reprs
-        r = r.replace("',)", "')")
-        # Python 2 doesn't have a leading b prefix for byte literals
-        r = r.replace("oid '", "oid b'")
-        return r
-
-    def _normalized_repr(self, o):
-        return self._normalize_repr(repr(o))
-
-    def test_repr_no_oid_no_jar(self):
-        p = self._makeOne()
-        result = self._normalized_repr(p)
-        self.assertEqual(result, '<persistent.Persistent object at 0xdeadbeef>')
-
-    def test_repr_no_oid_in_jar(self):
-        p = self._makeOne()
-
-        class Jar(object):
-            def __repr__(self):
-                return '<SomeJar>'
-
-        p._p_jar = Jar()
-
-        result = self._normalized_repr(p)
-        self.assertEqual(
-            result,
-            "<persistent.Persistent object at 0xdeadbeef in <SomeJar>>")
-
-    def test_repr_oid_no_jar(self):
-        p = self._makeOne()
-        p._p_oid = b'12345678'
-
-        result = self._normalized_repr(p)
-        self.assertEqual(
-            result,
-            "<persistent.Persistent object at 0xdeadbeef oid b'12345678'>")
-
-    def test_repr_no_oid_repr_jar_raises_exception(self):
-        p = self._makeOne()
-
-        class Jar(object):
-            def __repr__(self):
-                raise Exception('jar repr failed')
-
-        p._p_jar = Jar()
-
-        result = self._normalized_repr(p)
-        self.assertEqual(
-            result,
-            "<persistent.Persistent object at 0xdeadbeef in Exception('jar repr failed')>")
-
-
-    def test_repr_oid_raises_exception_no_jar(self):
-        p = self._makeOne()
-
-        class BadOID(bytes):
-            def __repr__(self):
-                raise Exception("oid repr failed")
-        p._p_oid = BadOID(b'12345678')
-
-        result = self._normalized_repr(p)
-        self.assertEqual(
-            result,
-            "<persistent.Persistent object at 0xdeadbeef oid Exception('oid repr failed')>")
-
-
-    def test_repr_oid_and_jar_raise_exception(self):
-        p = self._makeOne()
-
-        class BadOID(bytes):
-            def __repr__(self):
-                raise Exception("oid repr failed")
-        p._p_oid = BadOID(b'12345678')
-
-        class Jar(object):
-            def __repr__(self):
-                raise Exception('jar repr failed')
-
-        p._p_jar = Jar()
-
-
-        result = self._normalized_repr(p)
-        self.assertEqual(
-            result,
-            "<persistent.Persistent object at 0xdeadbeef oid Exception('oid repr failed')"
-            " in Exception('jar repr failed')>")
-
-    def test_repr_no_oid_repr_jar_raises_baseexception(self):
-        p = self._makeOne()
-
-        class Jar(object):
-            def __repr__(self):
-                raise BaseException('jar repr failed')
-
-        p._p_jar = Jar()
-        with self.assertRaisesRegex(BaseException, 'jar repr failed'):
-            repr(p)
-
-    def test_repr_oid_raises_baseexception_no_jar(self):
-        p = self._makeOne()
-
-        class BadOID(bytes):
-            def __repr__(self):
-                raise BaseException("oid repr failed")
-        p._p_oid = BadOID(b'12345678')
-
-        with self.assertRaisesRegex(BaseException, 'oid repr failed'):
-            repr(p)
-
-    def test_repr_oid_and_jar(self):
-        p = self._makeOne()
-        p._p_oid = b'12345678'
-
-        class Jar(object):
-            def __repr__(self):
-                return '<SomeJar>'
-
-        p._p_jar = Jar()
-
-        result = self._normalized_repr(p)
-        self.assertEqual(
-            result,
-            "<persistent.Persistent object at 0xdeadbeef oid b'12345678' in <SomeJar>>")
-
-    def test__p_repr(self):
-        class P(self._getTargetClass()):
-            def _p_repr(self):
-                return "Override"
-        p = P()
-        self.assertEqual("Override", repr(p))
-
-    def test__p_repr_exception(self):
-        class P(self._getTargetClass()):
-            def _p_repr(self):
-                raise Exception("_p_repr failed")
-        p = P()
-        result = self._normalized_repr(p)
-        self.assertEqual(
-            result,
-            "<P object at 0xdeadbeef"
-            " _p_repr Exception('_p_repr failed')>")
-
-        p._p_oid = b'12345678'
-        result = self._normalized_repr(p)
-        self.assertEqual(
-            result,
-            "<P object at 0xdeadbeef oid b'12345678'"
-            " _p_repr Exception('_p_repr failed')>")
-
-        class Jar(object):
-            def __repr__(self):
-                return '<SomeJar>'
-
-        p._p_jar = Jar()
-        result = self._normalized_repr(p)
-        self.assertEqual(
-            result,
-            "<P object at 0xdeadbeef oid b'12345678'"
-            " in <SomeJar> _p_repr Exception('_p_repr failed')>")
-
-    def test__p_repr_in_instance_ignored(self):
-        class P(self._getTargetClass()):
-            pass
-        p = P()
-        p._p_repr = lambda: "Instance"
-        result = self._normalized_repr(p)
-        self.assertEqual(result, '<P object at 0xdeadbeef>')
-
-    def test__p_repr_baseexception(self):
-        class P(self._getTargetClass()):
-            def _p_repr(self):
-                raise BaseException("_p_repr failed")
-        p = P()
-        with self.assertRaisesRegex(BaseException, '_p_repr failed'):
-            repr(p)
 
 class PyPersistentTests(unittest.TestCase, _Persistent_Base):
 
@@ -1989,39 +1801,47 @@ class PyPersistentTests(unittest.TestCase, _Persistent_Base):
         inst._Persistent__flags = None
         inst._p_accessed()
 
+_add_to_suite = [PyPersistentTests]
 
-@skipIfNoCExtension
-class CPersistentTests(unittest.TestCase, _Persistent_Base):
+if not os.environ.get('PURE_PYTHON'):
+    try:
+        from persistent import cPersistence
+    except ImportError: # pragma: no cover
+        pass
+    else:
+        class CPersistentTests(unittest.TestCase, _Persistent_Base):
 
-    def _getTargetClass(self):
-        from persistent.cPersistence import Persistent
-        return Persistent
+            def _getTargetClass(self):
+                from persistent.cPersistence import Persistent
+                return Persistent
 
-    def _checkMRU(self, jar, value):
-        pass # Figure this out later
+            def _checkMRU(self, jar, value):
+                pass # Figure this out later
 
-    def _clearMRU(self, jar):
-        pass # Figure this out later
+            def _clearMRU(self, jar):
+                pass # Figure this out later
 
-    def _makeCache(self, jar):
-        from persistent.cPickleCache import PickleCache
-        return PickleCache(jar)
+            def _makeCache(self, jar):
+                from persistent.cPickleCache import PickleCache
+                return PickleCache(jar)
+
+        _add_to_suite.append(CPersistentTests)
 
+        class Test_simple_new(unittest.TestCase):
 
-@skipIfNoCExtension
-class Test_simple_new(unittest.TestCase):
+            def _callFUT(self, x):
+                from persistent.cPersistence import simple_new
+                return simple_new(x)
 
-    def _callFUT(self, x):
-        from persistent.cPersistence import simple_new
-        return simple_new(x)
+            def test_w_non_type(self):
+                self.assertRaises(TypeError, self._callFUT, '')
 
-    def test_w_non_type(self):
-        self.assertRaises(TypeError, self._callFUT, '')
+            def test_w_type(self):
+                TO_CREATE = [type, list, tuple, object, dict]
+                for typ in TO_CREATE:
+                    self.assertTrue(isinstance(self._callFUT(typ), typ))
 
-    def test_w_type(self):
-        TO_CREATE = [type, list, tuple, object, dict]
-        for typ in TO_CREATE:
-            self.assertTrue(isinstance(self._callFUT(typ), typ))
+        _add_to_suite.append(Test_simple_new)
 
 def test_suite():
-    return unittest.defaultTestLoader.loadTestsFromName(__name__)
+    return unittest.TestSuite([unittest.makeSuite(x) for x in _add_to_suite])
diff --git a/persistent/tests/test_timestamp.py b/persistent/tests/test_timestamp.py
index cc1253c..ff8b6a9 100644
--- a/persistent/tests/test_timestamp.py
+++ b/persistent/tests/test_timestamp.py
@@ -17,6 +17,8 @@ import sys
 MAX_32_BITS = 2 ** 31 - 1
 MAX_64_BITS = 2 ** 63 - 1
 
+import persistent.timestamp
+
 class Test__UTC(unittest.TestCase):
 
     def _getTargetClass(self):
@@ -202,7 +204,8 @@ class TimeStampTests(pyTimeStampTests):
         from persistent.timestamp import TimeStamp
         return TimeStamp
 
-
+@unittest.skipIf(persistent.timestamp.CTimeStamp is None,
+                 "CTimeStamp not available")
 class PyAndCComparisonTests(unittest.TestCase):
     """
     Compares C and Python implementations.
@@ -254,7 +257,6 @@ class PyAndCComparisonTests(unittest.TestCase):
 
     def test_equal(self):
         c, py = self._make_C_and_Py(*self.now_ts_args)
-
         self.assertEqual(c, py)
 
     def test_hash_equal(self):
@@ -396,22 +398,32 @@ class PyAndCComparisonTests(unittest.TestCase):
         self.assertTrue(big_c != small_py)
         self.assertTrue(small_py != big_c)
 
+    def test_seconds_precision(self, seconds=6.123456789):
+        # https://github.com/zopefoundation/persistent/issues/41
+        args = (2001, 2, 3, 4, 5, seconds)
+        c = self._makeC(*args)
+        py = self._makePy(*args)
 
-def test_suite():
-    suite = [
-        unittest.makeSuite(Test__UTC),
-        unittest.makeSuite(pyTimeStampTests),
-        unittest.makeSuite(TimeStampTests),
-    ]
+        self.assertEqual(c, py)
+        self.assertEqual(c.second(), py.second())
+
+        py2 = self._makePy(c.raw())
+        self.assertEqual(py2, c)
+
+        c2 = self._makeC(c.raw())
+        self.assertEqual(c2, c)
+
+    def test_seconds_precision_half(self):
+        # make sure our rounding matches
+        self.test_seconds_precision(seconds=6.5)
+        self.test_seconds_precision(seconds=6.55)
+        self.test_seconds_precision(seconds=6.555)
+        self.test_seconds_precision(seconds=6.5555)
+        self.test_seconds_precision(seconds=6.55555)
+        self.test_seconds_precision(seconds=6.555555)
+        self.test_seconds_precision(seconds=6.5555555)
+        self.test_seconds_precision(seconds=6.55555555)
+        self.test_seconds_precision(seconds=6.555555555)
 
-    try:
-        from persistent.timestamp import pyTimeStamp
-        from persistent.timestamp import TimeStamp
-    except ImportError: # pragma: no cover
-        pass
-    else:
-        if pyTimeStamp != TimeStamp:
-            # We have both implementations available
-            suite.append(unittest.makeSuite(PyAndCComparisonTests))
-
-    return unittest.TestSuite(suite)
+def test_suite():
+    return unittest.defaultTestLoader.loadTestsFromName(__name__)