「datetime.datetimeはJSONシリアライズ可能ではない」を克服する方法?


742

私は次のような基本的な口述を持っています:

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


1
これは具体的にはpython全般ですか、それともdjangoですか?
jdi 2012

1
厳密にはpythonです。私はdjangoを使用していませんが、mongodbからレコードを取得しています。
Rolando 2012


私はmongoengineを使用していますが、pymongoがこれを回避または克服するより良い方法を持っている場合は、教えてください。
Rolando 2012

3
リンクされた質問は基本的に、datetimeオブジェクトをシリアル化しようとするのではなく、シリアル化する前に一般的なISO形式の文字列に変換するように指示しています。
トーマスケリー

回答:


377

2018年に更新

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

{"$date": 1506816000000}

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


(コメントごとに)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
)

このようなDjangoJSONEncoderカスタムを使用することと私が気付いた1つの違い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

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


3
複数のライブラリを混合することは良い/悪い習慣ですか?つまり、ドキュメントを挿入するためのmongoengineとクエリ/検索のためのpymongoを持つことですか?
Rolando 2012

これは悪い習慣ではなく、メインライブラリが使用するライブラリへの依存関係を暗示しているだけです。mongoengineから必要なことを達成できない場合は、pymongoにドロップダウンします。それと同じDjango MongoDBです。後者では、バックエンドにとらわれない状態を維持するために、django ORM内に留まるようにします。しかし、抽象化で必要なことができない場合があるため、レイヤーをドロップダウンします。この場合、JSON形式に付随するユーティリティメソッドを使用しているだけなので、問題とはまったく関係ありません。
jdi 2012

私はこれをFlaskで試してみましたが、json.dumpを使用すると、jsonify()ラッパーをその周りに配置して、application / jsonで返すことができないようです。jsonify(json.dumps(sample、default = json_util.default))を返そうとする
Rolando

2
@amit構文を覚えるのはそれほど重要ではありません。ドキュメントをよく読み、どこに、いつ再取得する必要があるかを認識するのに十分な情報を頭の中に保管することです。この場合、「Oh a custom object with json」と言って、その使用法をすぐに更新します
jdi

2
@guyskk 5年前にこれを書いてから、bjsonまたはmongoの変更を追跡していません。しかし、datetimeのシリアル化を制御したい場合は、jgbarahによる回答に示されているように、独自のデフォルトハンドラー関数を作成する必要があります
jdi

619

日付とすべてを食べる私の汚れたJSONダンプ:

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

14
これは素晴らしいですが、残念ながら何が起こったのか理解できませんでしたか?誰かがこの答えを説明できますか?
Kishor Pawar

63
@KishorPawar:defaultシリアル化できないオブジェクトに適用される関数です。この場合strはなので、わからないものはすべて文字列に変換します。これは、シリアル化には最適ですが、関数やnumpy配列など、何も警告なしに文字列化されている可能性があるため、逆シリアル化(したがって「クイック&ダーティ」)の場合はそれほど優れていません。
マーク

1
@素晴らしいマーク。ありがとう。日付など、シリアル化できない値のタイプがわかっている場合に役立ちます。
キショールパワール2016年

2
なぜ私はこれを知らずに私の人生のすべてを行きましたか。:)
AREL

1
@jjmontesはすべてに対して機能しません(例:json.dumps({():1,type(None):2},default=str)raises)TypeError、型またはタプルを持つことはできません。
alancalvitti

443

特定のシリアライザに基づいて他の回答を踏まえ、シンプルなソリューションことだけで変換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またはdatetime.dateであるかどうかを確認し、次にそれを使用.isoformat()して、オブジェクトのシリアル化されたバージョンを生成します。 )。より複雑なシリアル化された表現が求められる場合は、str()の代わりに他のコードを使用できます(例については、この質問に対する他の回答を参照してください)。コードは、シリアル化不可能な型で呼び出された場合に対処するために、例外を発生させることで終了します。

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

from datetime import datetime
from json import dumps

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

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


5
正解、よりきれいな輸入日時とでisinstance(OBJ、datetime.datetimeの)場合は日時インポート日時から使用されていないので、私はとにかく感謝、多くの時間を失っええ
セルジオ

12
しかし、これは正しいタイプでそれを逆シリアル化する方法を説明していませんか?
BlueTrin 2015年

2
いいえ、@ BlueTrin、それについては何も言われていません。私の場合、私はJavaScriptで逆シリアル化しています。これはそのまま使用できます。
jgbarah

1
これにより、jsonモジュールが更新され、datetimeオブジェクトのシリアル化が含まれる場合、予期しない動作が発生します。
ジャスティン

1
@sergしかし、時間に応じてUTCに変換する01:00:00+01:00と統一さ02:00:00+00:00れ、コンテキストによっては同じになるとは限りません。もちろん、それらは同じ時点を指しますが、オフセットは値の関連する側面である可能性があります。
Alfe、

211

私はこの問題に遭遇したばかりであり、私の解決策はサブクラス化すること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)

:お電話でのような何かを、私は上記の答えの1からもらったの。json.dumps(yourobj, cls=DateTimeEncoder).isoformat()


22
カスタムJSONEncoderを実装するのが適切な方法であるべきであるために更新されました
3k-

25
これがトップアンサーであるだけでなく、通常のjsonエンコーダーの一部である必要があります。デコードのみが曖昧でなくなった場合..
Joost

4
Djangoを使用している場合は、を参照してくださいDjangoJSONEncoderdocs.djangoproject.com/en/dev/topics/serialization/...
S.カービー

4
超役立つ。最終行はreturn super(DateTimeEncoder, self).default(o)
ボブスタイン

16
Pythonの3では、最後の行は、さらに簡単です:return super().default(o)
ariddell

124

日付を文字列に変換します

sample['somedate'] = str( datetime.utcnow() )

10
そして、どうすればPythonでデシリアライズできますか?
wobmene 14年

62
問題は、多くの日時オブジェクトがデータ構造に深く埋め込まれているか、ランダムであるかです。これは信頼できる方法ではありません。
2014年

3
逆シリアル化しますoDate = datetime.datetime.strptime(sDate, '%Y-%m-%d %H:%M:%S.%f')。取得した形式: docs.python.org/2/library/datetime.html
ローマン

13
タイムゾーン情報を無視するため、反対票が投じられました。は.now()これを示さずに現地時間を使用することに注意してください。少なくとも.utcnow()使用する必要があります(次に+0000またはZを追加します)
Daniel F

1
@DanielF At least .utcnow() should be used正確でdatetime.now(timezone.utc)はありませんが、推奨されます。docs.python.org / 3.8 / library / …の警告を参照してください。
Toreno96

79

これにpymongoライブラリを必要としない、または使用したい他の人にとっては、この小さなスニペットで簡単に日時の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'

1
millis=ifステートメント内でインデントする必要はありませんか?私がより一般的だと思うISO形式を取得するには、str(obj)を使用する方がおそらく良いでしょう。
2014年

なぜ字下げしたいのですか?このスニペットは機能し、結果の出力はJavaScriptから簡単にデシリアライズ/解析できます。
ジェイテイラー

5
objが[time、date、datetime]オブジェクトではない可能性があるため
Rebs

2
ローカルタイムゾーンのUTCオフセットがゼロ以外の場合(そのほとんど)、例は正しくありません。datetime.now()現地時間を(単純なdatetimeオブジェクトとして)返しますが、objタイムゾーンに対応していない場合、コードはそれがUTCであると想定します。datetime.utcnow()代わりに使用してください。
jfs 2014年

1
docs.python.org/2/library/json.html#basic-usageにあるPythonのドキュメントの推奨に従って、objが認識されない場合にタイプエラーを発生させるように調整しました
Jay Taylor

40

これが私の解決策です:

# -*- coding: utf-8 -*-
import json


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

それからあなたはそれをそのように使うことができます:

json.dumps(dictionnary, cls=DatetimeEncoder)

同意する。少なくともmongodbのコンテキストでは、はるかに優れています。isinstance(obj, datetime.datetime)TypeError内で実行し、処理するタイプを追加して、str(obj)またはで終了できrepr(obj)ます。そして、すべてのダンプは、この特殊なクラスを指すことができます。
JL Peyret 2017

@Natimこのソリューションは最高です。+1
Souvik Ray

20

同様の問題のあるアプリケーションがあります。私のアプローチは、日時の値を6項目のリスト(年、月、日、時、分、秒)としてJSON化することでした。あなたは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"}

datetime.utcnow()を実行して時間を節約した場合、動作しません
saurshaz

1
datetime.utcnow()でどのエラーが発生していますか?それは私にとっては大丈夫です。
codeatty 2013

17

私の解決策(冗長性が低いと思います):

def default(o):
    if type(o) is datetime.date or type(o) is datetime.datetime:
        return o.isoformat()

def jsondumps(o):
    return json.dumps(o, default=default)

次にのjsondumps代わりに使用しますjson.dumps。印刷されます:

>>> jsondumps({'today': datetime.date.today()})
'{"today": "2013-07-30"}'

私はあなたが欲しい、後でdefaultメソッドの簡単な工夫で他の特別なケースをこれに追加できます。例:

def default(o):
    if type(o) is datetime.date or type(o) is datetime.datetime:
        return o.isoformat()
    if type(o) is decimal.Decimal:
        return float(o)

1
isinstance(o、(datetime.date、datetime.datetime、))を使用する必要があります。おそらくdatetime.timeを含めても害はありません。
Rebs

これはもう良い解決策ではないと思います。おそらく、変換はコード内でより特権的な場所になり、理解しやすい場所になるはずです。そのため、データベースに物事を入れたときに何に変換するかがわかります。透過的な機能。しかし、私にはわかりません。
fiatjaf 2014年

1
JSONは、後で処理するためにデータをシリアル化するのに適しています。あなたはそのデータが何であるか正確に知らないかもしれません。そして、あなたがする必要はありません。JSONのシリアライズが機能するはずです。UnicodeをASCIIに変換するのと同じように。Pythonは、あいまいな関数なしでこれを行うことができないため、使用するのが面倒です。データベースの検証は、別の問題のIMOです。
Rebs 2014年

いいえ、それは「ただ働く」べきではありません。シリアル化がどのように行われたかわからず、後で別のプログラム/言語からデータにアクセスする必要がある場合は、失われます。
fiatjaf 2014年

2
JSONは文字列、整数、浮動小数点数、日付に一般的に使用されます(他の人も通貨、気温を使用していると思います)しかし、datetimeは標準ライブラリの一部であり、逆シリアル化をサポートする必要があります。それはこの質問のためではなかった場合、私はまだ手動で日付のために(私は常にための構造を作成しなかった)私の信じられないほど複雑なJSONのブロブを検索し、それらを1だけ1を直列化するだろう
Rebs

16

このQは何度も繰り返されます-シリアル化が日時をサポートするようにjsonモジュールにパッチを適用する簡単な方法。

import json
import datetime

json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)

いつものようにjsonシリアル化を使用するよりも、今回はdatetimeがisoformatとしてシリアル化されます。

json.dumps({'created':datetime.datetime.now()})

結果: '{"created": "2015-08-26T14:21:31.853855"}'

詳細と注意事項については、StackOverflow:PythonとJavaScriptの間のJSON日時をご覧ください。


モンキーパッチFTW。もちろん厄介なことは、これによりアプリケーション全体のjsonモジュールの動作が変更されるため、大規模なアプリケーションでは他のユーザーを驚かせる可能性があるため、通常は注意して使用する必要があります。
Jaap Versteegh

15

json.dumpsメソッドは、defaultと呼ばれるオプションのパラメーターを受け入れることができます。JSONが値を変換しようとするたびに、変換方法がわからないため、渡された関数が呼び出されます。関数は問題のオブジェクトを受け取り、オブジェクトのJSON表現を返すことが期待されています。

def myconverter(o):
 if isinstance(o, datetime.datetime):
    return o.__str__()

print(json.dumps(d, default = myconverter)) 

14

python3.7を使用している場合、最適なソリューションはdatetime.isoformat()and を使用すること datetime.fromisoformat()です。彼らはナイーブdatetimeオブジェクトとアウェアオブジェクトの両方で動作します:

#!/usr/bin/env python3.7

from datetime import datetime
from datetime import timezone
from datetime import timedelta
import json

def default(obj):
    if isinstance(obj, datetime):
        return { '_isoformat': obj.isoformat() }
    return super().default(obj)

def object_hook(obj):
    _isoformat = obj.get('_isoformat')
    if _isoformat is not None:
        return datetime.fromisoformat(_isoformat)
    return obj

if __name__ == '__main__':
    #d = { 'now': datetime(2000, 1, 1) }
    d = { 'now': datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=-8))) }
    s = json.dumps(d, default=default)
    print(s)
    print(d == json.loads(s, object_hook=object_hook))

出力:

{"now": {"_isoformat": "2000-01-01T00:00:00-08:00"}}
True

python3.6以下を使用していて、タイムゾーンではなく時間の値のみに関心がある場合はdatetime.timestamp()datetime.fromtimestamp()代わりにを使用できます。

python3.6以前を使用していて、タイムゾーンを気にしている場合は、を介して取得できdatetime.tzinfoますが、このフィールドを自分でシリアル化する必要があります。これを行う最も簡単な方法_tzinfoは、シリアル化されたオブジェクトに別のフィールドを追加することです。

最後に、これらすべての例の精度に注意してください。


datetime.isoformat()はまた、Pythonの2.7で存在する:docs.python.org/2/library/...
powlo

11

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

次に例を示します。

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'}

10

これは、「日時がJSONシリアライズ可能ではない」問題を解決する簡単な解決策です。

enco = lambda obj: (
    obj.isoformat()
    if isinstance(obj, datetime.datetime)
    or isinstance(obj, datetime.date)
    else None
)

json.dumps({'date': datetime.datetime.now()}, default=enco)

出力:-> {"date": "2015-12-16T04:48:20.024609"}


8

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は日付について少しあいまいだと思います)


5

これを行う最も簡単な方法は、日時形式のディクショナリの部分をisoformatに変更することです。その値は事実上、jsonが問題ないisoformatの文字列になります。

v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()

5

実際、それは非常に簡単です。日付を頻繁にシリアル化する必要がある場合は、それらを文字列として処理します。必要に応じて、それらを簡単に日付時刻オブジェクトに戻すことができます。

主に日時オブジェクトとして作業する必要がある場合は、シリアル化する前にそれらを文字列として変換します。

import json, datetime

date = str(datetime.datetime.now())
print(json.dumps(date))
"2018-12-01 15:44:34.409085"
print(type(date))
<class 'str'>

datetime_obj = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S.%f')
print(datetime_obj)
2018-12-01 15:44:34.409085
print(type(datetime_obj))
<class 'datetime.datetime'>

ご覧のとおり、どちらの場合も出力は同じです。タイプのみが異なります。


3

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

application / json MIMEタイプを使用して、指定された引数のJSON表現で応答を作成します。

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

1
質問はフラスコとは何の関係もありません。
Zoran Pavlovic 2014

2
問題はpythonについてです。私の答えはpythonを使用して質問を解決します。OPは、ソリューションに特定のライブラリを含めるか除外するかについては述べていません。これは、この質問を読んでいて、の代替を望んでいる人にも役立ちpymongoます。
reubano 2014

彼らの質問はPython に関するもので、Flask に関するものではありません。質問への回答にはFlaskは必要ないので、削除することをお勧めします。
Zoran Pavlovic 2014

3

これを例を使って解析してみてください:

#!/usr/bin/env python

import datetime
import json

import dateutil.parser  # pip install python-dateutil


class JSONEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()
        return super(JSONEncoder, self).default(obj)


def test():
    dts = [
        datetime.datetime.now(),
        datetime.datetime.now(datetime.timezone(-datetime.timedelta(hours=4))),
        datetime.datetime.utcnow(),
        datetime.datetime.now(datetime.timezone.utc),
    ]
    for dt in dts:
        dt_isoformat = json.loads(json.dumps(dt, cls=JSONEncoder))
        dt_parsed = dateutil.parser.parse(dt_isoformat)
        assert dt == dt_parsed
        print(f'{dt}, {dt_isoformat}, {dt_parsed}')
        # 2018-07-22 02:22:42.910637, 2018-07-22T02:22:42.910637, 2018-07-22 02:22:42.910637
        # 2018-07-22 02:22:42.910643-04:00, 2018-07-22T02:22:42.910643-04:00, 2018-07-22 02:22:42.910643-04:00
        # 2018-07-22 06:22:42.910645, 2018-07-22T06:22:42.910645, 2018-07-22 06:22:42.910645
        # 2018-07-22 06:22:42.910646+00:00, 2018-07-22T06:22:42.910646+00:00, 2018-07-22 06:22:42.910646+00:00


if __name__ == '__main__':
    test()

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

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オブジェクトをインポートおよびエクスポートできるようになりました。他の型に拡張するのは難しいことではありません。


1
Python 3で爆発しTypeError: 'str' does not support the buffer interfaceます。これは、'wb'オープンモードのためです'w'。また、日付に類似している'0000891618-05-000338'が一致するパターンではないデータがある場合は、逆シリアル化が吹き込まれます。
omikron 2014

2

変換datestring

date = str(datetime.datetime(somedatetimehere)) 

jjmontesの回答はそれを正確に行いますが、すべての日付に対して明示的に行う必要はありません...
bluesummers

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

免責事項:それは私が作ったものです。同じ問題があったからです。


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(),
                  ...

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)

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に渡すことができます。いずれにしてもこれはうまくいくはずです。


0

djangoモデルオブジェクトを外部化してJSONとしてダンプするときにも同じ問題が発生しました。これを解決する方法は次のとおりです。

def externalize(model_obj):
  keys = model_obj._meta.get_all_field_names() 
  data = {}
  for key in keys:
    if key == 'date_time':
      date_time_obj = getattr(model_obj, key)
      data[key] = date_time_obj.strftime("%A %d. %B %Y")
    else:
      data[key] = getattr(model_obj, key)
  return data

0
def j_serial(o):     # self contained
    from datetime import datetime, date
    return str(o).split('.')[0] if isinstance(o, (datetime, date)) else None

上記のユーティリティの使用:

import datetime
serial_d = j_serial(datetime.datetime.now())
if serial_d:
    print(serial_d)  # output: 2018-02-28 02:23:15

0

このライブラリsuperjsonはそれを行うことができます。そして、次の指示に従うことで、独自のPythonオブジェクト用のjsonシリアライザーを簡単にカスタムできますhttps://superjson.readthedocs.io/index.html#extend

一般的な概念は次のとおりです。

コードは、Pythonオブジェクトに基づいて適切なシリアル化/逆シリアル化メソッドを見つける必要があります。通常、完全なクラス名は適切な識別子です。

そして、あなたのser / deserメソッドは、オブジェクトを通常のJson直列化可能オブジェクト(一般的なpythonタイプ、dict、リスト、文字列、int、floatの組み合わせ)に変換できる必要があります。そして、deserメソッドを逆に実装します。


-1

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'> 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.