Дата и время JSON между Python и JavaScript

Я хочу отправить объект datetime.datetime в сериализованной форме из Python с помощью JSON и десериализовать в JavaScript с помощью JSON. Как лучше всего это сделать?

Вы предпочитаете использовать библиотеку или хотите сами написать код?

guettli 26.06.2015 15:23
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
399
1
192 658
12

Ответы 12

Если вы уверены, что JSON будет использовать только Javascript, я предпочитаю передавать объекты Javascript Date напрямую.

Метод ctime() для объектов datetime вернет строку, которую может понять объект Javascript Date.

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

Javascript с радостью будет использовать это как литерал объекта, и у вас есть встроенный объект Date.

Технически недействительный JSON, но это допустимый литерал объекта JavaScript. (Из принципа я бы установил Content-Type на text / javascript вместо application / json.) Если потребитель будет всегда, а навсегда будет Только реализацией JavaScript, то да, это довольно элегантно. Я бы использовал это.

system PAUSE 28.05.2009 18:45
.ctime() - ОЧЕНЬ плохой способ передачи информации о времени, .isoformat() намного лучше. .ctime() отбрасывает часовой пояс и переход на летнее время, как будто их не существует. Эта функция должна быть убита.
Evgeny 01.01.2012 21:37

Годы спустя: пожалуйста, никогда не думайте об этом. Это будет работать только в том случае, если вы eval () ваш json в Javascript, что вам действительно не следует ...

domenukk 11.04.2019 04:22

Я обнаружил, что для кросс-языковых проектов лучше всего подходят строки, содержащие даты RFC 3339. Дата RfC 3339 выглядит так:

  1985-04-12T23:20:50.52Z

Я думаю, что большая часть формата очевидна. Единственным несколько необычным может быть буква «Z» в конце. Это означает GMT / UTC. Вы также можете добавить смещение часового пояса, например +02: 00 для CEST (Германия летом). Лично я предпочитаю хранить все в формате UTC, пока оно не отобразится.

Для отображения, сравнения и хранения вы можете оставить его в строковом формате для всех языков. Если вам нужна дата для расчетов, легко преобразовать ее обратно в собственный объект даты на большинстве языков.

Итак, сгенерируйте JSON следующим образом:

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

К сожалению, конструктор Date в Javascript не принимает строки RfC 3339, но в Интернете доступно множество парсеры.

huTools.hujson пытается справиться с наиболее распространенными проблемами кодирования, с которыми вы можете столкнуться в коде Python, включая объекты даты / даты и времени, при правильной обработке часовых поясов.

Этот механизм форматирования даты изначально поддерживается как datetime: datetime.isoformat (), так и simplejson, который по умолчанию выгружает объекты datetime как строки isoformat. Нет необходимости в ручном взломе strftime.

jrk 21.10.2009 09:42

@jrk - У меня не получается автоматическое преобразование объектов datetime в строку isoformat. Для меня simplejson.dumps(datetime.now()) дает TypeError: datetime.datetime(...) is not JSON serializable

kostmo 15.03.2010 09:40
json.dumps(datetime.datetime.now().isoformat()) - вот где происходит волшебство.
jathanism 21.04.2010 07:26

Прелесть simplejson в том, что если у меня сложная структура данных, он проанализирует ее и превратит в JSON. Если мне нужно выполнить json.dumps (datetime.datetime.now (). Isoformat ()) для каждого объекта datetime, я потеряю это. Есть ли способ исправить это?

andrewrk 26.04.2010 03:47

superjoe30: как это сделать, см. stackoverflow.com/questions/455580/…

max 26.04.2010 23:01

да, stackoverflow.com/questions/455580/… - лучшее решение

Nick Franceschina 24.08.2010 04:26

Самые последние конструкторы даты Javascript в настоящее время принимают строки RfC3339

max 05.12.2011 12:50

Z для GMT / UTC - это код военной радиостанции, зулусское время: en.wikipedia.org/wiki/List_of_m military_time_zones.

Daniel J. Pritchett 23.08.2012 01:46

Вы можете добавить параметр 'default' в json.dumps, чтобы справиться с этим:

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))

Обновление: добавлен вывод типа и значения. Обновление: также обрабатывать дату

это решение намного проще, чем у mdorseif. Отлично работает в моем приложении django.

andrewrk 26.04.2010 04:49

Проблема в том, что если у вас есть другие объекты в list / dict, этот код преобразует их в None.

Tomasz Wysocki 03.07.2010 11:02

json.dumps тоже не знает, как их преобразовать, но исключение подавляется. К сожалению, однострочное исправление лямбда имеет свои недостатки. Если вы предпочитаете создавать исключение для неизвестных (что является хорошей идеей), используйте функцию, которую я добавил выше.

JT. 17.07.2010 04:06

полный выходной формат также должен иметь часовой пояс ... а isoformat () не предоставляет эту функцию ... поэтому вы должны обязательно добавить эту информацию в строку перед возвратом

Nick Franceschina 24.08.2010 04:27

Это лучший способ. Почему это не было выбрано в качестве ответа?

Brendon Crawford 08.06.2011 03:56

Похоже, что в ответе есть ошибка - в последней строке, где возникает ошибка TypeError, часть подстановки строки (type (Obj), repr (Obj)) относится к чему-то с именем Obj, тогда как это должно быть obj (обратите внимание на заглавные буквы) .

Sam 18.09.2011 10:56

отличный ответ, вы также можете получить метку времени, вы можете использовать что-то вроде этого: date2ts = lambda obj: time.mktime (obj.timetuple ()) if isinstance (obj, datetime.datetime) else None

tutuDajuju 07.06.2012 16:35

Лучше поднять TypeError, когда тип не является datetime - иначе данные могут быть потеряны без вашего ведома!

ibz 28.06.2012 14:27

Лямбда может быть адаптирована для вызова базовой реализации для типов, отличных от datetime, поэтому при необходимости может возникнуть ошибка TypeError: dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime) else json.JSONEncoder().default(obj)

Pascal Bourque 01.05.2013 17:34

Небольшое упрощение в однострочном лямбда-выражении: if isinstance(obj, (datetime.datetime, datetime.date)) устранит необходимость в or.

hobs 04.01.2014 04:51

@NickFranceschina Я только что протестировал isoformat(), и он выводит смещение часового пояса. >>> datetime.datetime (2012, 10, 20, tzinfo = tzoffset (Нет, 3600 * 12)). isoformat () '2012-10-20T00: 00: 00 + 12: 00'

JesseBuesking 16.01.2014 04:43

JSON from должен включать часовой пояс, и желательно UTC с буквой Z. Без этого время, подобное 2010-04-20T20: 08: 21.634121, будет считаться местным временем веб-браузера.

cagney 06.11.2018 21:40

Используя json, вы можете создать подкласс JSONEncoder и переопределить метод default (), чтобы предоставить свои собственные сериализаторы:

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"]'

Незначительное улучшение - использовать obj.isoformat(). Вы также можете использовать более распространенный вызов dumps(), который принимает другие полезные аргументы (например, indent): simplejson.dumps (myobj, cls = JSONEncoder, ...)

rcoup 22.12.2010 06:25

Потому что это вызовет родительский метод JSONEncoder, а не родительский метод DateTimeJSONEncoder. IE, вы поднялись бы на два уровня.

Brian Arsuaga 12.11.2012 22:05

Вот довольно полное решение для рекурсивного кодирования и декодирования объектов datetime.datetime и datetime.date с использованием модуля стандартной библиотеки json. Для этого требуется Python> = 2.6, поскольку с тех пор код формата %f в строке формата datetime.datetime.strptime () поддерживается только в. Для поддержки Python 2.5 отбросьте %f и удалите микросекунды из строки даты ISO, прежде чем пытаться преобразовать ее, но, конечно, вы потеряете точность в микросекундах. Для взаимодействия со строками даты ISO из других источников, которые могут включать имя часового пояса или смещение UTC, вам также может потребоваться удалить некоторые части строки даты перед преобразованием. Полный анализатор строк даты 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))

Если вы напечатаете дату как datetime.datetime.utcnow().isoformat()[:-3]+"Z", она будет точно такой же, как то, что JSON.stringify () создает в javascript.

w00t 01.06.2014 01:12

Я разобрался.

Допустим, у вас есть объект Python datetime, d, созданный с помощью datetime.now (). Его значение:

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

Вы можете сериализовать его в JSON как строку даты и времени ISO 8601:

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

Пример объекта datetime будет сериализован как:

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

Это значение, однажды полученное на уровне Javascript, может создать объект Date:

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

Начиная с Javascript 1.8.5, объекты Date имеют метод toJSON, который возвращает строку в стандартном формате. Следовательно, чтобы сериализовать указанный выше объект Javascript обратно в JSON, команда будет выглядеть так:

d.toJSON()

Что даст вам:

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

Эта строка, однажды полученная в Python, может быть десериализована обратно в объект datetime:

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

Это приводит к следующему объекту datetime, который является тем же самым, с которого вы начали, и, следовательно, правильным:

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

На стороне питона:

import time, json
from datetime import datetime as dt
your_date = dt.now()
data = json.dumps(time.mktime(your_date.timetuple())*1000)
return data # data send to javascript

На стороне javascript:

var your_date = new Date(data)

где данные являются результатом Python

Мой совет - использовать библиотеку. Их несколько доступно на pypi.org.

Пользуюсь вот такой, работает хорошо: https://pypi.python.org/pypi/asjson

Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если ссылка на страницу изменится. - Из обзора

Cray 13.10.2020 13:32

Поздно в игре ... :)

Очень простое решение - исправить модуль 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 (в существующем коде или нет).

Обратите внимание, что некоторые могут посчитать такое исправление библиотек плохой практикой. Следует проявлять особую осторожность, если вы можете захотеть расширить свое приложение более чем одним способом - в таком случае я предлагаю использовать решение от ramen или JT и выбирать правильное расширение json в каждом случае.

Это незаметно поедает несериализуемые объекты и превращает их в None. Вместо этого вы можете создать исключение.

Blender 26.04.2016 16:17

Не так много, чтобы добавить к ответу сообщества вики, кроме отметка времени!

Javascript использует следующий формат:

new Date().toJSON() // "2016-01-08T19:00:00.123Z"

Сторона Python (для обработчика json.dumps см. Другие ответы):

>>> from datetime import datetime
>>> d = datetime.strptime('2016-01-08T19:00:00.123Z', '%Y-%m-%dT%H:%M:%S.%fZ')
>>> d
datetime.datetime(2016, 1, 8, 19, 0, 0, 123000)
>>> d.isoformat() + 'Z'
'2016-01-08T19:00:00.123000Z'

Если вы не укажете Z, интерфейсные фреймворки, такие как angular, не смогут отображать дату в локальном часовом поясе браузера:

> $filter('date')('2016-01-08T19:00:00.123000Z', 'yyyy-MM-dd HH:mm:ss')
"2016-01-08 20:00:00"
> $filter('date')('2016-01-08T19:00:00.123000', 'yyyy-MM-dd HH:mm:ss')
"2016-01-08 19:00:00"

Очевидно, «Правильный» формат даты JSON (ну и JavaScript) - это 2012-04-23T18: 25: 43.511Z - UTC и "Z". Без этого JavaScript будет использовать местный часовой пояс веб-браузера при создании объекта Date () из строки.

Для «наивного» времени (то, что Python называет временем без часового пояса, и предполагается, что это локальный), ниже будет установить местный часовой пояс, чтобы затем его можно было правильно преобразовать в UTC:

def default(obj):
    if hasattr(obj, "json") and callable(getattr(obj, "json")):
        return obj.json()
    if hasattr(obj, "isoformat") and callable(getattr(obj, "isoformat")):
        # date/time objects
        if not obj.utcoffset():
            # add local timezone to "naive" local time
            # https://stackoverflow.com/questions/2720319/python-figure-out-local-timezone
            tzinfo = datetime.now(timezone.utc).astimezone().tzinfo
            obj = obj.replace(tzinfo=tzinfo)
        # convert to UTC
        obj = obj.astimezone(timezone.utc)
        # strip the UTC offset
        obj = obj.replace(tzinfo=None)
        return obj.isoformat() + "Z"
    elif hasattr(obj, "__str__") and callable(getattr(obj, "__str__")):
        return str(obj)
    else:
        print("obj:", obj)
        raise TypeError(obj)

def dump(j, io):
    json.dump(j, io, indent=2, default=default)

Почему это так сложно.

Для преобразования даты Python в JavaScript объект даты должен иметь определенный формат ISO, то есть формат ISO или номер UNIX. Если в формате ISO отсутствует какая-либо информация, вы можете сначала преобразовать в номер Unix с помощью Date.parse. Более того, Date.parse также работает с React, а новая дата может вызвать исключение.

Если у вас есть объект DateTime без миллисекунд, необходимо учитывать следующее. :

  var unixDate = Date.parse('2016-01-08T19:00:00') 
  var desiredDate = new Date(unixDate).toLocaleDateString();

Дата в примере может также быть переменной в объекте result.data после вызова API.

Чтобы узнать о параметрах отображения даты в желаемом формате (например, для отображения длинных дней недели), ознакомьтесь с Документ MDN.

есть ли способ сделать это, например, python для массивов? У меня есть массив объектов datetime, и я хочу нарезать час

alkanschtein 01.12.2020 23:30

Другие вопросы по теме