[javascript] Python과 JavaScript 사이의 JSON 날짜 시간

JSON을 사용하여 Python에서 직렬화 된 형식으로 datetime.datetime 객체를 보내고 JSON을 사용하여 JavaScript 에서 직렬화 해제하고 싶습니다 . 가장 좋은 방법은 무엇입니까?



답변

json.dumps에 ‘default’매개 변수를 추가하여이를 처리 할 수 ​​있습니다.

date_handler = lambda obj: (
    obj.isoformat()
    if isinstance(obj, (datetime.datetime, datetime.date))
    else None
)
json.dumps(datetime.datetime.now(), default=date_handler)
'"2010-04-20T20:08:21.634121"'

이는 ISO 8601 형식입니다.

보다 포괄적 인 기본 처리기 기능 :

def handler(obj):
    if hasattr(obj, 'isoformat'):
        return obj.isoformat()
    elif isinstance(obj, ...):
        return ...
    else:
        raise TypeError, 'Object of type %s with value of %s is not JSON serializable' % (type(obj), repr(obj))

업데이트 : 유형뿐만 아니라 값의 출력이 추가되었습니다.
업데이트 : 날짜도 처리


답변

언어 간 프로젝트의 경우 RfC 3339 날짜를 포함하는 문자열 이 가장 좋은 방법 이라는 것을 알았습니다 . RfC 3339 날짜는 다음과 같습니다.

  1985-04-12T23:20:50.52Z

나는 대부분의 형식이 분명하다고 생각합니다. 다소 특이한 것은 끝에 “Z”일 수 있습니다. GMT / UTC를 나타냅니다. CEST (여름에는 독일)에 +02 : 00과 같은 시간대 오프셋을 추가 할 수도 있습니다. 개인적으로 모든 것이 표시 될 때까지 UTC로 유지하는 것을 선호합니다.

표시, 비교 및 ​​저장을 위해 모든 언어에서 문자열 형식으로 남겨 둘 수 있습니다. 계산 날짜가 필요한 경우 대부분의 언어로 날짜를 기본 날짜 객체로 쉽게 변환 할 수 있습니다.

따라서 다음과 같이 JSON을 생성하십시오.

  json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ'))

불행히도 Javascript의 Date 생성자는 RfC 3339 문자열을 허용하지 않지만 인터넷 에는 많은 파서가 있습니다.

huTools.hujson 은 시간대를 올바르게 처리하면서 날짜 / 날짜 / 시간 객체를 포함하여 Python 코드에서 발생할 수있는 가장 일반적인 인코딩 문제를 처리하려고합니다.


답변

나는 그것을 해결했다.

datetime.now ()로 만든 파이썬 datetime 객체 d 가 있다고 가정 해 봅시다 . 그 가치는 다음과 같습니다.

datetime.datetime(2011, 5, 25, 13, 34, 5, 787000)

ISO 8601 날짜 / 시간 문자열로 JSON에 직렬화 할 수 있습니다.

import json
json.dumps(d.isoformat())

예제 날짜 시간 객체는 다음과 같이 직렬화됩니다.

'"2011-05-25T13:34:05.787000"'

Javascript 레이어에서 수신 한이 값은 Date 객체를 생성 할 수 있습니다.

var d = new Date("2011-05-25T13:34:05.787000");

Javascript 1.8.5부터 Date 객체에는 표준 형식으로 문자열을 반환하는 toJSON 메서드가 있습니다. 위의 자바 스크립트 객체를 다시 JSON으로 직렬화하려면 명령은 다음과 같습니다.

d.toJSON()

어느 것이 당신에게 줄 것입니까?

'2011-05-25T20:34:05.787Z'

이 문자열은 일단 파이썬으로 수신되면 datetime 객체로 역 직렬화 될 수 있습니다.

datetime.strptime('2011-05-25T20:34:05.787Z', '%Y-%m-%dT%H:%M:%S.%fZ')

결과적으로 다음과 같은 날짜 / 시간 객체가 생성됩니다.

datetime.datetime(2011, 5, 25, 20, 34, 5, 787000)


답변

를 사용하여 jsonJSONEncoder를 서브 클래 싱하고 default () 메서드를 재정 의하여 고유 한 사용자 지정 serializer를 제공 할 수 있습니다.

import json
import datetime

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

그런 다음 다음과 같이 호출 할 수 있습니다.

>>> DateTimeJSONEncoder().encode([datetime.datetime.now()])
'["2010-06-15T14:42:28"]'


답변

다음은 표준 라이브러리 json모듈을 사용하여 datetime.datetime 및 datetime.date 객체를 재귀 적으로 인코딩하고 디코딩하기위한 매우 완벽한 솔루션입니다 . %fdatetime.datetime.strptime () 형식 문자열 의 형식 코드는 그 이후로만 지원 되므로 Python> = 2.6이 필요합니다 . Python 2.5 지원의 경우, %f변환하기 전에 ISO 날짜 문자열에서 마이크로 초를 제거하고 제거하십시오. 물론 마이크로 초 정밀도는 느슨합니다. 표준 시간대 이름 또는 UTC 오프셋을 포함 할 수있는 다른 소스의 ISO 날짜 문자열과의 상호 운용성을 위해 변환 전에 날짜 문자열의 일부를 제거해야 할 수도 있습니다. ISO 날짜 문자열 (및 기타 여러 날짜 형식)에 대한 완전한 파서는 타사 dateutil 모듈을 참조하십시오 .

디코딩은 ISO 날짜 문자열이 JavaScript 리터럴 객체 표기법 또는 객체 내 중첩 구조의 값인 경우에만 작동합니다. 최상위 배열의 항목 인 ISO 날짜 문자열은 디코딩 되지 않습니다 .

즉,이 작동합니다 :

date = datetime.datetime.now()
>>> json = dumps(dict(foo='bar', innerdict=dict(date=date)))
>>> json
'{"innerdict": {"date": "2010-07-15T13:16:38.365579"}, "foo": "bar"}'
>>> loads(json)
{u'innerdict': {u'date': datetime.datetime(2010, 7, 15, 13, 16, 38, 365579)},
u'foo': u'bar'}

그리고 이것도 :

>>> json = dumps(['foo', 'bar', dict(date=date)])
>>> json
'["foo", "bar", {"date": "2010-07-15T13:16:38.365579"}]'
>>> loads(json)
[u'foo', u'bar', {u'date': datetime.datetime(2010, 7, 15, 13, 16, 38, 365579)}]

그러나 이것은 예상대로 작동하지 않습니다.

>>> json = dumps(['foo', 'bar', date])
>>> json
'["foo", "bar", "2010-07-15T13:16:38.365579"]'
>>> loads(json)
[u'foo', u'bar', u'2010-07-15T13:16:38.365579']

코드는 다음과 같습니다.

__all__ = ['dumps', 'loads']

import datetime

try:
    import json
except ImportError:
    import simplejson as json

class JSONDateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (datetime.date, datetime.datetime)):
            return obj.isoformat()
        else:
            return json.JSONEncoder.default(self, obj)

def datetime_decoder(d):
    if isinstance(d, list):
        pairs = enumerate(d)
    elif isinstance(d, dict):
        pairs = d.items()
    result = []
    for k,v in pairs:
        if isinstance(v, basestring):
            try:
                # The %f format code is only supported in Python >= 2.6.
                # For Python <= 2.5 strip off microseconds
                # v = datetime.datetime.strptime(v.rsplit('.', 1)[0],
                #     '%Y-%m-%dT%H:%M:%S')
                v = datetime.datetime.strptime(v, '%Y-%m-%dT%H:%M:%S.%f')
            except ValueError:
                try:
                    v = datetime.datetime.strptime(v, '%Y-%m-%d').date()
                except ValueError:
                    pass
        elif isinstance(v, (dict, list)):
            v = datetime_decoder(v)
        result.append((k, v))
    if isinstance(d, list):
        return [x[1] for x in result]
    elif isinstance(d, dict):
        return dict(result)

def dumps(obj):
    return json.dumps(obj, cls=JSONDateTimeEncoder)

def loads(obj):
    return json.loads(obj, object_hook=datetime_decoder)

if __name__ == '__main__':
    mytimestamp = datetime.datetime.utcnow()
    mydate = datetime.date.today()
    data = dict(
        foo = 42,
        bar = [mytimestamp, mydate],
        date = mydate,
        timestamp = mytimestamp,
        struct = dict(
            date2 = mydate,
            timestamp2 = mytimestamp
        )
    )

    print repr(data)
    jsonstring = dumps(data)
    print jsonstring
    print repr(loads(jsonstring))


답변

Javascript만이 JSON을 소비한다고 확신하는 경우 Javascript Date객체를 직접 전달하는 것이 좋습니다.

객체 의 ctime()메소드 datetime는 Javascript Date 객체가 이해할 수있는 문자열을 반환합니다.

import datetime
date = datetime.datetime.today()
json = '{"mydate":new Date("%s")}' % date.ctime()

Javascript는이를 행복하게 객체 리터럴로 사용하며 Date 객체가 내장되어 있습니다.


답변

게임에서 늦게 … 🙂

아주 간단한 해결책은 json 모듈 기본값을 패치하는 것입니다. 예를 들면 다음과 같습니다.

import json
import datetime

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

이제 json.dumps () 를 항상 datetime을 지원 한 것처럼 사용할 수 있습니다 …

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

이것은 항상 확장하기 위해 json 모듈에 대한이 확장이 필요하고 귀하 또는 다른 사람들이 json 직렬화를 사용하는 방식 (기존 코드에서 또는 아닌)을 변경하지 않으려는 경우에 적합합니다.

어떤 사람들은 그런 방식으로 라이브러리 패치를 나쁜 습관으로 생각할 수 있습니다. 응용 프로그램을 여러 가지 방법으로 확장하려는 경우 특별한주의가 필요합니다.이 경우라면라면 또는 JT로 솔루션을 사용하고 각 경우에 적절한 json 확장을 선택하는 것이 좋습니다.