"JSON 일련 화 가능하지 않은 datetime.datetime"을 극복하는 방법은 무엇입니까?
다음과 같은 기본 사전이 있습니다.
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
있습니다.
2018 년 업데이트
원래 답변은 MongoDB "날짜"필드가 다음과 같이 표현되는 방식을 수용했습니다.
{"$date": 1506816000000}
datetime
JSON 으로 직렬화하는 일반적인 파이썬 솔루션을 원한다면 @jjmontes 답변의 에서 종속성이 필요하지 않은 빠른 솔루션을 확인하십시오 .
mongoengine (댓글 당)을 사용하고 pymongo는 json을 사용하고 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
사용자 지정과 사용하는 것 사이 에 한 가지 차이점 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
따라서 어떤 경우에는주의해야 할 수도 있습니다.
날짜와 모든 것을 먹는 내 빠르고 더러운 JSON 발표 :
json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)
다른 답변을 기반으로하는 간단한 솔루션 은 문자열 로만 변환 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
또는 클래스 인지 확인한 다음 ISO 8601 형식 인 YYYY-MM-DDTHH : MM : SS (JavaScript로 쉽게 사용할 수 있음)에 따라 datetime.date
사용 하는 데 사용 .isoformat()
됩니다. ). 더 복잡한 구성 화 표현이 필요한 경우 str () 대신 다른 코드를 사용할 수 있습니다 (이 질문에 대한 다른 답변 참조). 코드는 생성 화 할 수없는 유형으로 호출 된 경우를 처리하기 위해 예외를 발생시키는 것으로 끝납니다.
이 json_serial 함수는 다음과 같이 사용할 수 있습니다.
from datetime import datetime
from json import dumps
print dumps(datetime.now(), default=json_serial)
json.dumps의 기본 매개 변수가 작동하는 방법에 대한 자세한 내용은 json 모듈 문서의 기본 사용법 섹션 에서 사용할 수 있습니다 .
방금이 문제가 발생하고 내 해결은 하위 클래스입니다 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()
날짜를 공유로 변환
sample['somedate'] = str( datetime.utcnow() )
이를 위해 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'
내 해결은 다음과 달라집니다.
# -*- 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)
어떤 문제가있는 응용 프로그램이 있습니다. 내 접근 방식은 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"}
이 Q는 몇 번이고 반복됩니다. 내장 화가 datetime을 지원하도록 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 datetime을 참조하십시오 .
내 솔루션 (더 약간 설명으로 생각합니다) :
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)
다음은 "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"}
직렬화는 메서드 로 만들 려면 .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'}
python3.7을 사용하는 경우 가장 좋은 해결책은 and ; 순진하고 인식하는 객체 에서 작동 합니다.datetime.isoformat()
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()
대신 사용할 수 있습니다 .
python 3.6 이하를 사용하고 있고, 거기에 관심이 있고, 거기에 더할 수 datetime.tzinfo
있습니다. 이를 수행하는 가장 쉬운 방법 _tzinfo
은 생성 화 된에 다른 필드를 추가하는 것입니다 .
마지막으로,이 모든 예에서 시작주의하십시오.
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은 날짜에 약간의 모호가 있다고 생각합니다)
json.dumps 메소드는 함수로 예상되는 기본라는 선언 변수를 허용 할 수 있습니다. JSON은 값을 변환 할 때마다 변환 방법을 알지 못하여 전달한 함수를 호출합니다. 함수는 문제의 표현을 수신하고 JSON 표현을 반환합니다.
def myconverter(o):
if isinstance(o, datetime.datetime):
return o.__str__()
print(json.dumps(d, default = myconverter))
이를 수행하는 가장 간단한 방법은 datetime 형식의 dict 부분을 isoformat으로 변경하는 것입니다. 그 값은 json이 괜찮은 isoformat의 ked이 될 것입니다.
v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()
사실 아주 간단합니다. 날짜를 자주 사용하는 경우 자주 작업하십시오. 필요한 경우 쉽게 다시 datetime 객체로 변환 할 수 있습니다.
주로 datetime 객체로 작업해야하는 경우 생성하기 전에 변환하기 전에.
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'>
보시다시피 두 경우 모두 출력이 동일합니다. 유형 만.
뷰에서 결과를 사용하는 경우 응답을 반환해야합니다. API에 따르면 jsonify는 다음을 수행합니다.
application / json mimetype을 사용하여 지정된 인수의 JSON 표현으로 응답을 생성합니다.
json.dumps 로이 동작을 모방 몇 줄의 코드를 추가해야합니다.
response = make_response(dumps(sample, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response
또한 jsonify의 응답을 완전히 삭제해야합니다. 따라서 전체 파일은 다음과 가변됩니다.
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
다음은 datetime을 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 개체를 가져오고 있습니다. 다른 유형으로 확장하는 것이 어렵지 않습니다.
그것을 구문 분석하는 예제와 함께 시도하십시오.
#!/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()
변환 date
에string
date = str(datetime.datetime(somedatetimehere))
일반적으로 다음과 같은 여러 가지 방법으로 날짜 시간을 여러 가지로 할 수 있습니다.
- 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인지 알 수 있습니다. 딕셔너리로 메타 데이터를 저장하여 자동으로 사용할 수 있습니다 json_tricks
. 인간이 쉽게 편집 할 수 있습니다.
면책 조항 : 그것은 내가 만든 것입니다. 나는 같은 문제가 있었기 때문에.
내 솔루션 ...
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
sqlalchemy를 사용하여 클래스 내부에 내장 화 데코레이터를 작성하는 동안 동일한 오류 메시지가 나타납니다. 그래서 대신 :
Class Puppy(Base):
...
@property
def serialize(self):
return { 'id':self.id,
'date_birth':self.date_birth,
...
}
jgbarah의 isoformat () 사용 아이디어를 빌려서 원래 값에 isoformat ()을 추가했을 때 다음과 같이 시청합니다.
...
'date_birth':self.date_birth.isoformat(),
...
자신만의 서식을 원하는 경우 빠른 수정
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)
통신의 양쪽에있는 권한이 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))
datetime을 다음으로 가져옵니다.
from datetime import datetime
eval이 불평하기 때문에. 또는 eval에 대한 매개 변수로 datetime을 사용할 수 있습니다. 어쨌든 작동합니다.
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
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
이 라이브러리 superjson 은 그것을 사용할 수 있습니다. 그리고 https://superjson.readthedocs.io/index.html#extend 지침에 따라 Python 개체에 대한 JSON 변환기를 쉽게 사용자 수 있습니다 .
일반적인 개념은 다음과 가변합니다.
코드는 파이썬 객체를 기반으로 올바른 배열 화 / 비 배열 화 방법을 찾아야합니다. 일반적으로 전체 클래스 이름은 좋은 식별자입니다.
그런 다음 ser / deser 메서드는 인로 생성 목록을 일반 표준 유형, dict, 일반 클래스, int, float의 조합, Json 배열 변환이 가능합니다. 그리고 deser 메소드를 구현하십시오.
단순한
str(date_variable_here)
참고 URL : https://stackoverflow.com/questions/11875770/how-to-overcome-datetime-datetime-not-json-serializable
'IT' 카테고리의 다른 글
최후의 수단의 성능 최적화 전략 (0) | 2020.10.03 |
---|---|
배치 파일에서 줄 바꿈을 어떻게 에코 할 수 있습니까? (0) | 2020.10.03 |
Android에서 SharedPreferences를 사용하여 값을 저장, 가져 오기 및 편집하는 방법 (0) | 2020.10.03 |
Android 앱 업데이트시 SharedPreferences는 어떻게하나요? (0) | 2020.09.25 |
날짜별로 DynamoDB 쿼리 (0) | 2020.09.25 |