Agreed with Antoine, strftime/strptime are somewhat different concerns.
Doesn't mean thay cannot be fixed at the same time but it's a bit a separate.

I'm not sure this thread / discussion has reached critical mass yet, meanwhile I was looking at what was involved and came up with this half-baked patch - by no way meant to be complete or correct, but rather get a feel to it.

I can't help thinking this is much more involved than I first expected, and what I try to achieve should be reasonably simple.

Stepping back a little, I wonder if the datetime module is really the right location, that has constructor(year, month, day, ..., second, microsecond) - with 0<ms<999999, no millis. adding 0<ns<999 would seem quite ugly, in fact nothing looks quite right.

datetime seems to be dealing with 'calendar time' stuff - and to some extent, maybe, shouldn't concern itself so much with fraction of seconds.

I'm pondering now if the 'time' module that seems to be dealing with 'computer clock time' wouldn't be a better target to introduce struct_timespec and the like.

I'd be curious to hear back from this list, if this deserves more investigation or what might be a better way to go.

Regards,
Matthieu


On 12/11/2014 11:46 AM, Antoine Pitrou wrote:
On Thu, 11 Dec 2014 13:43:05 -0600
Skip Montanaro <skip.montan...@gmail.com> wrote:
On Thu, Dec 11, 2014 at 1:23 PM, Antoine Pitrou <solip...@pitrou.net> wrote:
I think strftime / strptime support is a low-priority concern on this
topic, and can probably be discussed independently of the core
nanosecond support.

Might be low-priority, but with %f support as a template, supporting
something to specify nanoseconds should be pretty trivial. The hardest
question will be to convince ourselves that we aren't choosing a
format code which some other strftime/strptime implementation is
already using.

In addition, ISTR that one of the use cases was analysis of datetime
data generated by other applications which has nanosecond resolution.

One of the use cases is to deal with OS-generated timestamps without
losing information. As long as you don't need to represent or parse
those timestamps, strptime / strftime don't come into the picture.

Regards

Antoine.
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/mdcb808%40gmail.com



--
Matthieu Bec                GMTO Corp
cell : +1 626 425 7923      251 S Lake Ave, Suite 300
phone: +1 626 204 0527      Pasadena, CA 91101
diff -r 5754f069b123 Include/datetime.h
--- a/Include/datetime.h	Sat Nov 22 12:54:57 2014 -0800
+++ b/Include/datetime.h	Tue Dec 16 09:04:35 2014 -0800
@@ -18,18 +18,34 @@
  *  5           minute   1 byte, 0-59
  *  6           second   1 byte, 0-59
  *  7           usecond  3 bytes, 0-999999
- * 10
+ * 10           nsecond  2 bytes, 0-999
+ * 12
  */
 
 /* # of bytes for year, month, and day. */
 #define _PyDateTime_DATE_DATASIZE 4
 
-/* # of bytes for hour, minute, second, and usecond. */
-#define _PyDateTime_TIME_DATASIZE 6
+/* # of bytes for hour, minute, second, usecond and nsecond. */
+#define _PyDateTime_TIME_DATASIZE 8
+#define _PyDateTime_TIME_DATASIZE_V0 6 /* older version used for backward compatibility access */
 
-/* # of bytes for year, month, day, hour, minute, second, and usecond. */
-#define _PyDateTime_DATETIME_DATASIZE 10
+/* # of bytes for year, month, day, hour, minute, second, usecond and nsecond. */
+#define _PyDateTime_DATETIME_DATASIZE 12
+#define _PyDateTime_DATETIME_DATASIZE_V0 10 /* older version used for backward compatibility access */
 
+/* max usecond is hex(1e6) = 0x0f4240, hence the 4 upper bits that are not used to encode the
+ * number of milliseconds can be used for pickle versioning.
+ */
+#define _PyDateTime_USECOND_MSB_VALUE_MASK 0x0f
+#define _PyDateTime_USECOND_MSB_PICKLEVERSION_MASK 0xf0
+/* up to 15 pickle versions are available
+ * version 0 is vanilla
+ * version 1 adds nanosecond (this version)
+ * version 2..15 are available for future upgrades
+ */
+#define _PyDateTime_PICKLE_V0_VANILLA 0
+#define _PyDateTime_PICKLE_V1_NANOSECOND 1
+#define _PyDateTime_PICKLE_CURRENT_VERSION _PyDateTime_PICKLE_V1_NANOSECOND
 
 typedef struct
 {
@@ -38,6 +54,7 @@
     int days;                   /* -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS */
     int seconds;                /* 0 <= seconds < 24*3600 is invariant */
     int microseconds;           /* 0 <= microseconds < 1000000 is invariant */
+    int nanoseconds;            /* 0 <= nanoseconds < 1000 is invariant */
 } PyDateTime_Delta;
 
 typedef struct
@@ -122,18 +139,30 @@
 #define PyDateTime_DATE_GET_MINUTE(o)      (((PyDateTime_DateTime*)o)->data[5])
 #define PyDateTime_DATE_GET_SECOND(o)      (((PyDateTime_DateTime*)o)->data[6])
 #define PyDateTime_DATE_GET_MICROSECOND(o)              \
-    ((((PyDateTime_DateTime*)o)->data[7] << 16) |       \
+    (((((PyDateTime_DateTime*)o)->data[7] & _PyDateTime_USECOND_MSB_VALUE_MASK) << 16) |       \
      (((PyDateTime_DateTime*)o)->data[8] << 8)  |       \
       ((PyDateTime_DateTime*)o)->data[9])
+#define PyDateTime_DATE_GET_NANOSECOND(o)               \
+    ((((PyDateTime_Date*)o)->data[10] << 8) | \
+     ((PyDateTime_Date*)o)->data[11])
+
+#define PyDateTime_DATE_PICKLE_GET_VERSION(o)  (((((PyDateTime_DateTime*)o)->data[7]) & _PyDateTime_USECOND_MSB_PICKLEVERSION_MASK) >> 8 )
+#define PyDateTime_DATE_PICKLE_SET_VERSION(o,v)  (((PyDateTime_DateTime*)o)->data[7] |= (v<<8))
 
 /* Apply for time instances. */
 #define PyDateTime_TIME_GET_HOUR(o)        (((PyDateTime_Time*)o)->data[0])
 #define PyDateTime_TIME_GET_MINUTE(o)      (((PyDateTime_Time*)o)->data[1])
 #define PyDateTime_TIME_GET_SECOND(o)      (((PyDateTime_Time*)o)->data[2])
 #define PyDateTime_TIME_GET_MICROSECOND(o)              \
-    ((((PyDateTime_Time*)o)->data[3] << 16) |           \
+    (((((PyDateTime_Time*)o)->data[3] & _PyDateTime_USECOND_MSB_VALUE_MASK) << 16) |           \
      (((PyDateTime_Time*)o)->data[4] << 8)  |           \
       ((PyDateTime_Time*)o)->data[5])
+#define PyDateTime_TIME_GET_NANOSECOND(o)               \
+    ((((PyDateTime_Date*)o)->data[6] << 8) | \
+     ((PyDateTime_Date*)o)->data[7])
+
+#define PyDateTime_TIME_PICKLE_GET_VERSION(o)  (((((PyDateTime_Time*)o)->data[3]) & _PyDateTime_USECOND_MSB_PICKLEVERSION_MASK) >> 8 )
+#define PyDateTime_TIME_PICKLE_SET_VERSION(o,v)  (((PyDateTime_DateTime*)o)->data[3] |= (v<<8))
 
 /* Apply for time delta instances */
 #define PyDateTime_DELTA_GET_DAYS(o)         (((PyDateTime_Delta*)o)->days)
@@ -153,13 +182,14 @@
 
     /* constructors */
     PyObject *(*Date_FromDate)(int, int, int, PyTypeObject*);
-    PyObject *(*DateTime_FromDateAndTime)(int, int, int, int, int, int, int,
+    PyObject *(*DateTime_FromDateAndTime)(int, int, int, int, int, int, int, int,
         PyObject*, PyTypeObject*);
-    PyObject *(*Time_FromTime)(int, int, int, int, PyObject*, PyTypeObject*);
-    PyObject *(*Delta_FromDelta)(int, int, int, int, PyTypeObject*);
+    PyObject *(*Time_FromTime)(int, int, int, int, int, PyObject*, PyTypeObject*);
+    PyObject *(*Delta_FromDelta)(int, int, int, int, int, PyTypeObject*);
 
     /* constructors for the DB API */
     PyObject *(*DateTime_FromTimestamp)(PyObject*, PyObject*, PyObject*);
+    PyObject *(*DateTime_FromTimespec)(PyObject*, PyObject*, PyObject*);
     PyObject *(*Date_FromTimestamp)(PyObject*, PyObject*);
 
 } PyDateTime_CAPI;
@@ -230,6 +260,10 @@
     PyDateTimeAPI->DateTime_FromTimestamp( \
         (PyObject*) (PyDateTimeAPI->DateTimeType), args, NULL)
 
+#define PyDateTime_FromTimespec(args) \
+    PyDateTimeAPI->DateTime_FromTimespec( \
+        (PyObject*) (PyDateTimeAPI->DateTimeType), args, NULL)
+
 #define PyDate_FromTimestamp(args) \
     PyDateTimeAPI->Date_FromTimestamp( \
         (PyObject*) (PyDateTimeAPI->DateType), args)
diff -r 5754f069b123 Lib/datetime.py
--- a/Lib/datetime.py	Sat Nov 22 12:54:57 2014 -0800
+++ b/Lib/datetime.py	Tue Dec 16 09:04:35 2014 -0800
@@ -631,6 +631,7 @@
 
     __new__()
     fromtimestamp()
+    fromtimespec()
     today()
     fromordinal()
 
@@ -683,7 +684,7 @@
         "Construct a date from a POSIX timestamp (like time.time())."
         y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t)
         return cls(y, m, d)
-
+    
     @classmethod
     def today(cls):
         "Construct a date from time.time()."
@@ -1388,6 +1389,12 @@
             result = tz.fromutc(result)
         return result
 
+    
+    @classmethod
+    def fromtimespec(cls, t):
+        "Construct a date from a POSIX timespec."
+        return cls(t.tv_sec + 1e-9 * t.tv_nsec)
+
     @classmethod
     def utcfromtimestamp(cls, t):
         "Construct a UTC datetime from a POSIX timestamp (like time.time())."
diff -r 5754f069b123 Modules/_datetimemodule.c
--- a/Modules/_datetimemodule.c	Sat Nov 22 12:54:57 2014 -0800
+++ b/Modules/_datetimemodule.c	Tue Dec 16 09:04:35 2014 -0800
@@ -50,6 +50,7 @@
 #define DATE_GET_MINUTE         PyDateTime_DATE_GET_MINUTE
 #define DATE_GET_SECOND         PyDateTime_DATE_GET_SECOND
 #define DATE_GET_MICROSECOND    PyDateTime_DATE_GET_MICROSECOND
+#define DATE_GET_NANOSECOND     PyDateTime_DATE_GET_NANOSECOND
 
 /* Date accessors for date and datetime. */
 #define SET_YEAR(o, v)          (((o)->data[0] = ((v) & 0xff00) >> 8), \
@@ -62,31 +63,39 @@
 #define DATE_SET_MINUTE(o, v)   (PyDateTime_DATE_GET_MINUTE(o) = (v))
 #define DATE_SET_SECOND(o, v)   (PyDateTime_DATE_GET_SECOND(o) = (v))
 #define DATE_SET_MICROSECOND(o, v)      \
-    (((o)->data[7] = ((v) & 0xff0000) >> 16), \
+    (((o)->data[7] = (((v) & 0xff0000) >> 16) & _PyDateTime_PICKLE_CURRENT_VERSION), \
      ((o)->data[8] = ((v) & 0x00ff00) >> 8), \
      ((o)->data[9] = ((v) & 0x0000ff)))
-
+#define DATE_SET_NANOSECOND(o, v)      \
+    (((o)->data[10] = ((v) & 0xff00) >> 8), \
+     ((o)->data[11] = ((v) & 0x00ff)))
 /* Time accessors for time. */
 #define TIME_GET_HOUR           PyDateTime_TIME_GET_HOUR
 #define TIME_GET_MINUTE         PyDateTime_TIME_GET_MINUTE
 #define TIME_GET_SECOND         PyDateTime_TIME_GET_SECOND
 #define TIME_GET_MICROSECOND    PyDateTime_TIME_GET_MICROSECOND
+#define TIME_GET_NANOSECOND     PyDateTime_TIME_GET_NANOSECOND
 #define TIME_SET_HOUR(o, v)     (PyDateTime_TIME_GET_HOUR(o) = (v))
 #define TIME_SET_MINUTE(o, v)   (PyDateTime_TIME_GET_MINUTE(o) = (v))
 #define TIME_SET_SECOND(o, v)   (PyDateTime_TIME_GET_SECOND(o) = (v))
 #define TIME_SET_MICROSECOND(o, v)      \
-    (((o)->data[3] = ((v) & 0xff0000) >> 16), \
+    (((o)->data[3] = (((v) & 0xff0000) >> 16) & _PyDateTime_PICKLE_CURRENT_VERSION), \
      ((o)->data[4] = ((v) & 0x00ff00) >> 8), \
      ((o)->data[5] = ((v) & 0x0000ff)))
+#define TIME_SET_NANOSECOND(o, v)      \
+    (((o)->data[6] = ((v) & 0xff00) >> 8), \
+     ((o)->data[7] = ((v) & 0x00ff)))
 
 /* Delta accessors for timedelta. */
 #define GET_TD_DAYS(o)          (((PyDateTime_Delta *)(o))->days)
 #define GET_TD_SECONDS(o)       (((PyDateTime_Delta *)(o))->seconds)
 #define GET_TD_MICROSECONDS(o)  (((PyDateTime_Delta *)(o))->microseconds)
+#define GET_TD_NANOSECONDS(o)   (((PyDateTime_Delta *)(o))->nanoseconds)
 
 #define SET_TD_DAYS(o, v)       ((o)->days = (v))
 #define SET_TD_SECONDS(o, v)    ((o)->seconds = (v))
 #define SET_TD_MICROSECONDS(o, v) ((o)->microseconds = (v))
+#define SET_TD_NANOSECONDS(o, v)  ((o)->nanoseconds = (v))
 
 /* p is a pointer to a time or a datetime object; HASTZINFO(p) returns
  * p->hastzinfo.
@@ -103,12 +112,14 @@
 #define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12)
 
 /* Forward declarations. */
+static int initialized;
 static PyTypeObject PyDateTime_DateType;
 static PyTypeObject PyDateTime_DateTimeType;
 static PyTypeObject PyDateTime_DeltaType;
 static PyTypeObject PyDateTime_TimeType;
 static PyTypeObject PyDateTime_TZInfoType;
 static PyTypeObject PyDateTime_TimeZoneType;
+static PyTypeObject PyDateTime_StructTimespecType;
 
 _Py_IDENTIFIER(as_integer_ratio);
 _Py_IDENTIFIER(fromutc);
@@ -669,7 +680,7 @@
 /* Create a datetime instance with no range checking. */
 static PyObject *
 new_datetime_ex(int year, int month, int day, int hour, int minute,
-             int second, int usecond, PyObject *tzinfo, PyTypeObject *type)
+             int second, int usecond, int nsecond, PyObject *tzinfo, PyTypeObject *type)
 {
     PyDateTime_DateTime *self;
     char aware = tzinfo != Py_None;
@@ -682,6 +693,7 @@
         DATE_SET_MINUTE(self, minute);
         DATE_SET_SECOND(self, second);
         DATE_SET_MICROSECOND(self, usecond);
+        DATE_SET_NANOSECOND(self, nsecond);
         if (aware) {
             Py_INCREF(tzinfo);
             self->tzinfo = tzinfo;
@@ -690,14 +702,14 @@
     return (PyObject *)self;
 }
 
-#define new_datetime(y, m, d, hh, mm, ss, us, tzinfo)           \
-    new_datetime_ex(y, m, d, hh, mm, ss, us, tzinfo,            \
+#define new_datetime(y, m, d, hh, mm, ss, us, ns, tzinfo)           \
+    new_datetime_ex(y, m, d, hh, mm, ss, us, ns, tzinfo,            \
                     &PyDateTime_DateTimeType)
 
 /* Create a time instance with no range checking. */
 static PyObject *
 new_time_ex(int hour, int minute, int second, int usecond,
-            PyObject *tzinfo, PyTypeObject *type)
+            int nsecond, PyObject *tzinfo, PyTypeObject *type)
 {
     PyDateTime_Time *self;
     char aware = tzinfo != Py_None;
@@ -710,6 +722,7 @@
         TIME_SET_MINUTE(self, minute);
         TIME_SET_SECOND(self, second);
         TIME_SET_MICROSECOND(self, usecond);
+        TIME_SET_NANOSECOND(self, nsecond);
         if (aware) {
             Py_INCREF(tzinfo);
             self->tzinfo = tzinfo;
@@ -718,8 +731,8 @@
     return (PyObject *)self;
 }
 
-#define new_time(hh, mm, ss, us, tzinfo)                \
-    new_time_ex(hh, mm, ss, us, tzinfo, &PyDateTime_TimeType)
+#define new_time(hh, mm, ss, us, ns, tzinfo)                \
+    new_time_ex(hh, mm, ss, us, ns, tzinfo, &PyDateTime_TimeType)
 
 /* Create a timedelta instance.  Normalize the members iff normalize is
  * true.  Passing false is a speed optimization, if you know for sure
@@ -728,8 +741,8 @@
  * of range).
  */
 static PyObject *
-new_delta_ex(int days, int seconds, int microseconds, int normalize,
-             PyTypeObject *type)
+new_delta_ex(int days, int seconds, int microseconds, int nanoseconds,
+             int normalize, PyTypeObject *type)
 {
     PyDateTime_Delta *self;
 
@@ -747,12 +760,13 @@
         SET_TD_DAYS(self, days);
         SET_TD_SECONDS(self, seconds);
         SET_TD_MICROSECONDS(self, microseconds);
+        SET_TD_NANOSECONDS(self, nanoseconds);
     }
     return (PyObject *) self;
 }
 
-#define new_delta(d, s, us, normalize)  \
-    new_delta_ex(d, s, us, normalize, &PyDateTime_DeltaType)
+#define new_delta(d, s, us, ns, normalize)  \
+    new_delta_ex(d, s, us, ns, normalize, &PyDateTime_DeltaType)
 
 
 typedef struct
@@ -1131,6 +1145,20 @@
     return PyBytes_FromStringAndSize(freplacement, strlen(freplacement));
 }
 
+static PyObject *
+make_Nreplacement(PyObject *object)
+{
+    char Nreplacement[64];
+    if (PyTime_Check(object))
+        sprintf(Nreplacement, "%09d", (int) (TIME_GET_MICROSECOND(object) * 1e3 + TIME_GET_NANOSECOND(object)));
+    else if (PyDateTime_Check(object))
+        sprintf(Nreplacement, "%09d", (int) (DATE_GET_MICROSECOND(object) * 1e3 + DATE_GET_NANOSECOND(object)));
+    else
+        sprintf(Nreplacement, "%09d", 0);
+
+    return PyBytes_FromStringAndSize(Nreplacement, strlen(Nreplacement));
+}
+
 /* I sure don't want to reproduce the strftime code from the time module,
  * so this imports the module and calls it.  All the hair is due to
  * giving special meanings to the %z, %Z and %f format codes via a
@@ -1147,6 +1175,7 @@
     PyObject *zreplacement = NULL;      /* py string, replacement for %z */
     PyObject *Zreplacement = NULL;      /* py string, replacement for %Z */
     PyObject *freplacement = NULL;      /* py string, replacement for %f */
+    PyObject *Nreplacement = NULL;      /* py string, replacement for %N */
 
     const char *pin;            /* pointer to next char in input format */
     Py_ssize_t flen;            /* length of input format */
@@ -1249,6 +1278,18 @@
             ptoappend = PyBytes_AS_STRING(freplacement);
             ntoappend = PyBytes_GET_SIZE(freplacement);
         }
+        else if (ch == 'N') {
+            /* format nanoseconds */
+            if (Nreplacement == NULL) {
+                Nreplacement = make_Nreplacement(object);
+                if (Nreplacement == NULL)
+                    goto Done;
+            }
+            assert(Nreplacement != NULL);
+            assert(PyBytes_Check(Nreplacement));
+            ptoappend = PyBytes_AS_STRING(Nreplacement);
+            ntoappend = PyBytes_GET_SIZE(Nreplacement);
+        }
         else {
             /* percent followed by neither z nor Z */
             ptoappend = pin - 2;
@@ -1295,6 +1336,7 @@
         Py_DECREF(time);
     }
  Done:
+    Py_XDECREF(Nreplacement);
     Py_XDECREF(freplacement);
     Py_XDECREF(zreplacement);
     Py_XDECREF(Zreplacement);
@@ -1537,7 +1579,7 @@
                         "large to fit in a C int");
         goto Done;
     }
-    result = new_delta_ex(d, s, us, 0, type);
+    result = new_delta_ex(d, s, us, 0 /* XXX ns */, 0, type);
 
 Done:
     Py_XDECREF(tuple);
@@ -1730,7 +1772,7 @@
         int seconds = GET_TD_SECONDS(left) + GET_TD_SECONDS(right);
         int microseconds = GET_TD_MICROSECONDS(left) +
                            GET_TD_MICROSECONDS(right);
-        result = new_delta(days, seconds, microseconds, 1);
+        result = new_delta(days, seconds, microseconds, 0 /* ns XXX */,1);
     }
 
     if (result == Py_NotImplemented)
@@ -1743,7 +1785,7 @@
 {
     return new_delta(-GET_TD_DAYS(self),
                      -GET_TD_SECONDS(self),
-                     -GET_TD_MICROSECONDS(self),
+                     -GET_TD_MICROSECONDS(self), 0 /* ns XXX */,
                      1);
 }
 
@@ -1755,7 +1797,7 @@
      */
     return new_delta(GET_TD_DAYS(self),
                      GET_TD_SECONDS(self),
-                     GET_TD_MICROSECONDS(self),
+                     GET_TD_MICROSECONDS(self), 0 /* ns XXX */,
                      0);
 }
 
@@ -1789,7 +1831,7 @@
         int seconds = GET_TD_SECONDS(left) - GET_TD_SECONDS(right);
         int microseconds = GET_TD_MICROSECONDS(left) -
                            GET_TD_MICROSECONDS(right);
-        result = new_delta(days, seconds, microseconds, 1);
+        result = new_delta(days, seconds, microseconds, 0 /* ns XXX */, 1);
     }
 
     if (result == Py_NotImplemented)
@@ -2608,7 +2650,7 @@
             int right_ord = ymd_to_ord(GET_YEAR(right),
                                        GET_MONTH(right),
                                        GET_DAY(right));
-            return new_delta(left_ord - right_ord, 0, 0, 0);
+            return new_delta(left_ord - right_ord, 0, 0, 0, 0);
         }
         if (PyDelta_Check(right)) {
             /* date - delta */
@@ -3420,6 +3462,21 @@
     timezone_new,                     /* tp_new */
 };
 
+static PyStructSequence_Field struct_timespec_type_fields[] = {
+    {"tv_sec", "seconds"},
+    {"tv_nsec", "nanoseconds"},
+    {0}
+};
+
+static PyStructSequence_Desc struct_timespec_type_desc = {
+    "datetime.struct_timespec",
+    "POSIX.1b structure for a time value. This is like a `struct timeval' but\n"
+    "has nanoseconds instead of microseconds.",
+    struct_timespec_type_fields,
+    2,
+};
+
+
 /*
  * PyDateTime_Time implementation.
  */
@@ -3453,6 +3510,12 @@
 }
 
 static PyObject *
+time_nanosecond(PyDateTime_Time *self, void *unused)
+{
+    return PyLong_FromLong(TIME_GET_NANOSECOND(self));
+}
+
+static PyObject *
 time_tzinfo(PyDateTime_Time *self, void *unused)
 {
     PyObject *result = HASTZINFO(self) ? self->tzinfo : Py_None;
@@ -3465,7 +3528,8 @@
     {"minute",      (getter)time_minute},
     {"second",      (getter)py_time_second},
     {"microsecond", (getter)time_microsecond},
-    {"tzinfo",          (getter)time_tzinfo},
+    {"nanosecond",  (getter)time_nanosecond},
+    {"tzinfo",      (getter)time_tzinfo},
     {NULL}
 };
 
@@ -3491,7 +3555,7 @@
     if (PyTuple_GET_SIZE(args) >= 1 &&
         PyTuple_GET_SIZE(args) <= 2 &&
         PyBytes_Check(state = PyTuple_GET_ITEM(args, 0)) &&
-        PyBytes_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE &&
+        ((PyBytes_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE) || (PyBytes_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE_V0)) &&
         ((unsigned char) (PyBytes_AS_STRING(state)[0])) < 24)
     {
         PyDateTime_Time *me;
@@ -3509,8 +3573,10 @@
         me = (PyDateTime_Time *) (type->tp_alloc(type, aware));
         if (me != NULL) {
             char *pdata = PyBytes_AS_STRING(state);
-
-            memcpy(me->data, pdata, _PyDateTime_TIME_DATASIZE);
+            memset(me->data, 0, _PyDateTime_TIME_DATASIZE);
+            memcpy(me->data, pdata, PyBytes_GET_SIZE(state) /* _PyDateTime_TIME_DATASIZE */ );
+            PyDateTime_TIME_PICKLE_SET_VERSION(me, _PyDateTime_PICKLE_CURRENT_VERSION);
+            
             me->hashcode = -1;
             me->hastzinfo = aware;
             if (aware) {
@@ -3528,7 +3594,7 @@
             return NULL;
         if (check_tzinfo_subclass(tzinfo) < 0)
             return NULL;
-        self = new_time_ex(hour, minute, second, usecond, tzinfo,
+        self = new_time_ex(hour, minute, second, usecond, 0 /* ns XXX */, tzinfo,
                            type);
     }
     return self;
@@ -3579,9 +3645,13 @@
     int m = TIME_GET_MINUTE(self);
     int s = TIME_GET_SECOND(self);
     int us = TIME_GET_MICROSECOND(self);
+    int ns = TIME_GET_NANOSECOND(self);
     PyObject *result = NULL;
 
-    if (us)
+    if (ns)
+        result = PyUnicode_FromFormat("%s(%d, %d, %d, %d, %d)",
+                                      type_name, h, m, s, us, ns);
+    else if (us)
         result = PyUnicode_FromFormat("%s(%d, %d, %d, %d)",
                                       type_name, h, m, s, us);
     else if (s)
@@ -3606,8 +3676,16 @@
     char buf[100];
     PyObject *result;
     int us = TIME_GET_MICROSECOND(self);
-
-    if (us)
+    int ns = TIME_GET_NANOSECOND(self);
+    
+    if (ns)
+        result = PyUnicode_FromFormat("%02d:%02d:%02d.%09d",
+                                      TIME_GET_HOUR(self),
+                                      TIME_GET_MINUTE(self),
+                                      TIME_GET_SECOND(self),
+                                      ns + 1e3 * us);
+
+    else if (us)
         result = PyUnicode_FromFormat("%02d:%02d:%02d.%06d",
                                       TIME_GET_HOUR(self),
                                       TIME_GET_MINUTE(self),
@@ -3717,8 +3795,8 @@
                    GET_TD_SECONDS(offset2);
         diff = offsecs1 - offsecs2;
         if (diff == 0)
-            diff = TIME_GET_MICROSECOND(self) -
-                   TIME_GET_MICROSECOND(other);
+            diff = TIME_GET_MICROSECOND(self) * 1e3 + TIME_GET_NANOSECOND(self) -
+                   TIME_GET_MICROSECOND(other) * 1e3 - TIME_GET_NANOSECOND(other);
         result = diff_to_bool(diff, op);
     }
     else if (op == Py_EQ) {
@@ -3757,13 +3835,14 @@
                 (unsigned char *)self->data, _PyDateTime_TIME_DATASIZE);
         else {
             PyObject *temp1, *temp2;
-            int seconds, microseconds;
+            int seconds, microseconds, nanoseconds;
             assert(HASTZINFO(self));
             seconds = TIME_GET_HOUR(self) * 3600 +
                       TIME_GET_MINUTE(self) * 60 +
                       TIME_GET_SECOND(self);
             microseconds = TIME_GET_MICROSECOND(self);
-            temp1 = new_delta(0, seconds, microseconds, 1);
+            nanoseconds = TIME_GET_NANOSECOND(self);
+            temp1 = new_delta(0, seconds, microseconds, nanoseconds, 1);
             if (temp1 == NULL) {
                 Py_DECREF(offset);
                 return -1;
@@ -3791,13 +3870,14 @@
     int mm = TIME_GET_MINUTE(self);
     int ss = TIME_GET_SECOND(self);
     int us = TIME_GET_MICROSECOND(self);
+    int ns = TIME_GET_NANOSECOND(self);
     PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None;
 
-    if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO:replace",
+    if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiiO:replace",
                                       time_kws,
-                                      &hh, &mm, &ss, &us, &tzinfo))
+                                      &hh, &mm, &ss, &us, &ns, &tzinfo))
         return NULL;
-    tuple = Py_BuildValue("iiiiO", hh, mm, ss, us, tzinfo);
+    tuple = Py_BuildValue("iiiiiO", hh, mm, ss, us, ns, tzinfo);
     if (tuple == NULL)
         return NULL;
     clone = time_new(Py_TYPE(self), tuple, NULL);
@@ -3947,6 +4027,12 @@
 }
 
 static PyObject *
+datetime_nanosecond(PyDateTime_DateTime *self, void *unused)
+{
+    return PyLong_FromLong(DATE_GET_NANOSECOND(self));
+}
+
+static PyObject *
 datetime_tzinfo(PyDateTime_DateTime *self, void *unused)
 {
     PyObject *result = HASTZINFO(self) ? self->tzinfo : Py_None;
@@ -3959,7 +4045,8 @@
     {"minute",      (getter)datetime_minute},
     {"second",      (getter)datetime_second},
     {"microsecond", (getter)datetime_microsecond},
-    {"tzinfo",          (getter)datetime_tzinfo},
+    {"nanosecond",  (getter)datetime_nanosecond},
+    {"tzinfo",      (getter)datetime_tzinfo},
     {NULL}
 };
 
@@ -3990,7 +4077,7 @@
     if (PyTuple_GET_SIZE(args) >= 1 &&
         PyTuple_GET_SIZE(args) <= 2 &&
         PyBytes_Check(state = PyTuple_GET_ITEM(args, 0)) &&
-        PyBytes_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE &&
+        ((PyBytes_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE) || (PyBytes_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE_V0)) &&
         MONTH_IS_SANE(PyBytes_AS_STRING(state)[2]))
     {
         PyDateTime_DateTime *me;
@@ -4009,7 +4096,11 @@
         if (me != NULL) {
             char *pdata = PyBytes_AS_STRING(state);
 
-            memcpy(me->data, pdata, _PyDateTime_DATETIME_DATASIZE);
+            memset(me->data, 0, _PyDateTime_DATETIME_DATASIZE);
+            memcpy(me->data, pdata, PyBytes_GET_SIZE(state) /* _PyDateTime_DATETIME_DATASIZE */);
+
+            PyDateTime_DATE_PICKLE_SET_VERSION(me, _PyDateTime_PICKLE_CURRENT_VERSION);
+
             me->hashcode = -1;
             me->hastzinfo = aware;
             if (aware) {
@@ -4030,7 +4121,7 @@
         if (check_tzinfo_subclass(tzinfo) < 0)
             return NULL;
         self = new_datetime_ex(year, month, day,
-                                hour, minute, second, usecond,
+                                hour, minute, second, usecond, 0 /* ns XXX */,
                                 tzinfo, type);
     }
     return self;
@@ -4040,11 +4131,11 @@
 typedef struct tm *(*TM_FUNC)(const time_t *timer);
 
 /* Internal helper.
- * Build datetime from a time_t and a distinct count of microseconds.
+ * Build datetime from a time_t and a distinct count of nanoseconds.
  * Pass localtime or gmtime for f, to control the interpretation of timet.
  */
 static PyObject *
-datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us,
+datetime_from_timet_and_ns(PyObject *cls, TM_FUNC f, time_t timet, int ns,
                            PyObject *tzinfo)
 {
     struct tm *tm;
@@ -4073,7 +4164,7 @@
                                  tm->tm_hour,
                                  tm->tm_min,
                                  tm->tm_sec,
-                                 us,
+                                 (int) (ns / 1e3), // XXX
                                  tzinfo);
 }
 
@@ -4081,7 +4172,7 @@
  * Build datetime from a Python timestamp.  Pass localtime or gmtime for f,
  * to control the interpretation of the timestamp.  Since a double doesn't
  * have enough bits to cover a datetime's full range of precision, it's
- * better to call datetime_from_timet_and_us provided you have a way
+ * better to call datetime_from_timet_and_ns provided you have a way
  * to get that much precision (e.g., C time() isn't good enough).
  */
 static PyObject *
@@ -4093,7 +4184,31 @@
 
     if (_PyTime_ObjectToTimeval(timestamp, &timet, &us, _PyTime_ROUND_DOWN) == -1)
         return NULL;
-    return datetime_from_timet_and_us(cls, f, timet, (int)us, tzinfo);
+    return datetime_from_timet_and_ns(cls, f, timet, (int) (us * 1e3), tzinfo);
+}
+
+/* Internal helper.
+ * Build datetime from a Python struct timespec.
+ */
+static PyObject *
+datetime_from_timespec(PyObject *cls, TM_FUNC f, PyObject *args,
+                        PyObject *tzinfo)
+{
+    struct timespec ts;
+
+    if (!PyTuple_Check(args)) {
+        PyErr_SetString(PyExc_TypeError,
+                        "Tuple or struct_timespec argument required");
+        return NULL;
+    }
+
+    if (!PyArg_ParseTuple(args, "ii",
+                          &ts.tv_sec, &ts.tv_nsec))
+        return NULL;
+
+    return datetime_from_timet_and_ns(cls, f, ts.tv_sec, ts.tv_nsec,
+                                      tzinfo);
+
 }
 
 /* Internal helper.
@@ -4105,7 +4220,7 @@
 {
     _PyTime_timeval t;
     _PyTime_gettimeofday(&t);
-    return datetime_from_timet_and_us(cls, f, t.tv_sec, (int)t.tv_usec,
+    return datetime_from_timet_and_ns(cls, f, t.tv_sec, (int) (t.tv_usec * 1e3),
                                       tzinfo);
 }
 
@@ -4219,6 +4334,24 @@
     return self;
 }
 
+/* Return new local datetime from struct timespec. */
+static PyObject *
+datetime_fromtimespec(PyObject *cls, PyObject *args, PyObject *kw)
+{
+    PyObject *self;
+    PyObject *timespec;
+    static char *keywords[] = {"timespec", NULL};
+
+    if (! PyArg_ParseTupleAndKeywords(args, kw, "O:fromtimespec",
+                                      keywords, &timespec))
+        return NULL;
+
+    self = datetime_from_timespec(cls, gmtime,
+                                   timespec, Py_None);
+    return self;
+}
+
+
 /* Return new UTC datetime from timestamp (Python timestamp -- a double). */
 static PyObject *
 datetime_utcfromtimestamp(PyObject *cls, PyObject *args)
@@ -4268,7 +4401,7 @@
 
         if (HASTZINFO(time))
             tzinfo = ((PyDateTime_Time *)time)->tzinfo;
-        result = PyObject_CallFunction(cls, "iiiiiiiO",
+        result = PyObject_CallFunction(cls, "iiiiiiiiO",
                                         GET_YEAR(date),
                                         GET_MONTH(date),
                                         GET_DAY(date),
@@ -4276,6 +4409,7 @@
                                         TIME_GET_MINUTE(time),
                                         TIME_GET_SECOND(time),
                                         TIME_GET_MICROSECOND(time),
+                                        TIME_GET_NANOSECOND(time),
                                         tzinfo);
     }
     return result;
@@ -4343,7 +4477,7 @@
         return NULL;
     else
         return new_datetime(year, month, day,
-                            hour, minute, second, microsecond,
+                            hour, minute, second, microsecond, 0 /* ns XXX */,
                             HASTZINFO(date) ? date->tzinfo : Py_None);
 }
 
@@ -4432,7 +4566,7 @@
                        DATE_GET_SECOND(right));
             delta_us = DATE_GET_MICROSECOND(left) -
                        DATE_GET_MICROSECOND(right);
-            result = new_delta(delta_d, delta_s, delta_us, 1);
+            result = new_delta(delta_d, delta_s, delta_us, 0 /* ns XXX */, 1);
             if (result == NULL)
                 return NULL;
 
@@ -4465,7 +4599,17 @@
     const char *type_name = Py_TYPE(self)->tp_name;
     PyObject *baserepr;
 
-    if (DATE_GET_MICROSECOND(self)) {
+    if (DATE_GET_NANOSECOND(self)) {
+        baserepr = PyUnicode_FromFormat(
+                      "%s(%d, %d, %d, %d, %d, %d, %d, %d)",
+                      type_name,
+                      GET_YEAR(self), GET_MONTH(self), GET_DAY(self),
+                      DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
+                      DATE_GET_SECOND(self),
+                      DATE_GET_MICROSECOND(self),
+                      DATE_GET_NANOSECOND(self));
+    }
+    else if (DATE_GET_MICROSECOND(self)) {
         baserepr = PyUnicode_FromFormat(
                       "%s(%d, %d, %d, %d, %d, %d, %d)",
                       type_name,
@@ -4508,10 +4652,17 @@
     char buffer[100];
     PyObject *result;
     int us = DATE_GET_MICROSECOND(self);
+    int ns = DATE_GET_NANOSECOND(self);
 
     if (!PyArg_ParseTupleAndKeywords(args, kw, "|C:isoformat", keywords, &sep))
         return NULL;
-    if (us)
+    if (ns)
+        result = PyUnicode_FromFormat("%04d-%02d-%02d%c%02d:%02d:%02d.%09d",
+                                      GET_YEAR(self), GET_MONTH(self),
+                                      GET_DAY(self), (int)sep,
+                                      DATE_GET_HOUR(self), DATE_GET_MINUTE(self),
+                                      DATE_GET_SECOND(self), us * 1e3 + ns);
+    else if (us)
         result = PyUnicode_FromFormat("%04d-%02d-%02d%c%02d:%02d:%02d.%06d",
                                       GET_YEAR(self), GET_MONTH(self),
                                       GET_DAY(self), (int)sep,
@@ -4658,7 +4809,7 @@
                       DATE_GET_MINUTE(self) * 60 +
                       DATE_GET_SECOND(self);
             temp1 = new_delta(days, seconds,
-                              DATE_GET_MICROSECOND(self),
+                              DATE_GET_MICROSECOND(self), 0 /* ns XXX */,
                               1);
             if (temp1 == NULL) {
                 Py_DECREF(offset);
@@ -4690,14 +4841,15 @@
     int mm = DATE_GET_MINUTE(self);
     int ss = DATE_GET_SECOND(self);
     int us = DATE_GET_MICROSECOND(self);
+    int ns = DATE_GET_NANOSECOND(self);
     PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None;
 
-    if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiiiiO:replace",
+    if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiiiiiO:replace",
                                       datetime_kws,
                                       &y, &m, &d, &hh, &mm, &ss, &us,
-                                      &tzinfo))
+                                      &ns, &tzinfo))
         return NULL;
-    tuple = Py_BuildValue("iiiiiiiO", y, m, d, hh, mm, ss, us, tzinfo);
+    tuple = Py_BuildValue("iiiiiiiiO", y, m, d, hh, mm, ss, us, ns, tzinfo);
     if (tuple == NULL)
         return NULL;
     clone = datetime_new(Py_TYPE(self), tuple, NULL);
@@ -4720,7 +4872,7 @@
     delta = datetime_subtract((PyObject *)utc_time, PyDateTime_Epoch);
     if (delta == NULL)
         return NULL;
-    one_second = new_delta(0, 1, 0, 0);
+    one_second = new_delta(0, 1, 0, 0 /* ns XXX */, 0);
     if (one_second == NULL)
         goto error;
     seconds = divide_timedelta_timedelta((PyDateTime_Delta *)delta,
@@ -4736,14 +4888,14 @@
     timep = localtime(&timestamp);
 #ifdef HAVE_STRUCT_TM_TM_ZONE
     zone = timep->tm_zone;
-    delta = new_delta(0, timep->tm_gmtoff, 0, 1);
+    delta = new_delta(0, timep->tm_gmtoff, 0, 0 /* ns XXX */, 1);
 #else /* HAVE_STRUCT_TM_TM_ZONE */
     {
         PyObject *local_time;
         local_time = new_datetime(timep->tm_year + 1900, timep->tm_mon + 1,
                                   timep->tm_mday, timep->tm_hour, timep->tm_min,
                                   timep->tm_sec, DATE_GET_MICROSECOND(utc_time),
-                                  utc_time->tzinfo);
+                                  DATE_GET_NANOSECOND(utc_time), utc_time->tzinfo);
         if (local_time == NULL)
             goto error;
         delta = datetime_subtract(local_time, (PyObject*)utc_time);
@@ -4899,7 +5051,7 @@
                             "timestamp out of range");
             return NULL;
         }
-        result = PyFloat_FromDouble(timestamp + DATE_GET_MICROSECOND(self) / 1e6);
+        result = PyFloat_FromDouble(timestamp + DATE_GET_MICROSECOND(self) / 1e6 + DATE_GET_NANOSECOND(self) / 1e9);
     }
     return result;
 }
@@ -4919,6 +5071,7 @@
                     DATE_GET_MINUTE(self),
                     DATE_GET_SECOND(self),
                     DATE_GET_MICROSECOND(self),
+                    DATE_GET_NANOSECOND(self),
                     Py_None);
 }
 
@@ -4929,6 +5082,7 @@
                     DATE_GET_MINUTE(self),
                     DATE_GET_SECOND(self),
                     DATE_GET_MICROSECOND(self),
+                    DATE_GET_NANOSECOND(self),
                     GET_DT_TZINFO(self));
 }
 
@@ -5018,6 +5172,10 @@
      METH_VARARGS | METH_KEYWORDS | METH_CLASS,
      PyDoc_STR("timestamp[, tz] -> tz's local time from POSIX timestamp.")},
 
+    {"fromtimespec", (PyCFunction)datetime_fromtimespec,
+     METH_VARARGS | METH_KEYWORDS | METH_CLASS,
+     PyDoc_STR("timespec[, tz] -> tz's local time from POSIX timestamp.")},
+
     {"utcfromtimestamp", (PyCFunction)datetime_utcfromtimestamp,
      METH_VARARGS | METH_CLASS,
      PyDoc_STR("timestamp -> UTC datetime from a POSIX timestamp "
@@ -5165,6 +5323,7 @@
     new_time_ex,
     new_delta_ex,
     datetime_fromtimestamp,
+    datetime_fromtimespec,
     date_fromtimestamp
 };
 
@@ -5210,17 +5369,17 @@
     /* timedelta values */
     d = PyDateTime_DeltaType.tp_dict;
 
-    x = new_delta(0, 0, 1, 0);
+    x = new_delta(0, 0, 1, 0 /* ns XXX */, 0);
     if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0)
         return NULL;
     Py_DECREF(x);
 
-    x = new_delta(-MAX_DELTA_DAYS, 0, 0, 0);
+    x = new_delta(-MAX_DELTA_DAYS, 0, 0, 0 /* ns XXX */, 0);
     if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
         return NULL;
     Py_DECREF(x);
 
-    x = new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0);
+    x = new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0 /* ns XXX */, 0);
     if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
         return NULL;
     Py_DECREF(x);
@@ -5238,7 +5397,7 @@
         return NULL;
     Py_DECREF(x);
 
-    x = new_delta(1, 0, 0, 0);
+    x = new_delta(1, 0, 0, 0 /* ns XXX */, 0);
     if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0)
         return NULL;
     Py_DECREF(x);
@@ -5246,17 +5405,17 @@
     /* time values */
     d = PyDateTime_TimeType.tp_dict;
 
-    x = new_time(0, 0, 0, 0, Py_None);
+    x = new_time(0, 0, 0, 0, 0 /* ns XXX */, Py_None);
     if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
         return NULL;
     Py_DECREF(x);
 
-    x = new_time(23, 59, 59, 999999, Py_None);
+    x = new_time(23, 59, 59, 999999, 0 /* ns XXX */, Py_None);
     if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
         return NULL;
     Py_DECREF(x);
 
-    x = new_delta(0, 0, 1, 0);
+    x = new_delta(0, 0, 1, 0 /* ns XXX */, 0);
     if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0)
         return NULL;
     Py_DECREF(x);
@@ -5264,17 +5423,17 @@
     /* datetime values */
     d = PyDateTime_DateTimeType.tp_dict;
 
-    x = new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None);
+    x = new_datetime(1, 1, 1, 0, 0, 0, 0, 0 /* ns XXX */, Py_None);
     if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
         return NULL;
     Py_DECREF(x);
 
-    x = new_datetime(MAXYEAR, 12, 31, 23, 59, 59, 999999, Py_None);
+    x = new_datetime(MAXYEAR, 12, 31, 23, 59, 59, 999999, 0 /* ns XXX */, Py_None);
     if (x == NULL || PyDict_SetItemString(d, "max", x) < 0)
         return NULL;
     Py_DECREF(x);
 
-    x = new_delta(0, 0, 1, 0);
+    x = new_delta(0, 0, 1, 0 /* ns XXX */, 0);
     if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0)
         return NULL;
     Py_DECREF(x);
@@ -5282,7 +5441,7 @@
     /* timezone values */
     d = PyDateTime_TimeZoneType.tp_dict;
 
-    delta = new_delta(0, 0, 0, 0);
+    delta = new_delta(0, 0, 0, 0 /* ns XXX */, 0);
     if (delta == NULL)
         return NULL;
     x = create_timezone(delta, NULL);
@@ -5291,7 +5450,7 @@
         return NULL;
     PyDateTime_TimeZone_UTC = x;
 
-    delta = new_delta(-1, 60, 0, 1); /* -23:59 */
+    delta = new_delta(-1, 60, 0, 0 /* ns XXX */, 1); /* -23:59 */
     if (delta == NULL)
         return NULL;
     x = create_timezone(delta, NULL);
@@ -5300,7 +5459,7 @@
         return NULL;
     Py_DECREF(x);
 
-    delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */
+    delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0 /* ns XXX */, 0); /* +23:59 */
     if (delta == NULL)
         return NULL;
     x = create_timezone(delta, NULL);
@@ -5310,7 +5469,7 @@
     Py_DECREF(x);
 
     /* Epoch */
-    PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0,
+    PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, 0 /* ns XXX */,
                                     PyDateTime_TimeZone_UTC);
     if (PyDateTime_Epoch == NULL)
       return NULL;
@@ -5338,6 +5497,14 @@
     Py_INCREF(&PyDateTime_TimeZoneType);
     PyModule_AddObject(m, "timezone", (PyObject *) &PyDateTime_TimeZoneType);
 
+    if (!initialized) {
+        if (PyStructSequence_InitType2(&PyDateTime_StructTimespecType,
+                                       &struct_timespec_type_desc) < 0)
+            return NULL;
+    }
+    Py_INCREF(&PyDateTime_StructTimespecType);
+    PyModule_AddObject(m, "struct_timespec", (PyObject *) &PyDateTime_StructTimespecType);
+
     x = PyCapsule_New(&CAPI, PyDateTime_CAPSULE_NAME, NULL);
     if (x == NULL)
         return NULL;
@@ -5378,6 +5545,7 @@
     us_per_week = PyLong_FromDouble(604800000000.0);
     if (us_per_hour == NULL || us_per_day == NULL || us_per_week == NULL)
         return NULL;
+    initialized = 1;
     return m;
 }
 
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to