我有一个基本的字典如下:

sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere

当我尝试做jsonify(sample)时,我得到:

TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable

我该怎么做才能使我的字典样本克服上面的错误呢?

注意:虽然它可能不相关,字典是从mongodb的记录检索中生成的,当我打印出str(sample['somedate'])时,输出是2012-08-08 21:46:24.862000。


当前回答

您应该在.datetime.now()方法上应用.strftime()方法,使其成为一个可序列化的方法。

这里有一个例子:

from datetime import datetime

time_dict = {'time': datetime.now().strftime('%Y-%m-%dT%H:%M:%S')}
sample_dict = {'a': 1, 'b': 2}
sample_dict.update(time_dict)
sample_dict

输出:

Out[0]: {'a': 1, 'b': 2, 'time': '2017-10-31T15:16:30'}

(更新):

在Python3.7及以后版本中,你可以简单地使用.isoformat()方法:

from datetime import datetime

datetime.now().isoformat()

其他回答

通常有几种方法来序列化日期时间,比如:

ISO字符串,短,可以包含时区信息,例如@jgbarah的答案 时间戳(时区数据丢失),例如@JayTaylor的答案 属性字典(包括时区)。

如果您同意最后一种方法,json_tricks包将处理日期、时间和日期时间(包括时区)。

from datetime import datetime
from json_tricks import dumps
foo = {'title': 'String', 'datetime': datetime(2012, 8, 8, 21, 46, 24, 862000)}
dumps(foo)

这使:

{"title": "String", "datetime": {"__datetime__": null, "year": 2012, "month": 8, "day": 8, "hour": 21, "minute": 46, "second": 24, "microsecond": 862000}}

所以你要做的就是

`pip install json_tricks`

然后导入从json_tricks而不是json。

不将其存储为单个字符串、int型或float型的优势体现在解码时:如果你遇到的只是字符串,特别是int型或float型,你需要了解一些关于数据的信息,以知道它是否是一个datetime。作为dict,您可以存储元数据,以便自动解码,这就是json_tricks为您做的。它也很容易为人类编辑。

免责声明:这是我做的。因为我也有同样的问题。

我今天遇到了这个问题,我发现了一种叫做泡菜的东西。它是一个用于序列化python对象的内置库,也可以从pickle文件加载它。

我发现pickle和json之间唯一的区别是pickle文件是二进制文件,而json是通常的文本文件。

它不会对datetime对象造成任何问题。

我可能不是百分百正确, 这是实现序列化的简单方法

#!/usr/bin/python
import datetime,json

sampledict = {}
sampledict['a'] = "some string"
sampledict['b'] = datetime.datetime.now()

print sampledict   # output : {'a': 'some string', 'b': datetime.datetime(2017, 4, 15, 5, 15, 34, 652996)}

#print json.dumps(sampledict)

'''
output : 

Traceback (most recent call last):
  File "./jsonencodedecode.py", line 10, in <module>
    print json.dumps(sampledict)
  File "/usr/lib/python2.7/json/__init__.py", line 244, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python2.7/json/encoder.py", line 184, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: datetime.datetime(2017, 4, 15, 5, 16, 17, 435706) is not JSON serializable


'''

sampledict['b'] = datetime.datetime.now().strftime("%B %d, %Y %H:%M %p")

afterdump = json.dumps(sampledict)

print afterdump  #output : {"a": "some string", "b": "April 15, 2017 05:18 AM"}

print type(afterdump) #<type 'str'>


afterloads = json.loads(afterdump) 

print afterloads # output : {u'a': u'some string', u'b': u'April 15, 2017 05:18 AM'}


print type(afterloads) # output :<type 'dict'> 

在其他答案的基础上,一个简单的解决方案基于只转换datetime的特定序列化器。Datetime和Datetime。将对象日期指定为字符串。

from datetime import date, datetime

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError ("Type %s not serializable" % type(obj))

As seen, the code just checks to find out if object is of class datetime.datetime or datetime.date, and then uses .isoformat() to produce a serialized version of it, according to ISO 8601 format, YYYY-MM-DDTHH:MM:SS (which is easily decoded by JavaScript). If more complex serialized representations are sought, other code could be used instead of str() (see other answers to this question for examples). The code ends by raising an exception, to deal with the case it is called with a non-serializable type.

这个json_serial函数可以这样使用:

from datetime import datetime
from json import dumps

print dumps(datetime.now(), default=json_serial)

详细说明如何将默认参数设置为json。可以在json模块文档的基本用法章节中找到dump作品。

Another approach is to adopt a concept from FEEL (the Friendly Enough Expression Language) defined in DMN (Decision Model Notation) - namely @strings. Any string starting with @" and ending with " is decoded separately with FEEL decoding. Of course the sender and the receiver have to agree to this convention, but ... the code below lets you encode lots of other things as well as dates, times, date/times, timedeltas. You can encode year/month durations and ranges (so long as you except a 4 element tuple of chr, expr, expr, chr as being a good representation of a range - where the two chrs are open/close brackets). So, @"P4Y2M" is a duration of 4 years and 2 months. @"P2DT5H" is a timedelta of 2 days and 4 hours, @"(2021-01-02 .. 2021-12-31)" is a year range.

下面的代码可用于序列化和反序列化@strings。

import datetime
import pySFeel

parser = pySFeel.SFeelParser()


def convertAtString(thisString):
    # Convert an @string
    (status, newValue) = parser.sFeelParse(thisString[2:-1])
    if 'errors' in status:
        return thisString
    else:
        return newValue


def convertIn(newValue):
    if isinstance(newValue, dict):
        for key in newValue:
            if isinstance(newValue[key], int):
                newValue[key] = float(newValue[key])
            elif isinstance(newValue[key], str) and (newValue[key][0:2] == '@"') and (newValue[key][-1] == '"'):
                newValue[key] = convertAtString(newValue[key])
            elif isinstance(newValue[key], dict) or isinstance(newValue[key], list):
                newValue[key] = convertIn(newValue[key])
    elif isinstance(newValue, list):
        for i in range(len(newValue)):
            if isinstance(newValue[i], int):
                newValue[i] = float(newValue[i])
            elif isinstance(newValue[i], str) and (newValue[i][0:2] == '@"') and (newValue[i][-1] == '"'):
                newValue[i] = convertAtString(newValue[i])
            elif isinstance(newValue[i], dict) or isinstance(newValue[i], list):
                newValue[i] = convertIn(newValue[i])
    elif isinstance(newValue, str) and (newValue[0:2] == '@"') and (newValue[-1] == '"'):
        newValue = convertAtString(newValue)
    return newValue


  def convertOut(thisValue):
      if isinstance(thisValue, datetime.date):
          return '@"' + thisValue.isoformat() + '"'
      elif isinstance(thisValue, datetime.datetime):
          return '@"' + thisValue.isoformat(sep='T') + '"'
      elif isinstance(thisValue, datetime.time):
          return '@"' + thisValue.isoformat() + '"'
      elif isinstance(thisValue, datetime.timedelta):
          sign = ''
          duration = thisValue.total_seconds()
          if duration < 0:
              duration = -duration
              sign = '-'
          secs = duration % 60
          duration = int(duration / 60)
          mins = duration % 60
          duration = int(duration / 60)
          hours = duration % 24
          days = int(duration / 24)
          return '@"%sP%dDT%dH%dM%fS"' % (sign, days, hours, mins, secs)
      elif isinstance(thisValue, bool):
          return thisValue:
      elif thisValue is None:
          return thisValue:
      elif isinstance(thisValue, int):
          sign = ''
          if thisValue < 0:
              thisValue = -thisValue
              sign = '-'
          years = int(thisValue / 12)
          months = (thisValue % 12)
          return '@"%sP%dY%dM"' % (sign, years, months)
      elif isinstance(thisValue, tuple) and (len(thisValue) == 4):
          (lowEnd, lowVal, highVal, highEnd) = thisValue
          return '@"' + lowEnd + str(lowVal) + ' .. ' + str(highVal) + highEnd
      elif thisValue is None:
          return 'null'
      elif isinstance(thisValue, dict):
          for item in thisValue:
              thisValue[item] = convertOut(thisValue[item])
          return thisValue
      elif isinstance(thisValue, list):
          for i in range(len(thisValue)):
              thisValue[i] = convertOut(thisValue[i])
          return thisValue
      else:
          return thisValue