Eu tenho um ditado básico da seguinte maneira:
sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere
Quando tento fazer jsonify(sample)
, recebo:
TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable
O que posso fazer para que meu exemplo de dicionário possa superar o erro acima?
Nota: Embora possa não ser relevante, os dicionários são gerados a partir da recuperação de registros fora de mongodb
onde quando eu imprimo str(sample['somedate'])
, a saída é 2012-08-08 21:46:24.862000
.
Respostas:
Atualizado para 2018
A resposta original acomodava a maneira como os campos de "data" do MongoDB eram representados como:
{"$date": 1506816000000}
Se você deseja uma solução Python genérica para serializar
datetime
para json, consulte a resposta do @jjmontes para obter uma solução rápida que não requer dependências.Como você está usando o mongoengine (por comentários) e o pymongo é uma dependência, o pymongo possui utilitários internos para ajudar na serialização do json:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html
Exemplo de uso (serialização):
Exemplo de uso (desserialização):
Django
O Django fornece um
DjangoJSONEncoder
serializador nativo que lida com esse tipo de maneira adequada.Consulte https://docs.djangoproject.com/en/dev/topics/serialization/#djangojsonencoder
Uma diferença que eu notei entre
DjangoJSONEncoder
e usando um costumedefault
como este:O Django retira um pouco dos dados:
Portanto, talvez seja necessário ter cuidado com isso em alguns casos.
fonte
Django MongoDB
. Com o posterior, você tentaria permanecer no ORM do django para manter o estado agnóstico do back-end. Mas, às vezes, você não pode fazer o que precisa na abstração, então você desce uma camada. Nesse caso, isso não está relacionado ao seu problema, pois você está apenas usando métodos utilitários para acompanhar o formato JSON.Meu dump JSON rápido e sujo que come datas e tudo:
fonte
default
é uma função aplicada a objetos que não são serializáveis. Nesse caso, éstr
, portanto, apenas converte tudo o que não sabe em seqüências de caracteres. O que é ótimo para serialização, mas não é tão bom ao desserializar (daí o "rápido e sujo") quanto qualquer coisa pode ter sido digitada sem aviso, por exemplo, uma função ou matriz numpy.json.dumps({():1,type(None):2},default=str)
aumentosTypeError
, não pode ter tipo ou tupla.Com base em outras respostas, uma solução simples baseada em um serializador específico que apenas converte
datetime.datetime
edatetime.date
objetos em seqüências de caracteres.Como visto, o código apenas verifica se o objeto é da classe
datetime.datetime
oudatetime.date
, e depois usa.isoformat()
para produzir uma versão serializada, de acordo com o formato ISO 8601, AAAA-MM-DDTHH: MM: SS (que é facilmente decodificado por JavaScript ) Se representações serializadas mais complexas forem buscadas, outro código poderá ser usado em vez de str () (consulte outras respostas a esta pergunta para exemplos). O código termina levantando uma exceção, para lidar com o caso em que é chamado com um tipo não serializável.Essa função json_serial pode ser usada da seguinte maneira:
Os detalhes sobre como o parâmetro padrão do json.dumps funciona podem ser encontrados na Seção Uso Básico da documentação do módulo json .
fonte
01:00:00+01:00
e02:00:00+00:00
que não deve ser a mesma, dependendo do contexto. Eles se referem ao mesmo ponto no tempo, é claro, mas o deslocamento pode ser um aspecto relevante do valor.Acabei de encontrar esse problema e minha solução é subclassificar
json.JSONEncoder
:Na sua ligação, faça algo como:
json.dumps(yourobj, cls=DateTimeEncoder)
O.isoformat()
que recebi de uma das respostas acima.fonte
DjangoJSONEncoder
. docs.djangoproject.com/en/dev/topics/serialization/…return super(DateTimeEncoder, self).default(o)
return super().default(o)
Converter a data em uma sequência
fonte
oDate = datetime.datetime.strptime(sDate, '%Y-%m-%d %H:%M:%S.%f')
. Formatos obtidos em: docs.python.org/2/library/datetime.html.now()
usa a hora local, sem indicar isso. Pelo menos.utcnow()
deveria ser utilizada (e, em seguida, um ou Z 0000 anexa)At least .utcnow() should be used
Não exatamente,datetime.now(timezone.utc)
é recomendado, consulte o aviso em: docs.python.org/3.8/library/… .Para outras pessoas que não precisam ou desejam usar a biblioteca pymongo para isso, é possível obter facilmente a conversão JSON de data e hora com este pequeno trecho:
Em seguida, use-o assim:
resultado:
fonte
millis=
ser recuado dentro da instrução if? Provavelmente também é melhor usar str (obj) para obter o formato ISO que eu acho mais comum.datetime.now()
retorna a hora local (como um objeto de data e hora ingênuo), mas seu código assume queobj
está no UTC se não estiver ciente do fuso horário. Use emdatetime.utcnow()
vez disso.Aqui está a minha solução:
Então você pode usá-lo assim:
fonte
isinstance(obj, datetime.datetime)
dentro do TypeError, adicionar mais tipos para manipular e finalizar com ostr(obj)
ourepr(obj)
. E todos os seus despejos podem apenas apontar para essa classe especializada.Eu tenho um aplicativo com um problema semelhante; minha abordagem foi JSONize o valor datetime como uma lista de 6 itens (ano, mês, dia, hora, minutos, segundos); você poderia ir para microssegundos como uma lista de 7 itens, mas eu não precisava:
produz:
fonte
Minha solução (com menos verbosidade, eu acho):
Em seguida, use em
jsondumps
vez dejson.dumps
. Irá imprimir:Eu quero, mais tarde você pode adicionar outros casos especiais a isso com um simples toque no
default
método. Exemplo:fonte
Este Q repete uma e outra vez - uma maneira simples de corrigir o módulo json de forma que a serialização suporte a data e hora.
Em seguida, use a serialização json como sempre - desta vez com o datetime sendo serializado como isoformato.
Resultando em: '{"created": "26-08-2015T14: 21: 31.853855"}'
Veja mais detalhes e algumas palavras de cautela em: StackOverflow: JSON datetime entre Python e JavaScript
fonte
O método json.dumps pode aceitar um parâmetro opcional chamado default, que se espera seja uma função. Toda vez que o JSON tenta converter um valor, ele não sabe como convertê-lo, chamará a função que passamos para ele. A função receberá o objeto em questão e espera-se retornar a representação JSON do objeto.
fonte
se você estiver usando python3.7, a melhor solução será usar
datetime.isoformat()
anddatetime.fromisoformat()
; eles trabalham comdatetime
objetos ingênuos e conscientes :resultado:
se você estiver usando python3.6 ou abaixo, e você só se preocupam com o valor de tempo (não o fuso horário), então você pode usar
datetime.timestamp()
edatetime.fromtimestamp()
, em vez;se você estiver usando python3.6 ou abaixo, e se importa com o fuso horário, pode obtê-lo via
datetime.tzinfo
, mas é necessário serializar esse campo sozinho; a maneira mais fácil de fazer isso é adicionar outro campo_tzinfo
no objeto serializado;finalmente, cuidado com as precisões em todos esses exemplos;
fonte
Você deve usar o
.strftime()
método no.datetime.now()
método para torná-lo como um método serializável .Aqui está um exemplo:
Resultado:
fonte
Aqui está uma solução simples para superar o problema "datetime não JSON serializable".
Saída: -> {"date": "2015-12-16T04: 48: 20.024609"}
fonte
Você tem que fornecer uma classe codificador personalizado com o
cls
parâmetro dejson.dumps
. Para citar os documentos :Isso usa números complexos como o exemplo, mas você pode facilmente criar uma classe para codificar datas (exceto que eu acho que o JSON é um pouco confuso sobre datas)
fonte
A maneira mais simples de fazer isso é alterar a parte do ditado que está no formato de data e hora para isoformato. Esse valor será efetivamente uma string em isoformat com a qual json está bem.
fonte
Na verdade, é bastante simples. Se você precisar serializar datas com frequência, trabalhe com elas como seqüências de caracteres. Você pode convertê-los facilmente novamente como objetos de data e hora, se necessário.
Se você precisar trabalhar principalmente como objetos de data e hora, converta-os como seqüências de caracteres antes de serializar.
Como você pode ver, a saída é a mesma nos dois casos. Somente o tipo é diferente.
fonte
Se você estiver usando o resultado em uma exibição, certifique-se de retornar uma resposta adequada. De acordo com a API, o jsonify faz o seguinte:
Para imitar esse comportamento com o json.dumps, você precisa adicionar algumas linhas extras de código.
Você também deve retornar um dict para replicar completamente a resposta do jsonify. Portanto, o arquivo inteiro ficará assim
fonte
pymongo
.Tente este com um exemplo para analisá-lo:
fonte
Minha solução ...
Ok, agora alguns testes.
fonte
Aqui está minha solução completa para converter datetime em JSON e vice-versa.
Resultado
Arquivo JSON
Isso me permitiu importar e exportar objetos de strings, ints, floats e datetime. Não deve ser difícil estender para outros tipos.
fonte
TypeError: 'str' does not support the buffer interface
. É por causa do'wb'
modo aberto, deve ser'w'
. Ele também é deserializado quando temos dados semelhantes ao'0000891618-05-000338'
padrão de data semelhante, mas sem correspondência.Converta
date
emstring
fonte
Geralmente, existem várias maneiras de serializar datetime, como:
Se você estiver de acordo com a última maneira, o pacote json_tricks manipula datas, horários e horários, incluindo fusos horários.
que dá:
Então, tudo que você precisa fazer é
e importe de em
json_tricks
vez dejson
.A vantagem de não armazená-lo como uma única string, int ou float ocorre ao decodificar: se você encontrar apenas uma string ou especialmente int ou float, precisará saber algo sobre os dados para saber se é uma data e hora. Como regra, você pode armazenar os metadados para que possam ser decodificados automaticamente, e é
json_tricks
isso que faz com você. Também é facilmente editável para humanos.Disclaimer: é feito por mim. Porque eu tive o mesmo problema.
fonte
Recebi a mesma mensagem de erro ao escrever o decorador de serialização dentro de uma classe com sqlalchemy. Então, em vez de:
Simplesmente peguei emprestado a ideia de jgbarah de usar isoformat () e acrescentei o valor original com isoformat (), para que agora se pareça com:
fonte
Uma solução rápida, se você quiser sua própria formatação
fonte
Se você estiver nos dois lados da comunicação, poderá usar as funções repr () e eval () junto com json.
Você não deve importar data e hora como
desde eval vai reclamar. Ou você pode passar datetime como um parâmetro para avaliar. De qualquer forma, isso deve funcionar.
fonte
Eu encontrei o mesmo problema ao externalizar o objeto de modelo django para despejar como JSON. Aqui está como você pode resolvê-lo.
fonte
Uso do utilitário acima:
fonte
Esse superjson da biblioteca pode fazer isso. E você pode facilmente personalizar o serializador json para seu próprio objeto Python, seguindo estas instruções https://superjson.readthedocs.io/index.html#extend .
O conceito geral é:
seu código precisa localizar o método correto de serialização / desserialização com base no objeto python. Normalmente, o nome completo da classe é um bom identificador.
E então seu método ser / deser deve ser capaz de transformar seu objeto em um objeto serializável Json normal, uma combinação de tipo python genérico, dict, lista, string, int, float. E implemente seu método deser inversamente.
fonte
Posso não estar 100% correto, mas esta é a maneira mais simples de serializar
fonte