1087

次のような基本的な辞書があります。

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ます。

4

31 に答える 31

1162

日付とすべてを食べる私のクイック&ダーティJSONダンプ:

json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)

defaultシリアライズできないオブジェクトに適用される関数です。
この場合は でstrあるため、知らないことはすべて文字列に変換するだけです。これはシリアライゼーションには優れていますが、デシリアライズ時にはそれほど優れていません(したがって、「クイック&ダーティ」)。関数やnumpy配列など、警告なしに何かが文字列化されている可能性があります。

于 2016-03-21T22:29:26.813 に答える
521

datetime.datetime他の回答に基づいて構築された、文字列に変換してdatetime.dateオブジェクトを変換する特定のシリアライザーに基づく単純なソリューション。

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))

datetime.datetimeご覧のように、コードは object がまたはのクラスであるかどうかを確認しdatetime.date、 を使用.isoformat()して、ISO 8601 形式の YYYY-MM-DDTHH:MM:SS (JavaScript で簡単にデコードできます) に従って、オブジェクトのシリアル化されたバージョンを生成します。 )。より複雑なシリアル化された表現が必要な場合は、 str() の代わりに他のコードを使用できます (例については、この質問に対する他の回答を参照してください)。コードは、シリアル化できない型で呼び出された場合に対処するために、例外を発生させて終了します。

この json_serial 関数は次のように使用できます。

from datetime import datetime
from json import dumps

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

json.dumps のデフォルト パラメータがどのように機能するかについての詳細は、json モジュール ドキュメントのセクション 基本的な使用法 にあります

于 2014-03-06T23:46:17.797 に答える
496

2018年更新

元の回答は、MongoDB の「日付」フィールドが次のように表される方法に対応していました。

{"$date": 1506816000000}

json にシリアル化するための一般的な Python ソリューションが必要な場合は、 @jjmontes の回答datetimeをチェックして、依存関係を必要としない簡単なソリューションを確認してください。


(コメントごとに)mongoengineを使用しており、pymongoは依存関係であるため、pymongoにはjsonのシリアル化を支援する組み込みユーティリティがあります:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html

使用例(連載):

from bson import json_util
import json

json.dumps(anObject, default=json_util.default)

使用例 (デシリアライゼーション):

json.loads(aJsonString, object_hook=json_util.object_hook)

ジャンゴ

Django は、DjangoJSONEncoderこの種のものを適切に処理するネイティブ シリアライザーを提供します。

https://docs.djangoproject.com/en/dev/topics/serialization/#djangojsonencoderを参照してください

from django.core.serializers.json import DjangoJSONEncoder

return json.dumps(
  item,
  sort_keys=True,
  indent=1,
  cls=DjangoJSONEncoder
)

私が気付いた 1 つの違いと、次のようなDjangoJSONEncoderカスタムの使用default:

import datetime
import json

def default(o):
    if isinstance(o, (datetime.date, datetime.datetime)):
        return o.isoformat()

return json.dumps(
  item,
  sort_keys=True,
  indent=1,
  default=default
)

Django はデータを少し削除します:

 "last_login": "2018-08-03T10:51:42.990", # DjangoJSONEncoder 
 "last_login": "2018-08-03T10:51:42.990239", # default

そのため、場合によってはその点に注意する必要があります。

于 2012-08-09T02:07:57.893 に答える
252

私はこの問題に遭遇したばかりで、私の解決策はサブクラス化することjson.JSONEncoderです:

from datetime import datetime
import json

class DateTimeEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime):
            return o.isoformat()

        return json.JSONEncoder.default(self, o)

あなたの電話では、次のようなことをしてください:json.dumps(yourobj, cls=DateTimeEncoder)上記.isoformat()の回答の1つから得たもの。

于 2014-11-21T09:52:44.897 に答える
140

日付を文字列に変換する

sample['somedate'] = str( datetime.utcnow() )
于 2012-08-09T02:10:55.093 に答える
83

これにpymongoライブラリを必要としない、または使用したくない他の人のために..次の小さなスニペットを使用して、datetime JSON変換を簡単に実現できます。

def default(obj):
    """Default JSON serializer."""
    import calendar, datetime

    if isinstance(obj, datetime.datetime):
        if obj.utcoffset() is not None:
            obj = obj - obj.utcoffset()
        millis = int(
            calendar.timegm(obj.timetuple()) * 1000 +
            obj.microsecond / 1000
        )
        return millis
    raise TypeError('Not sure how to serialize %s' % (obj,))

次に、次のように使用します。

import datetime, json
print json.dumps(datetime.datetime.now(), default=default)

出力: 

'1365091796124'
于 2013-04-04T23:15:58.543 に答える
64

これが私の解決策です:

import json


class DatetimeEncoder(json.JSONEncoder):
    def default(self, obj):
        try:
            return super().default(obj)
        except TypeError:
            return str(obj)

次に、次のように使用できます。

json.dumps(dictionnary, cls=DatetimeEncoder)
于 2013-05-03T06:38:32.587 に答える
21

同様の問題を持つアプリケーションがあります。私のアプローチは、datetime 値を 6 項目のリスト (年、月、日、時、分、秒) として JSONize することでした。7 項目のリストとしてマイクロ秒に移動することもできますが、次のことを行う必要はありませんでした。

class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            encoded_object = list(obj.timetuple())[0:6]
        else:
            encoded_object =json.JSONEncoder.default(self, obj)
        return encoded_object

sample = {}
sample['title'] = "String"
sample['somedate'] = datetime.datetime.now()

print sample
print json.dumps(sample, cls=DateTimeEncoder)

生成:

{'somedate': datetime.datetime(2013, 8, 1, 16, 22, 45, 890000), 'title': 'String'}
{"somedate": [2013, 8, 1, 16, 22, 45], "title": "String"}
于 2013-08-01T23:27:38.493 に答える
19

.strftime()メソッドにメソッドを適用.datetime.now()して、シリアライズ可能なメソッドにする必要があります。

次に例を示します。

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'}
于 2017-10-31T11:48:43.073 に答える
11

clsパラメータが。のカスタムエンコーダクラスを指定する必要がありますjson.dumpsドキュメントから引用するには:

>>> import json
>>> class ComplexEncoder(json.JSONEncoder):
...     def default(self, obj):
...         if isinstance(obj, complex):
...             return [obj.real, obj.imag]
...         return json.JSONEncoder.default(self, obj)
...
>>> dumps(2 + 1j, cls=ComplexEncoder)
'[2.0, 1.0]'
>>> ComplexEncoder().encode(2 + 1j)
'[2.0, 1.0]'
>>> list(ComplexEncoder().iterencode(2 + 1j))
['[', '2.0', ', ', '1.0', ']']

これは例として複素数を使用しますが、日付をエンコードするクラスを同じように簡単に作成できます(ただし、JSONは日付について少しあいまいだと思います)

于 2012-08-09T03:08:10.347 に答える
2

私の解決策...

from datetime import datetime
import json

from pytz import timezone
import pytz


def json_dt_serializer(obj):
    """JSON serializer, by macm.
    """
    rsp = dict()
    if isinstance(obj, datetime):
        rsp['day'] = obj.day
        rsp['hour'] = obj.hour
        rsp['microsecond'] = obj.microsecond
        rsp['minute'] = obj.minute
        rsp['month'] = obj.month
        rsp['second'] = obj.second
        rsp['year'] = obj.year
        rsp['tzinfo'] = str(obj.tzinfo)
        return rsp
    raise TypeError("Type not serializable")


def json_dt_deserialize(obj):
    """JSON deserialize from json_dt_serializer, by macm.
    """
    if isinstance(obj, str):
        obj = json.loads(obj)
    tzone = timezone(obj['tzinfo'])
    tmp_dt = datetime(obj['year'],
                      obj['month'],
                      obj['day'],
                      hour=obj['hour'],
                      minute=obj['minute'],
                      second=obj['second'],
                      microsecond=obj['microsecond'])
    loc_dt = tzone.localize(tmp_dt)
    deserialize = loc_dt.astimezone(tzone)
    return deserialize    

さて、いくつかのテストです。

# Tests
now = datetime.now(pytz.utc)

# Using this solution
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)
assert tmp == now
assert isinstance(tmp, datetime) == True
assert isinstance(now, datetime) == True

# using default from json.dumps
tmp = json.dumps(datetime.now(pytz.utc), default=json_dt_serializer)
rsp = json_dt_deserialize(tmp)
assert isinstance(rsp, datetime) == True

# Lets try another timezone
eastern = timezone('US/Eastern')
now = datetime.now(eastern)
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)

print(tmp)
# 2015-10-22 09:18:33.169302-04:00

print(now)
# 2015-10-22 09:18:33.169302-04:00

# Wow, Works!
assert tmp == now
于 2015-10-22T13:29:54.227 に答える
2

これは、日時をJSONに変換して戻すための私の完全なソリューションです..

import calendar, datetime, json

def outputJSON(obj):
    """Default JSON serializer."""

    if isinstance(obj, datetime.datetime):
        if obj.utcoffset() is not None:
            obj = obj - obj.utcoffset()

        return obj.strftime('%Y-%m-%d %H:%M:%S.%f')
    return str(obj)

def inputJSON(obj):
    newDic = {}

    for key in obj:
        try:
            if float(key) == int(float(key)):
                newKey = int(key)
            else:
                newKey = float(key)

            newDic[newKey] = obj[key]
            continue
        except ValueError:
            pass

        try:
            newDic[str(key)] = datetime.datetime.strptime(obj[key], '%Y-%m-%d %H:%M:%S.%f')
            continue
        except TypeError:
            pass

        newDic[str(key)] = obj[key]

    return newDic

x = {'Date': datetime.datetime.utcnow(), 34: 89.9, 12.3: 90, 45: 67, 'Extra': 6}

print x

with open('my_dict.json', 'w') as fp:
    json.dump(x, fp, default=outputJSON)

with open('my_dict.json') as f:
    my_dict = json.load(f, object_hook=inputJSON)

print my_dict

出力

{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}
{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}

JSON ファイル

{"Date": "2013-11-08 02:30:56.479727", "34": 89.9, "45": 67, "12.3": 90, "Extra": 6}

これにより、文字列、int、float、datetime オブジェクトのインポートとエクスポートが可能になりました。他のタイプに拡張するのは難しくありません。

于 2013-11-08T02:36:09.497 に答える
2

一般に、日時をシリアル化するには、次のようないくつかの方法があります。

  1. ISO 文字列、短く、タイムゾーン情報を含めることができます。例: @jgbarah の回答
  2. タイムスタンプ (タイムゾーン データが失われます)、例 @JayTaylor の回答
  3. プロパティのディクショナリ (タイムゾーンを含む)。

最後の方法でよろしければ、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 に遭遇した場合、それが日時かどうかを知るために、データについて何かを知る必要があります。dict として、メタデータを保存して、自動的にデコードできるようにすることができjson_tricksます。また、人間が簡単に編集できます。

免責事項:それは私によって作られています。私は同じ問題を抱えていたからです。

于 2016-10-19T21:12:33.893 に答える
2

ビューで結果を使用している場合は、必ず適切な応答を返すようにしてください。API によると、jsonify は次のことを行います。

application/json mimetype を使用して、指定された引数の JSON 表現で Response を作成します。

json.dumps でこの動作を模倣するには、数行のコードを追加する必要があります。

response = make_response(dumps(sample, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response

また、jsonify の応答を完全に複製するには、dict を返す必要があります。したがって、ファイル全体は次のようになります

from flask import make_response
from json import JSONEncoder, dumps


class CustomEncoder(JSONEncoder):
    def default(self, obj):
        if set(['quantize', 'year']).intersection(dir(obj)):
            return str(obj)
        elif hasattr(obj, 'next'):
            return list(obj)
        return JSONEncoder.default(self, obj)

@app.route('/get_reps/', methods=['GET'])
def get_reps():
    sample = ['some text', <datetime object>, 123]
    response = make_response(dumps({'result': sample}, cls=CustomEncoder))
    response.headers['Content-Type'] = 'application/json'
    response.headers['mimetype'] = 'application/json'
    return response
于 2013-05-03T22:21:22.520 に答える
1

sqlalchemy を使用してクラス内にシリアライズ デコレータを記述しているときに、同じエラー メッセージが表示されました。代わりに:

Class Puppy(Base):
    ...
    @property
    def serialize(self):
        return { 'id':self.id,
                 'date_birth':self.date_birth,
                  ...
                }

isoformat() を使用するという jgbarah のアイデアを借りて、元の値に isoformat() を追加しただけなので、次のようになります。

                  ...
                 'date_birth':self.date_birth.isoformat(),
                  ...
于 2015-12-02T22:13:38.660 に答える
1

通信の両側にいる場合は、json と共にrepr()およびeval()関数を使用できます。

import datetime, json

dt = datetime.datetime.now()
print("This is now: {}".format(dt))

dt1 = json.dumps(repr(dt))
print("This is serialised: {}".format(dt1))

dt2 = json.loads(dt1)
print("This is loaded back from json: {}".format(dt2))

dt3 = eval(dt2)
print("This is the same object as we started: {}".format(dt3))

print("Check if they are equal: {}".format(dt == dt3))

日時を次のようにインポートしないでください

from datetime import datetime

eval が文句を言うからです。または、datetime をパラメーターとして eval に渡すこともできます。いずれにせよ、これはうまくいくはずです。

于 2018-08-08T12:48:23.400 に答える
1

独自のフォーマットが必要な場合の簡単な修正

for key,val in sample.items():
    if isinstance(val, datetime):
        sample[key] = '{:%Y-%m-%d %H:%M:%S}'.format(val) #you can add different formating here
json.dumps(sample)
于 2016-04-09T00:17:15.810 に答える
0

今日、この問題に直面しましたpickle。これは、python オブジェクトをシリアライズし、pickle ファイルからロードするための組み込みライブラリです。

pickle私が見つけたとjsonisファイルの唯一の違いpickleはバイナリ ファイルで、asjsonは通常のテキスト ファイルです。

また、日時オブジェクトに問題はありません。

于 2020-08-22T13:48:08.877 に答える
-2

私は100%正しいとは限りませんが、これはシリアル化を行う簡単な方法です

#!/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'> 
于 2017-04-15T08:27:51.210 に答える