"JSON serializable이 아닌 datetime.datetime"을 극복하는 방법은 무엇입니까?


740

다음과 같은 기본 dict이 있습니다.

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
이것은 일반적으로 파이썬입니까, 아니면 장고입니까?
jdi

1
그것은 기술적으로 특히 파이썬이며, django를 사용하지 않고 mongodb에서 레코드를 검색합니다.
Rolando


나는 mongoengine을 사용하고 있지만 pymongo 가이 문제를 해결하거나 극복하는 더 좋은 방법이 있다면 알려주십시오.
Rolando

3
연결된 질문은 본질적으로 날짜 시간 객체를 직렬화하지 말고 직렬화하기 전에 공통 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커스텀을 사용하고 사용하는 것의 차이점은 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
)

장고가 약간의 데이터를 제거한다는 것입니까?

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

따라서 경우에 따라주의해야 할 수도 있습니다.


3
여러 라이브러리를 혼합하는 것이 좋습니다 / 예를 들어 문서를 삽입하기 위해 mongoengine을 가지고 있고 쿼리 / 검색을 위해 pymongo를 가지고 있습니까?
Rolando

나쁜 습관은 아니지만 기본 라이브러리가 사용하는 라이브러리에 대한 의존성을 의미합니다. mongoengine에서 필요한 것을 얻을 수 없다면 pymongo로 넘어갑니다. 와 동일합니다 Django MongoDB. 이후에는 장고 ORM 내에서 백엔드 불가지론 상태를 유지하려고 시도합니다. 그러나 때로는 추상화에서 필요한 것을 수행 할 수 없으므로 레이어를 드롭 다운합니다. 이 경우 유틸리티 형식을 사용하여 JSON 형식과 함께 제공되므로 문제와 완전히 관련이 없습니다.
jdi

Flask로 이것을 시도하고 있으며 json.dump를 사용하여 jsonify () 래퍼를 배치 할 수 없어서 application / json으로 돌아갑니다. jsonify (json.dumps (sample, default = json_util.default))를 반환하려고 시도
Rolando

2
@amit 구문을 암기하는 데 그다지 중요하지 않습니다. 문서를 잘 읽고 머리에 충분한 정보를 저장하여 언제 어디서 다시 검색해야하는지 인식 할 수 있기 때문입니다. 이 경우 "Oh가있는 사용자 정의 객체"라고 말한 다음 해당 사용법을 빠르게 새로 고
칩니다.

2
@guyskk이 5 년 전에 쓴 이래로 bjson 또는 mongo의 변경 사항을 추적하지 않았습니다. 당신이 날짜의 직렬화를 제어 원한다면 당신은 jgbarah에 의해 주어진 대답에 도시 된 바와 같이 자신의 기본 핸들러 함수를 작성해야
JDI

617

날짜와 모든 것을 먹는 내 빠르고 더러운 JSON 덤프 :

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

14
이것은 굉장하지만 불행히도 무슨 일이 있었는지 이해하지 못했습니까? 누구든지이 답변을 설명 할 수 있습니까?
Kishor Pawar

62
@KishorPawar : default직렬화 할 수없는 객체에 적용되는 함수입니다. 이 경우에는 str이므로 모르는 모든 것을 문자열로 변환합니다. 직렬화에는 좋지만 함수 또는 numpy 배열과 같이 경고없이 문자열 화 된 것처럼 직렬화 해제 (따라서 "빠른 & 더티")에는 그리 좋지 않습니다.
Mark

1
@ 마크 굉장합니다. 감사. 날짜와 같이 직렬화 할 수없는 값의 유형을 알고있는 경우에 유용합니다.
Kishor Pawar

2
나는 이것을 모르면서 평생 간직한 이유는 무엇입니까? :)
Arel

1
@jjmontes는 예를 들어 json.dumps({():1,type(None):2},default=str)raises TypeError와 같은 모든 유형에서 작동하지 않으며 유형이나 튜플을 가질 수 없습니다.
alancalvitti

443

특정 시리얼에 따라 다른 답변에 구축, 간단한 해결책이 바로 변환 datetime.datetimedatetime.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 모듈 설명서의 기본 사용법 섹션을 참조하십시오 .


5
그래 정답보다 꽤 수입 날짜 및 경우 isinstance (OBJ, datetime.datetime) 날짜 가져 오기 날짜에서 사용되지 않기 때문에, 나는 어쨌든 덕분에 많은 시간을 잃었
세르지오을

12
그러나 이것은 올바른 유형으로 직렬화를 해제하는 방법을 설명하지 않습니다.
BlueTrin 2016 년

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)

: 통화에서 같은 것을 할 나는 위의 답변 중 하나를 얻었다.json.dumps(yourobj, cls=DateTimeEncoder).isoformat()


22
사용자 정의 JSONEncoder를 구현하는 것이 올바른 방법이어야하기 때문에
업그레이드

25
이것이 최고의 답변 일뿐 만 아니라 일반 json 인코더의 일부 여야합니다. 디코딩 만 덜 애매한 경우 ..
Joost

4
Django를 사용하는 사람들은를 참조하십시오 DjangoJSONEncoder. docs.djangoproject.com/en/dev/topics/serialization/…
S. Kirby

4
매우 도움이되었습니다. 마지막 라인이 될 수return super(DateTimeEncoder, self).default(o)
밥 스타

16
Python 3을 사용하면 마지막 행이 훨씬 간단 해집니다.return super().default(o)
ariddell

124

날짜를 문자열로 변환

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

10
그리고 어떻게 파이썬에서 역 직렬화 할 수 있습니까?
wobmene

62
데이터 구조에 깊이 포함 된 datetime 객체가 많거나 임의 인 경우 문제가 발생합니다. 이것은 신뢰할 수있는 방법이 아닙니다.
Rebs

3
역 직렬화 : oDate = datetime.datetime.strptime(sDate, '%Y-%m-%d %H:%M:%S.%f'). 형식 : docs.python.org/2/library/datetime.html
Roman

13
시간대 정보를 무시하므로 다운 보트. .now()이것을 나타내지 않고 현지 시간 을 사용 한다는 것을 명심하십시오 . 적어도 .utcnow()사용 (다음 0000 또는 Z가 추가)해야한다
다니엘 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 문 안에 들여 쓰기 해서는 안됩니까? str (obj)를 사용하여 ISO 형식을 얻는 것이 더 일반적이라고 생각합니다.
Rebs

왜 들여 쓰기를 원하십니까? 이 스 니펫은 작동하며 결과는 자바 스크립트에서 직렬화 해제 / 파싱 될 수 있습니다.
Jay Taylor

5
obj가되지 않을 수 있으므로 [시간, 날짜, 날짜 시간] 객체
남군

2
현지 시간대의 UTC 오프셋이 0이 아닌 경우 (예 : 대부분) 예제가 올바르지 않습니다. datetime.now()현지 시간을 순진한 datetime 객체로 반환하지만 obj표준 시간대를 인식하지 않으면 코드는 UTC로 가정합니다 . datetime.utcnow()대신 사용하십시오 .
jfs

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

@Natim이 솔루션이 최고입니다. +1
Souvik Ray

20

비슷한 문제가있는 응용 프로그램이 있습니다. 내 접근 방식은 날짜 시간 값을 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"}

저장 시간이 datetime.utcnow () 수행하여 저장하면 작업에 실패
saurshaz을

1
datetime.utcnow ()에서 어떤 오류가 발생합니까? 그것은 나에게 잘 작동합니다.
codingatty

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

1
JSON은 나중에 처리하기 위해 데이터를 직렬화하는 데 유용합니다. 해당 데이터가 무엇인지 정확히 알지 못할 수 있습니다. 그리고 당신은 필요하지 않습니다. JSON 직렬화가 작동해야합니다. 유니 코드를 ASCII로 변환하는 것과 같습니다. 불분명 한 함수 없이이 작업을 수행 할 수없는 파이썬의 사용은 성가시다. 데이터베이스 유효성 검사는 별도의 문제 IMO입니다.
Rebs

아니요, "그냥 작동"해서는 안됩니다. 직렬화 방법을 모르고 나중에 다른 프로그램 / 언어에서 데이터에 액세스해야하는 경우 손실됩니다.
fiatjaf

2
JSON은 일반적으로 문자열, 정수, 부동 소수점, 날짜에 사용됩니다 (다른 사람들도 통화, 온도를 공통적으로 사용합니다). 그러나 datetime은 표준 라이브러리의 일부이며 de / serialization을 지원해야합니다. 이 질문에 대한 것이 아니라면, 나는 날짜에 대한 믿을 수 없을만큼 복잡한 json blob (항상 구조를 만들지는 않았 음)을 수동으로 검색하고 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 ()은 파이썬 2.7에도 있습니다 : docs.python.org/2/library/…
powlo

11

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

10

다음은 "datetime not JSON serializable"문제를 극복하는 간단한 솔루션입니다.

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

가장 간단한 방법은 날짜 / 시간 형식 인 dict의 일부를 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 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의 응답을 완전히 복제하려면 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

2
문제는 파이썬에 관한 것입니다. 내 대답은 파이썬을 사용하여 질문을 해결합니다. OP는 솔루션에 특정 라이브러리를 포함하거나 제외해야하는지 여부를 밝히지 않았습니다. 또한이 질문을 읽고 다른 사람에게 대안을 원하는 사람에게도 유용합니다 pymongo.
reubano

그들은 문제는 파이썬에 대해 모두입니다 하지 플라스크에 대해. 플라스크는 질문에 대한 답변에 필요하지 않으므로 제거하는 것이 좋습니다.
Zoran Pavlovic

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

2

변환 datestring

date = str(datetime.datetime(somedatetimehere)) 

jjmontes 답변은 정확히 그렇게하지만 모든 날짜에 대해 명시 적으로 할 필요없이 ...
bluesummers

2

일반적으로 날짜 시간을 직렬화하는 몇 가지 방법이 있습니다.

  1. ISO 문자열, 짧고 시간대 정보를 포함 할 수 있습니다 (예 : @ jgbarah 's answer)
  2. 타임 스탬프 (시간대 데이터가 손실 됨) (예 : @ JayTaylor 's answer)
  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를 사용하여 클래스 내부에서 serialize 데코레이터를 작성하는 동안 동일한 오류 메시지가 나타납니다. 따라서 대신 :

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

통신의 양쪽에 있다면 reson ()eval () 함수를 json과 함께 사용할 수 있습니다 .

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

평가가 불평하기 때문에. 또는 datetime을 매개 변수로 eval에 전달할 수 있습니다. 어쨌든 이것이 효과가 있습니다.


0

장고 모델 객체를 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이 할 수 있습니다. https://superjson.readthedocs.io/index.html#extend 명령에 따라 자신의 Python 객체에 맞게 json serializer를 쉽게 사용자 정의 할 수 있습니다. .

일반적인 개념은 다음과 같습니다.

코드는 파이썬 객체를 기반으로 올바른 직렬화 / 역 직렬화 방법을 찾아야합니다. 일반적으로 전체 클래스 이름은 좋은 식별자입니다.

그런 다음 ser / deser 메소드는 일반 파이썬 유형, dict, list, string, int, float의 조합으로 일반 Json 직렬화 가능 객체로 객체를 변환 할 수 있어야합니다. 그리고 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.