Odpowiedzi:
Możesz dodać parametr „default” do json.dumps, aby to obsłużyć:
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"'
Co to jest ISO 8601 formatem .
Bardziej kompleksowa domyślna funkcja obsługi:
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))
Aktualizacja: Dodano wynik zarówno typu, jak i wartości.
Aktualizacja: obsługuje także datę
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime) else json.JSONEncoder().default(obj)
W przypadku projektów międzyjęzykowych odkryłem, że ciągi zawierające daty RfC 3339 są najlepszym sposobem. Data RfC 3339 wygląda następująco:
1985-04-12T23:20:50.52Z
Myślę, że większość formatu jest oczywista. Jedyną dość niezwykłą rzeczą może być „Z” na końcu. Oznacza GMT / UTC. Możesz również dodać przesunięcie strefy czasowej, takie jak +02: 00 dla CEST (Niemcy latem). Osobiście wolę trzymać wszystko w UTC, dopóki nie zostanie wyświetlone.
Do wyświetlania, porównań i przechowywania możesz pozostawić go w formacie ciągu we wszystkich językach. Jeśli potrzebujesz daty do obliczeń, łatwo przekonwertuj ją na natywny obiekt daty w większości języków.
Więc wygeneruj JSON w ten sposób:
json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ'))
Niestety konstruktor daty Javascript nie akceptuje ciągów RfC 3339, ale w Internecie dostępnych jest wiele parserów .
huTools.hujson próbuje poradzić sobie z najczęstszymi problemami z kodowaniem, które mogą wystąpić w kodzie Pythona, w tym z obiektami daty / daty i godziny, przy prawidłowej obsłudze stref czasowych.
datetime: datetime.isoformat (), jak i przez simplejson, który domyślnie zrzuca datetimeobiekty jako isoformatciągi znaków. Nie ma potrzeby ręcznego strftimehakowania.
datetimeobiektów na isoformatciąg. Dla mnie simplejson.dumps(datetime.now())wydajnośćTypeError: datetime.datetime(...) is not JSON serializable
json.dumps(datetime.datetime.now().isoformat())tam, gdzie dzieje się magia.
Rozpracowałem to.
Załóżmy, że masz obiekt Pytetime datetime, d , utworzony za pomocą datetime.now (). Jego wartość to:
datetime.datetime(2011, 5, 25, 13, 34, 5, 787000)
Możesz serializować to do JSON jako ciąg datetime ISO 8601:
import json
json.dumps(d.isoformat())
Przykładowy obiekt datetime zostałby serializowany jako:
'"2011-05-25T13:34:05.787000"'
Ta wartość, po otrzymaniu w warstwie JavaScript, może utworzyć obiekt Date:
var d = new Date("2011-05-25T13:34:05.787000");
Począwszy od JavaScript 1.8.5, obiekty Date mają metodę toJSON, która zwraca ciąg znaków w standardowym formacie. Aby serializować powyższy obiekt JavaScript z powrotem do JSON, polecenie powinno wyglądać następująco:
d.toJSON()
Co dałoby ci:
'2011-05-25T20:34:05.787Z'
Ten ciąg, raz otrzymany w Pythonie, można przekształcić z postaci szeregowej z powrotem do obiektu datetime:
datetime.strptime('2011-05-25T20:34:05.787Z', '%Y-%m-%dT%H:%M:%S.%fZ')
Powoduje to powstanie następującego obiektu datetime, który jest tym samym, który zacząłeś i dlatego jest poprawny:
datetime.datetime(2011, 5, 25, 20, 34, 5, 787000)
Za pomocą jsonmożna podklasować JSONEncoder i przesłonić metodę default (), aby zapewnić własne niestandardowe serializatory:
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)
Następnie możesz nazwać to tak:
>>> DateTimeJSONEncoder().encode([datetime.datetime.now()])
'["2010-06-15T14:42:28"]'
obj.isoformat(). Możesz także użyć bardziej popularnego dumps()wywołania, które pobiera inne przydatne argumenty (jak indent): simplejson.dumps (myobj, cls = JSONEncoder, ...)
Oto dość kompletne rozwiązanie do rekurencyjnego kodowania i dekodowania obiektów datetime.datetime i datetime.date przy użyciu standardowego jsonmodułu bibliotecznego . Wymaga to Python> = 2.6, ponieważ %fkod formatu w ciągu formatu datetime.datetime.strptime () jest obsługiwany tylko od tego czasu. Aby obsługiwać Python 2.5, upuść %fi usuń mikrosekundy z ciągu daty ISO przed próbą konwersji, ale stracisz precyzję mikrosekund. Aby zapewnić zgodność z ciągami dat ISO z innych źródeł, które mogą obejmować nazwę strefy czasowej lub przesunięcie UTC, konieczne może być również usunięcie niektórych części ciągu daty przed konwersją. Pełny parser dla ciągów daty ISO (i wielu innych formatów dat) znajduje się w module dateutil innej firmy .
Dekodowanie działa tylko wtedy, gdy ciągi daty ISO są wartościami w dosłownym zapisie obiektu w JavaScript lub w zagnieżdżonych strukturach w obiekcie. Ciągi daty ISO, które są elementami tablicy najwyższego poziomu, nie będą dekodowane.
Tzn. To działa:
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'}
I to także:
>>> 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)}]
Ale to nie działa zgodnie z oczekiwaniami:
>>> 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']
Oto kod:
__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"że będzie dokładnie taka, jak JSON.stringify () produkuje w javascript
Jeśli masz pewność, że tylko JavaScript będzie zużywał JSON, wolę przekazywać Dateobiekty JavaScript bezpośrednio.
ctime()Metoda na datetimeobiektach zwróci napis, że obiekt Date JavaScript może zrozumieć.
import datetime
date = datetime.datetime.today()
json = '{"mydate":new Date("%s")}' % date.ctime()
JavaScript z przyjemnością użyje tego jako literału obiektu, a ty masz wbudowany obiekt Date.
.ctime()jest BARDZO złym sposobem na przekazanie informacji o czasie, .isoformat()jest znacznie lepszy. Co .ctime()robi jest wyrzucić strefę czasową i czas letni jakby nie istnieją. Ta funkcja powinna zostać zabita.
Późno w grze ... :)
Bardzo prostym rozwiązaniem jest załatanie domyślnego modułu json. Na przykład:
import json
import datetime
json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)
Teraz możesz używać json.dumps () tak, jakby zawsze obsługiwał datetime ...
json.dumps({'created':datetime.datetime.now()})
Ma to sens, jeśli wymagasz tego rozszerzenia modułu json, aby zawsze się uruchamiało i nie chciałeś zmieniać sposobu, w jaki ty lub inni używacie serializacji json (w istniejącym kodzie lub nie).
Zauważ, że niektórzy mogą uważać łatanie bibliotek w ten sposób za złą praktykę. Należy zachować szczególną ostrożność, jeśli chcesz rozszerzyć swoją aplikację na więcej niż jeden sposób - w takim przypadku sugeruję skorzystanie z rozwiązania przez ramen lub JT i wybranie odpowiedniego rozszerzenia json w każdym przypadku.
None. Zamiast tego możesz zgłosić wyjątek.
Niewiele do dodania do odpowiedzi wiki społeczności, z wyjątkiem znacznika czasu !
JavaScript używa następującego formatu:
new Date().toJSON() // "2016-01-08T19:00:00.123Z"
Strona Pythona (dla json.dumpsobsługi zobacz inne odpowiedzi):
>>> 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'
Jeśli pominiesz to Z, frameworki takie jak kątowe nie będą mogły wyświetlać daty w lokalnej strefie czasowej przeglądarki:
> $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"
Radzę korzystać z biblioteki. Istnieje kilka dostępnych na pypi.org.
Używam tego, działa dobrze: https://pypi.python.org/pypi/asjson
Najwyraźniej „właściwy” format daty JSON (dobrze JavaScript) jest 2012-04-23T18: 25: 43.511Z - UTC i „Z”. Bez tego JavaScript będzie używał lokalnej strefy czasowej przeglądarki podczas tworzenia obiektu Date () z ciągu.
Przez „naiwny” czas (który Python nazywa czasem bez strefy czasowej i zakłada, że jest lokalny) poniżej wymusi lokalną strefę czasową, aby można ją było następnie poprawnie przekonwertować na 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
# /programming/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)
dlaczego to takie trudne
Do konwersji daty w Pythonie na JavaScript obiekt daty musi mieć określony format ISO, tj. Format ISO lub numer UNIX. Jeśli w formacie ISO brakuje pewnych informacji, możesz najpierw przekonwertować na numer uniksowy, używając najpierw Date.parse. Ponadto Date.parse działa również z React, podczas gdy nowa data może wywołać wyjątek.
Jeśli masz obiekt DateTime bez milisekund, należy wziąć pod uwagę następujące kwestie. :
var unixDate = Date.parse('2016-01-08T19:00:00')
var desiredDate = new Date(unixDate).toLocaleDateString();
Przykładowa data może być również zmienną w obiekcie result.data po wywołaniu interfejsu API.
Aby wyświetlić opcje wyświetlania daty w żądanym formacie (np. Wyświetlanie długich dni tygodnia), sprawdź dokument MDN .