I know I can do:
import datetime
def default(o):
    if type(o) is datetime.datetime:
        return o.isoformat()
data = {'a': datetime.datetime.today()}
json.dumps(data, default=default)
# '{"a": "2015-01-22T01:04:23.121392"}'
That works perfect. Now what if I have datetimes as my keys:
data = {datetime.datetime.today(): 'a'}
If I try the same it fails with a:
TypeError: keys must be a string
Is there any way I can do something similar, i.e. a custom converter but for keys?
Note: This is just a simple example. I have a deep nested dict structure where some keys are not strings.
EDIT: A nested example, but note that I don't have control over the data structure, it comes from an external function:
data = {'a': {datetime.datetime.today(): '1'}}
                You could do this:
class DatesToStrings(json.JSONEncoder):
    def _encode(self, obj):
        if isinstance(obj, dict):
            def transform_date(o):
                return self._encode(o.isoformat() if isinstance(o, datetime) else o)
            return {transform_date(k): transform_date(v) for k, v in obj.items()}
        else:
            return obj
    def encode(self, obj):
        return super(DatesToStrings, self).encode(self._encode(obj))
>>> json.dumps({"a": {datetime.now(): 3}}, cls=DatesToStrings)
'{"a": {"2015-01-22T11:49:25.910261": 3}}'
                        Upon Andrew Magee's and add nested list/set support:
import json
from datetime import datetime
class DatesToStrings(json.JSONEncoder):
    def _encode(self, obj):
        def transform_date(o):
            return self._encode(o.isoformat() if isinstance(o, datetime) else o)
        if isinstance(obj, dict):
            return {transform_date(k): transform_date(v) for k, v in obj.items()}
        elif isinstance(obj, list) or isinstance(obj, set):
            return [transform_date(l) for l in obj]
        else:
            return obj
    def encode(self, obj):
        return super(DatesToStrings, self).encode(self._encode(obj))
print(json.dumps({"a": datetime.now()}, cls=DatesToStrings))
print(json.dumps({datetime.now(): 1}, cls=DatesToStrings))
print(json.dumps({"a": {datetime.now(): 3}}, cls=DatesToStrings))
print(json.dumps({"a": [datetime.now()]}, cls=DatesToStrings))
print(json.dumps({"a": {1: [datetime.now()]}}, cls=DatesToStrings))
print(json.dumps({"a": [{1: [datetime.now()]}]}, cls=DatesToStrings))
print(json.dumps({"a": {datetime.now()}}, cls=DatesToStrings))
                        Here is the recursive version - note that I won't guarantee it will be any faster than the pickled version:
def dictRecursiveFormat(d): 
        for key, val in list(d.items()):
            if isinstance(key, datetime.datetime): 
                val = d.pop(key)
                d[str(key)] = val 
            if isinstance(val, datetime.datetime) and isinstance(key, datetime.datetime): 
                d[str(key)] = str(val)
            elif isinstance(val, datetime.datetime):
                d[key] = str(val)
            if type(val) is dict: 
                dictRecursiveFormat(val)
example:
In [52]: d= {'a': datetime.datetime.now(), 'b': {datetime.datetime.now(): datetime.datetime.now()}}
In [53]: dictRecursiveFormat(d)
In [54]: d
Out[54]: 
{'a': '2015-01-21 19:33:52.293182',
 'b': {'2015-01-21 19:33:52.293240': '2015-01-21 19:33:52.293229'}}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With