diff --git a/bson/__init__.py b/bson/__init__.py
index 184874c..2f296dd 100644
--- a/bson/__init__.py
+++ b/bson/__init__.py
@@ -27,6 +27,7 @@ from bson.dbref import DBRef
 from bson.errors import (InvalidBSON,
                          InvalidDocument,
                          InvalidStringData)
+import bson
 from bson.max_key import MaxKey
 from bson.min_key import MinKey
 from bson.objectid import ObjectId
@@ -140,7 +141,10 @@ def _get_boolean(data, as_class, tz_aware):
 
 def _get_date(data, as_class, tz_aware):
     seconds = float(struct.unpack("<q", data[:8])[0]) / 1000.0
-    if tz_aware:
+    tz = bson.__dict__.get('tzinfo')
+    if tz:
+        return (datetime.datetime.fromtimestamp(seconds, tz), data[8:])
+    elif tz_aware:
         return (datetime.datetime.fromtimestamp(seconds, utc), data[8:])
     return (datetime.datetime.utcfromtimestamp(seconds), data[8:])
 
@@ -304,6 +308,9 @@ def _element_to_bson(key, value, check_keys):
             return "\x12" + name + struct.pack("<q", value)
         return "\x10" + name + struct.pack("<i", value)
     if isinstance(value, datetime.datetime):
+        tz = bson.__dict__.get('tzinfo')
+        if not value.tzinfo and tz:
+            value = tz.localize(value)
         if value.utcoffset() is not None:
             value = value - value.utcoffset()
         millis = int(calendar.timegm(value.timetuple()) * 1000 +
diff --git a/bson/_cbsonmodule.c b/bson/_cbsonmodule.c
index 0242829..8c7c24e 100644
--- a/bson/_cbsonmodule.c
+++ b/bson/_cbsonmodule.c
@@ -40,6 +40,7 @@ static PyObject* Timestamp = NULL;
 static PyObject* MinKey = NULL;
 static PyObject* MaxKey = NULL;
 static PyObject* UTC = NULL;
+static PyObject* Bson = NULL;
 static PyTypeObject* REType = NULL;
 
 #if PY_VERSION_HEX < 0x02050000
@@ -204,6 +205,15 @@ static int _reload_python_objects(void) {
     /* Reload our REType hack too. */
     REType = PyObject_CallFunction(RECompile, "O",
                                    PyString_FromString(""))->ob_type;
+    Bson = PyImport_ImportModule("bson");
+    if (!Bson) {
+        return 1;
+    }
+    if (!PyObject_HasAttrString(Bson, "tzinfo")) {
+        if (PyObject_SetAttrString(Bson, "tzinfo", Py_None) == -1) {
+            return 1;
+        }
+    }
     return 0;
 }
 
@@ -431,11 +441,55 @@ static int write_element_to_buffer(buffer_t buffer, int type_byte, PyObject* val
         return result;
     } else if (PyDateTime_Check(value)) {
         long long millis;
+
+        /*
+        if bson.tzinfo != None and value.tzinfo == None:
+            value = bson.tzinfo.localize(value)
+        */
+        PyObject* bson_tzinfo = PyObject_GetAttrString(Bson, "tzinfo");
+        if (!bson_tzinfo) {
+            return 0;
+        }
+        PyObject* value_tzinfo = PyObject_GetAttrString(value, "tzinfo");
+        if (!value_tzinfo) {
+            Py_DECREF(bson_tzinfo);
+            return 0;
+        }
+        Py_DECREF(value_tzinfo);
+        int use_tzinfo = bson_tzinfo != Py_None && value_tzinfo == Py_None;
+        if (use_tzinfo) {
+            PyObject* localize = PyObject_GetAttrString(bson_tzinfo, "localize");
+            Py_DECREF(bson_tzinfo);
+            if (!localize) {
+                return 0;
+            }
+            PyObject* args = PyTuple_New(1);
+            if (!args) {
+                Py_DECREF(localize);
+                return 0;
+            }
+            if (PyTuple_SetItem(args, 0, value)) {
+                Py_DECREF(localize);
+                Py_DECREF(args);
+                return 0;
+            }
+            Py_INCREF(value);
+            value = PyObject_Call(localize, args, NULL);
+            Py_DECREF(localize);
+            Py_DECREF(args);
+            if (!value) {
+                return 0;
+            }
+        } else {
+            Py_DECREF(bson_tzinfo);
+        }
+
         PyObject* utcoffset = PyObject_CallMethod(value, "utcoffset", NULL);
         if (utcoffset != Py_None) {
             PyObject* result = PyNumber_Subtract(value, utcoffset);
             Py_DECREF(utcoffset);
             if (!result) {
+                if (use_tzinfo) Py_DECREF(value);
                 return 0;
             }
             millis = millis_from_datetime(result);
@@ -443,6 +497,7 @@ static int write_element_to_buffer(buffer_t buffer, int type_byte, PyObject* val
         } else {
             millis = millis_from_datetime(value);
         }
+        if (use_tzinfo) Py_DECREF(value);
         *(buffer_get_buffer(buffer) + type_byte) = 0x09;
         return buffer_write_bytes(buffer, (const char*)&millis, 8);
     } else if (PyObject_IsInstance(value, ObjectId)) {
@@ -1021,14 +1076,20 @@ static PyObject* get_value(const char* buffer, int* position, int type,
             PyObject* kwargs;
             PyObject* naive = datetime_from_millis(*(long long*)(buffer + *position));
             *position += 8;
-            if (!tz_aware) { /* In the naive case, we're done here. */
+
+            PyObject* bson_tzinfo = PyObject_GetAttrString(Bson, "tzinfo");
+            if (!bson_tzinfo) {
+                return NULL;
+            }
+            Py_DECREF(bson_tzinfo);
+            if (!tz_aware && bson_tzinfo == Py_None) {
                 value = naive;
                 break;
             }
-
             if (!naive) {
                 return NULL;
             }
+
             replace = PyObject_GetAttrString(naive, "replace");
             Py_DECREF(naive);
             if (!replace) {
@@ -1055,6 +1116,41 @@ static PyObject* get_value(const char* buffer, int* position, int type,
             Py_DECREF(replace);
             Py_DECREF(args);
             Py_DECREF(kwargs);
+            if (bson_tzinfo == Py_None) {
+                break;
+            }
+
+            /*
+            value = value.astimezone(bson.tzinfo)
+            */
+            PyObject* astimezone = PyObject_GetAttrString(value, "astimezone");
+            Py_DECREF(value);
+            if (!astimezone) {
+                return NULL;
+            }
+            args = PyTuple_New(1);
+            if (!args) {
+                Py_DECREF(astimezone);
+                return NULL;
+            }
+            bson_tzinfo = PyObject_GetAttrString(Bson, "tzinfo");
+            if (!bson_tzinfo) {
+                Py_DECREF(astimezone);
+                Py_DECREF(args);
+                return NULL;
+            }
+            if (PyTuple_SetItem(args, 0, bson_tzinfo)) {
+                Py_DECREF(astimezone);
+                Py_DECREF(args);
+                Py_DECREF(bson_tzinfo);
+                return NULL;
+            }
+            value = PyObject_Call(astimezone, args, NULL);
+            Py_DECREF(astimezone);
+            Py_DECREF(args);
+            if (!value) {
+                return NULL;
+            }
             break;
         }
     case 11:
