Как преодолеть «datetime.datetime не JSON сериализуемый»?

472

У меня есть базовый 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
    Это именно Python в целом, или, возможно, Django?
  • 0
    Технически это определенно python, я не использую django, но извлекаю записи из mongodb.
Показать ещё 9 комментариев
Теги:

31 ответ

233
Лучший ответ

Обновлено для 2018

Исходный ответ соответствовал тому, как поля даты в MongoDB были представлены как:

{"$date": 1506816000000}

Если вы хотите универсальное решение Python для сериализации datetime в json, посмотрите ответ @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 и использованием пользовательских 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

Таким образом, вам может потребоваться быть осторожным с этим в некоторых случаях.

  • 2
    Является ли хорошей / плохой практикой смешивать несколько библиотек, т.е. иметь mongoengine для вставки документов и pymongo для запроса / поиска?
  • 0
    Это неплохая практика, это просто подразумевает некоторую зависимость от библиотек, которые использует ваша основная библиотека. Если вы не можете выполнить то, что вам нужно от mongoengine, то вы переходите к pymongo. То же самое с Django MongoDB . В последнем случае вы пытаетесь оставаться в рамках django ORM, чтобы поддерживать независимое состояние бэкенда. Но иногда вы не можете делать то, что вам нужно в абстракции, поэтому вы опускаете слой. В этом случае это совершенно не связано с вашей проблемой, поскольку вы просто используете служебные методы для сопровождения формата JSON.
Показать ещё 13 комментариев
347

Основываясь на других ответах, простое решение, основанное на определенном сериализаторе, который просто преобразует объекты 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 или datetime.date, а затем использует .isoformat() для создания сериализованной версии в соответствии со стандартом ISO 8601, YYYY-MM- DDTHH: MM: SS (который легко декодируется JavaScript). Если запрашиваются более сложные сериализованные представления, вместо str() можно использовать другой код (см. Другие ответы на этот вопрос для примеров). Код заканчивается, создавая исключение, чтобы обработать случай, который вызывается с несериализуемым типом.

Эта функция json_serial может использоваться следующим образом:

from datetime import datetime
from json import dumps

print dumps(datetime.now(), default=json_serial)

Подробности о том, как работает параметр json.dumps по умолчанию, можно найти в Раздел Основное использование документации модуля json.

  • 5
    да, правильный ответ, более красивый импорт datetime и, если isinstance (obj, datetime.datetime), я потерял много времени, потому что не использовал datetime, импортируя datetime, в любом случае, спасибо
  • 8
    но это не объясняет, как десериализовать его с правильным типом, не так ли?
Показать ещё 5 комментариев
290

Мой быстрый и грязный свал JSON, который ест даты и все:

json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)
  • 5
    Это круто, но, к сожалению, я не поняла, что случилось? Кто-нибудь может объяснить этот ответ?
  • 33
    @KishorPawar: по default это функция, применяемая к объектам, которые не сериализуются. В этом случае это str , поэтому он просто конвертирует все, что не знает, в строки. Который отлично подходит для сериализации, но не так хорош при десериализации (отсюда и «быстрая и грязная»), так как все может быть строкой без предупреждения, например, функция или массив.
Показать ещё 5 комментариев
154

Я только что столкнулся с этой проблемой, и мое решение заключается в подклассе 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() Я получил один из ответов выше.

  • 14
    повышен, потому что реализация пользовательского JSONEncoder должна быть правильным способом
  • 18
    Это должно быть не только лучшим ответом, но и частью обычного кодера json. Если бы только декодирование было менее двусмысленным ..
Показать ещё 5 комментариев
105

Преобразование даты в строку

sample['somedate'] = str( datetime.utcnow() )
  • 10
    И как я могу десериализовать это в Python?
  • 54
    Проблема в том, что если у вас много объектов даты и времени, глубоко встроенных в структуру данных, или они случайные. Это не надежный метод.
Показать ещё 3 комментария
76

Для тех, кто не нуждается или хочет использовать библиотеку 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= не следует millis= в оператор if? Также, вероятно, лучше использовать str (obj) для получения формата ISO, который, я думаю, более распространен.
  • 0
    Почему вы хотите, чтобы он был с отступом? Этот фрагмент кода работает, и полученный вывод можно легко десериализовать / проанализировать из JavaScript.
Показать ещё 3 комментария
30

Вот мое решение:

# -*- 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)
  • 0
    согласна. Намного лучше, по крайней мере, вне контекста mongodb. Вы можете сделать isinstance(obj, datetime.datetime) в TypeError, добавить дополнительные типы для обработки и в конце получить str(obj) или repr(obj) . И все ваши свалки могут просто указывать на этот специализированный класс.
21

У меня есть приложение с аналогичной проблемой; мой подход состоял в том, чтобы JSONize значение datetime как список из 6 предметов (год, месяц, день, час, минуты, секунды); вы можете перейти на микросекунды в виде списка из 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"}
  • 0
    Не работает, если сэкономленное время сохраняется с помощью datetime.utcnow ()
  • 1
    Какую ошибку вы видите с datetime.utcnow ()? Это работает хорошо для меня.
15

Этот 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" }'

См. более подробную информацию и некоторые предостережения: https://stackoverflow.com/questions/455580/json-datetime-between-python-and-javascript

  • 0
    Обезьяна патч FTW. Конечно, неприятно то, что это изменяет поведение модуля json во всем приложении, что может удивить других в большом приложении, поэтому, как правило, его следует использовать с осторожностью imho.
15

Мое решение (с меньшей детализацией, я думаю):

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.
  • 0
    Я не думаю, что это хорошее решение больше. Вероятно, преобразования должны занять более привилегированное место - и также более понятное место - в вашем коде, чтобы вы знали, во что вы конвертируете, когда помещаете вещи в базу данных или что-то еще, вместо того, чтобы все делать прозрачная функция. Но я не знаю
Показать ещё 5 комментариев
9

Вот простое решение для более позднего "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" }

7

Вы должны указать собственный класс энкодера с параметром cls json.dumps. Цитировать из docs:

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

Вы должны использовать .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'}
5

Самый простой способ сделать это - изменить часть dict, которая находится в формате datetime, в isoformat. Это значение будет эффективно представлять собой строку в isoformat, с которой json в порядке.

v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()
3

Вот мое полное решение для преобразования даты и времени в 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' но не соответствующие шаблону.
  • 0
    Спасибо обновленный ответ, чтобы отразить это
3

Если вы используете результат в представлении, обязательно верните правильный ответ. Согласно API, jsonify выполняет следующие действия:

Создает ответ с представлением JSON данных аргументов с типом приложения /json.

Чтобы подражать этому поведению с помощью json.dumps, вам нужно добавить несколько дополнительных строк кода.

response = make_response(dumps(sample, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response

Вы также должны вернуть dict для полной репликации ответа 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
  • 1
    Вопрос не имеет ничего общего с колбой.
  • 2
    Вопрос о питоне. Мой ответ решает вопрос с использованием Python. ОП не сказал, должно ли решение включать или исключать определенные библиотеки. Это также полезно для любого, кто читает этот вопрос, кто хочет альтернативу pymongo .
Показать ещё 1 комментарий
2

если вы используете python3.7, то лучшим решением будет использование 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();

если вы используете python3.6 или ниже, и вы заботитесь о часовом поясе, то вы можете получить его через datetime.tzinfo, но вам придется сериализовать это поле самостоятельно; самый простой способ сделать это - добавить еще одно поле _tzinfo в сериализованном объекте;

наконец, остерегайтесь указаний во всех этих примерах;

2

Метод json.dumps может принимать необязательный параметр с именем default, который, как ожидается, будет функцией. Каждый раз, когда JSON пытается преобразовать значение, он не знает, как его преобразовать, он вызовет функцию, которую мы передали ей. Функция получит объект, о котором идет речь, и ожидается, что оно вернет представление объекта JSON.

def myconverter(o):
 if isinstance(o, datetime.datetime):
    return o.__str__()

print(json.dumps(d, default = myconverter)) 
  • 1
    Спасибо, сработало для меня!
2

Попробуйте этот пример с примером для его анализа:

#!/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()
  • 0
    А как насчет декодера?
2

Как правило, существует несколько способов сериализации datetimes, например:

  • Строка 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. Как dict, вы можете хранить метаданные, чтобы их можно было автоматически декодировать, что и делает json_tricks для вас. Он также легко редактируется для людей.

Отказ от ответственности: это сделано мной. Потому что у меня была такая же проблема.

2

Преобразуйте date в string

date = str(datetime.datetime(somedatetimehere)) 
  • 0
    Ответ jjmontes делает именно это, но без необходимости делать это явно для каждой даты ...
1

Если вы находитесь по обе стороны сообщения, вы можете использовать функции repr() и 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))

Вы не должны импортировать datetime как

from datetime import datetime

так как eval будет жаловаться. Или вы можете передать datetime в качестве параметра для eval. В любом случае это должно сработать.

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

У меня получилось такое же сообщение об ошибке при написании декоратора сериализации внутри класса с 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(),
                  ...
1

Мое решение...

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
0

На самом деле это довольно просто. Если вам нужно часто сериализовать даты, тогда работайте с ними как строки. Вы можете легко преобразовать их в качестве объектов 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'>

Как вы можете видеть, выход в обоих случаях одинаковый. Только тип отличается.

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
    Могли бы использовать объяснение кода ...
0

Мое решение состояло в том, чтобы использовать время EPOCH (это число), так как для моего использования не требовалось, чтобы конечный пользователь читал время в JSON. Было так много EASIER работать с эпохой.

0

Либо укажите как даты в mysql, так и в коде python json как String или как дату, так и дату и время. Он работал у меня, когда я преобразовал тип mysql в String.

0

Я столкнулся с такой же проблемой при экстернализации объекта модели 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
-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'> 

Ещё вопросы

Сообщество Overcoder
Наверх
Меню