import datetime
import json

import dateutil.parser
import pytz


class DateAwareJSONEncoder(json.JSONEncoder):

    def default(self, value):
        if isinstance(value, datetime.datetime):
            return "@T-" + value.isoformat()
        elif isinstance(value, datetime.timedelta):
            return "@I-" + str(value.total_seconds())

        return super(DateAwareJSONEncoder, self).default(value)


class DateAwareJSONDecoder(json.JSONDecoder):

    def decode(self, value):
        return self.convert(json.loads(value))

    def convert(self, value):
        if isinstance(value, basestring) and value.startswith("@T-"):
            return dateutil.parser.parse(value[3:], tzinfos={"UTC": pytz.utc})
        elif isinstance(value, basestring) and value.startswith("@I-"):
            return datetime.timedelta(seconds=float(value[3:]))
        elif isinstance(value, dict):
            for key, val in value.iteritems():
                converted = self.convert(val)
                if converted != val:
                    value[key] = converted
        elif isinstance(value, list):
            for index, val in enumerate(value):
                converted = self.convert(val)
                if converted != val:
                    value[index] = converted

        return value

@@ -59,16 +59,67 @@
  pytz%0A%0A%0A
+TIMESTAMP_PREFIX = %22@T-%22%0AINTERVAL_PREFIX = %22@I-%22%0A%0A%0A
 class Da
@@ -255,21 +255,32 @@
  return 
-%22@T-%22
+TIMESTAMP_PREFIX
  + value
@@ -363,21 +363,31 @@
  return 
-%22@I-%22
+INTERVAL_PREFIX
  + str(v
@@ -616,34 +616,32 @@
 onvert(self, val
-ue
 ):%0A        if is
@@ -644,34 +644,32 @@
 f isinstance(val
-ue
 , basestring) an
@@ -665,34 +665,32 @@
 estring) and val
-ue
 .startswith(%22@T-
@@ -685,21 +685,32 @@
 rtswith(
-%22@T-%22
+TIMESTAMP_PREFIX
 ):%0A     
@@ -745,23 +745,58 @@
 r.parse(
-value%5B3
+%0A                val%5Blen(TIMESTAMP_PREFIX)
 :%5D, tzin
@@ -816,16 +816,29 @@
 ytz.utc%7D
+%0A            
 )%0A      
@@ -858,18 +858,16 @@
 ance(val
-ue
 , basest
@@ -879,18 +879,16 @@
  and val
-ue
 .startsw
@@ -891,21 +891,31 @@
 rtswith(
-%22@I-%22
+INTERVAL_PREFIX
 ):%0A     
@@ -951,32 +951,79 @@
 lta(
-seconds=float(value%5B3:%5D)
+%0A                seconds=float(val%5Blen(INTERVAL_PREFIX):%5D)%0A            
 )%0A  
@@ -1047,18 +1047,16 @@
 ance(val
-ue
 , dict):
@@ -1072,42 +1072,15 @@
     
-for key, val in value.iteritems():
+val = %7B
 %0A   
@@ -1088,35 +1088,28 @@
             
-converted =
+key:
  self.conver
@@ -1105,32 +1105,34 @@
 self.convert(val
+ue
 )%0A              
@@ -1137,71 +1137,55 @@
     
-if converted != val:%0A                    value%5Bkey%5D = converted
+for key, value in val.iteritems()%0A            %7D
 %0A   
@@ -1208,18 +1208,16 @@
 ance(val
-ue
 , list):
@@ -1233,72 +1233,18 @@
     
-for index, val in enumerate(value):%0A                converted = 
+val = map(
 self
@@ -1255,95 +1255,14 @@
 vert
-(
+, 
 val)
-%0A                if converted != val:%0A                    value%5Bindex%5D = converted
 %0A%0A  
@@ -1277,11 +1277,9 @@
 turn val
-ue
 %0A

Simplify the serialization code a bit.