JSON kullanarak Python serileştirilmiş biçimde datetime.datetime nesnesini göndermek ve JSON kullanarak JavaScript serisini kaldırmak istiyorum . Bunu yapmanın en iyi yolu nedir?
JSON kullanarak Python serileştirilmiş biçimde datetime.datetime nesnesini göndermek ve JSON kullanarak JavaScript serisini kaldırmak istiyorum . Bunu yapmanın en iyi yolu nedir?
Yanıtlar:
Bunu yapmak için json.dumps dosyasına 'default' parametresini ekleyebilirsiniz:
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"'
Hangisi ISO 8601 biçimi.
Daha kapsamlı bir varsayılan işleyici işlevi:
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))
Güncelleme: Türün yanı sıra değer çıktısı eklendi.
Güncelleme: Ayrıca tarih işlemek
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime) else json.JSONEncoder().default(obj)
Diller arası projeler için, RfC 3339 tarihleri içeren dizelerin en iyi yol olduğunu öğrendim . RfC 3339 tarihi şöyle görünür:
1985-04-12T23:20:50.52Z
Sanırım formatın çoğu belli. Sadece alışılmadık bir şey sonunda "Z" olabilir. GMT / UTC anlamına gelir. Ayrıca CEST (yaz aylarında Almanya) için +02: 00 gibi bir saat dilimi uzaklığı ekleyebilirsiniz. Kişisel olarak görüntülenene kadar her şeyi UTC'de tutmayı tercih ederim.
Görüntüleme, karşılaştırma ve depolama için tüm dillerde dize biçiminde bırakabilirsiniz. Hesaplamalar için tarihe ihtiyacınız varsa, çoğu dilde bir yerel tarih nesnesine geri dönüştürmek kolaydır.
JSON'u şöyle oluşturun:
json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ'))
Ne yazık ki, Javascript'in Tarih yapıcısı RfC 3339 dizelerini kabul etmiyor, ancak internette birçok ayrıştırıcı var.
huTools.hujson , zaman dilimleri doğru işlenirken tarih / datetime nesneleri de dahil olmak üzere Python kodunda karşılaşabileceğiniz en yaygın kodlama sorunlarını ele almaya çalışır.
datetime
: datetime.isoformat () tarafından hem de varsayılan olarak nesneleri dize olarak simplejson
atacak olan yerel olarak desteklenir . Manuel saldırıya gerek yok . datetime
isoformat
strftime
datetime
Nesnelerden isoformat
dizgeye otomatik dönüşüm almıyorum . Benim için, simplejson.dumps(datetime.now())
verimTypeError: datetime.datetime(...) is not JSON serializable
json.dumps(datetime.datetime.now().isoformat())
sihrin gerçekleştiği yerdir.
Ben hallettim.
Diyelim ki bir Python datetime nesnesi var diyelim d DateTime.Now ile oluşturulan, (). Değeri:
datetime.datetime(2011, 5, 25, 13, 34, 5, 787000)
JSON'a ISO 8601 datetime dizesi olarak serileştirebilirsiniz:
import json
json.dumps(d.isoformat())
Örnek datetime nesnesi şu şekilde serileştirilir:
'"2011-05-25T13:34:05.787000"'
Bu değer, bir kez Javascript katmanında alındığında, bir Date nesnesi oluşturabilir:
var d = new Date("2011-05-25T13:34:05.787000");
Javascript 1.8.5 itibariyle, Date nesnelerinin bir toJSON yöntemi vardır ve bu da standart biçimde bir dize döndürür. Yukarıdaki Javascript nesnesini tekrar JSON'a serileştirmek için komut şu şekilde olur:
d.toJSON()
Hangi size verecek:
'2011-05-25T20:34:05.787Z'
Python'da bir kez alınan bu dize, bir datetime nesnesine geri serileştirilebilir:
datetime.strptime('2011-05-25T20:34:05.787Z', '%Y-%m-%dT%H:%M:%S.%fZ')
Bu, başlangıç tarihiyle aynı olan ve bu nedenle doğru olan aşağıdaki datetime nesnesiyle sonuçlanır:
datetime.datetime(2011, 5, 25, 20, 34, 5, 787000)
Kullanarak json
, kendi özel serileştiricilerinizi sağlamak için JSONEncoder öğesini alt sınıflandırabilir ve varsayılan () yöntemini geçersiz kılabilirsiniz:
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)
Sonra şöyle diyebilirsiniz:
>>> DateTimeJSONEncoder().encode([datetime.datetime.now()])
'["2010-06-15T14:42:28"]'
obj.isoformat()
. dumps()
Diğer yararlı argümanları da içeren daha yaygın çağrıyı da kullanabilirsiniz (like indent
): simplejson.dumps (myobj, cls = JSONEncoder, ...)
Standart kütüphane json
modülünü kullanarak datetime.datetime ve datetime.date nesnelerini özyinelemeli olarak kodlamak ve çözmek için oldukça eksiksiz bir çözüm . %f
Datetime.datetime.strptime () biçim dizesindeki biçim kodu yalnızca o zamandan beri desteklendiğinden, bu Python> = 2.6 gerektirir . Python 2.5 desteği için,%f
dönüştürmeye çalışmadan önce ISO tarih dizesinden mikrosaniye ve soyun, ancak elbette mikrosaniye hassasiyetini kaybedersiniz. Bir saat dilimi adı veya UTC ofseti içerebilen diğer kaynaklardan alınan ISO tarih dizeleriyle birlikte çalışabilirlik için, dönüşümden önce tarih dizesinin bazı bölümlerini çıkarmanız gerekebilir. ISO tarih dizeleri (ve diğer birçok tarih biçimi) için tam bir ayrıştırıcı için üçüncü taraf dateutil modülüne bakın.
Kod çözme yalnızca ISO tarih dizeleri bir JavaScript değişmez nesne gösterimindeki veya bir nesne içindeki iç içe yapılardaki değerler olduğunda çalışır. Üst düzey bir dizinin öğeleri olan ISO tarih dizeleri değil deşifre edilmesi.
Yani bu işe yarıyor:
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'}
Ve bu da:
>>> 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)}]
Ancak bu beklendiği gibi çalışmaz:
>>> 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']
İşte 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"
tam olarak JSON.stringify () JavaScript ürettiğinin gibi olacak
Yalnızca Javascript'in JSON'u tüketeceğinden eminseniz, Date
doğrudan Javascript nesnelerini iletmeyi tercih ederim .
ctime()
Üzerinde yöntem datetime
nesneleri JavaScript tarihi nesne anlayabileceği bir dize döndürür.
import datetime
date = datetime.datetime.today()
json = '{"mydate":new Date("%s")}' % date.ctime()
Javascript bunu bir nesne değişmezi olarak mutlu bir şekilde kullanacak ve Date nesnenizi tam olarak yerleşik hale getireceksiniz.
.ctime()
zaman bilgi geçmek için ÇOK kötü bir yoldur .isoformat()
, çok daha iyidir. Ne .ctime()
varmış gibi, saat dilimi ve yaz saatini atmak. Bu işlev öldürülmeli.
Oyunun sonlarında ... :)
Çok basit bir çözüm, json modülü varsayılanını düzeltmektir. Örneğin:
import json
import datetime
json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)
Artık json.dumps () yöntemini her zaman datetime özelliğini destekliyormuş gibi kullanabilirsiniz ...
json.dumps({'created':datetime.datetime.now()})
Bu, json modülünün bu uzantısının her zaman devreye girmesini ve sizin veya başkalarının json serileştirmesini kullanma şeklini (mevcut kodda ya da değil) değiştirmek istemiyorsanız mantıklıdır.
Bazılarının kütüphaneleri bu şekilde yamalamayı kötü uygulama olarak değerlendirebileceğini unutmayın. Başvurunuzu birden fazla şekilde genişletmek istemeniz durumunda özel dikkat gösterilmelidir - böyle bir durumdur, çözümü ramen veya JT ile kullanmanızı ve her durumda uygun json uzantısını seçmenizi öneririm.
None
. Bunun yerine bir istisna atmak isteyebilirsiniz.
Zaman damgası hariç, topluluk wiki yanıtına eklenecek çok fazla şey yok !
Javascript aşağıdaki biçimi kullanır:
new Date().toJSON() // "2016-01-08T19:00:00.123Z"
Python tarafı ( json.dumps
işleyici için diğer cevaplara bakın):
>>> 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'
Bu Z'yi dışarıda bırakırsanız, açısal gibi ön uç çerçeveleri tarihi tarayıcı-yerel saat diliminde görüntüleyemez:
> $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"
Benim tavsiyem kütüphane kullanmak. Pypi.org'da birkaç tane var.
Bunu kullanıyorum, iyi çalışıyor: https://pypi.python.org/pypi/asjson
Görünüşe göre "doğru" JSON (iyi JavaScript) tarih biçimi 2012-04-23T18: 25: 43.511Z - UTC ve "Z". Bu JavaScript olmadan, dizeden bir Date () nesnesi oluştururken web tarayıcısının yerel saat dilimini kullanır.
"Saf" bir süre için (Python'un saat dilimi olmadan bir saati çağırdığı ve bunun yerel olduğu varsayıldığı için) aşağıdakiler yerel saat dilimini zorlayarak UTC'ye dönüştürülebilir:
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)
bu neden bu kadar zor.
Python'dan JavaScript'e tarih dönüşümü için, tarih nesnesinin belirli ISO biçiminde, yani ISO biçiminde veya UNIX numarası olması gerekir. ISO biçiminde bazı bilgiler yoksa, önce Date.parse ile Unix numarasına dönüştürebilirsiniz. Ayrıca Date.parse, React ile de çalışır, ancak yeni Date bir istisnayı tetikleyebilir.
Milisaniye olmadan bir DateTime nesneniz varsa, aşağıdakilerin dikkate alınması gerekir. :
var unixDate = Date.parse('2016-01-08T19:00:00')
var desiredDate = new Date(unixDate).toLocaleDateString();
Örnek tarih, bir API çağrısından sonra sonuç.data nesnesinde eşit bir değişken olabilir.
Tarihi istenen biçimde görüntüleme seçenekleri (örneğin, uzun hafta içi günleri görüntülemek için) MDN belgesine bakın .