"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.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 모듈 설명서의 기본 사용법 섹션을 참조하십시오 .


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

변환 date 에 string

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.