Tôi muốn gửi một đối tượng datetime.datetime ở dạng tuần tự từ Python bằng JSON và khử tuần tự hóa trong JavaScript bằng JSON. Cách tốt nhất để làm việc này là gì?
Tôi muốn gửi một đối tượng datetime.datetime ở dạng tuần tự từ Python bằng JSON và khử tuần tự hóa trong JavaScript bằng JSON. Cách tốt nhất để làm việc này là gì?
Câu trả lời:
Bạn có thể thêm tham số 'mặc định' vào json.dumps để xử lý việc nà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"'
Đó là định dạng ISO 8601 .
Một hàm xử lý mặc định toàn diện hơn:
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))
Cập nhật: Đã thêm đầu ra của loại cũng như giá trị.
Cập nhật: Cũng xử lý ngày
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime) else json.JSONEncoder().default(obj)
Đối với các dự án đa ngôn ngữ, tôi phát hiện ra rằng các chuỗi chứa RfC 3339 ngày là cách tốt nhất để đi. Một ngày RfC 3339 trông như thế này:
1985-04-12T23:20:50.52Z
Tôi nghĩ rằng hầu hết các định dạng là rõ ràng. Điều duy nhất hơi bất thường có thể là "Z" ở cuối. Nó là viết tắt của GMT / UTC. Bạn cũng có thể thêm độ lệch múi giờ như +02: 00 cho CEST (Đức vào mùa hè). Cá nhân tôi thích giữ mọi thứ trong UTC cho đến khi nó được hiển thị.
Để hiển thị, so sánh và lưu trữ, bạn có thể để nó ở định dạng chuỗi trên tất cả các ngôn ngữ. Nếu bạn cần ngày để tính toán dễ dàng chuyển đổi nó trở lại một đối tượng ngày gốc trong hầu hết các ngôn ngữ.
Vì vậy, tạo JSON như thế này:
json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ'))
Thật không may, hàm tạo ngày của Javascript không chấp nhận chuỗi RfC 3339 nhưng có nhiều trình phân tích cú pháp có sẵn trên Internet.
huTools.hujson cố gắng xử lý các vấn đề mã hóa phổ biến nhất mà bạn có thể gặp phải trong mã Python bao gồm các đối tượng ngày / thời gian trong khi xử lý các múi giờ chính xác.
datetime
: datetime.isoformat () và by simplejson
, sẽ kết xuất datetime
các đối tượng dưới dạng isoformat
chuỗi theo mặc định. Không cần strftime
hack thủ công.
datetime
các đối tượng sang isoformat
chuỗi. Đối với tôi, simplejson.dumps(datetime.now())
sản lượngTypeError: datetime.datetime(...) is not JSON serializable
json.dumps(datetime.datetime.now().isoformat())
là nơi phép màu xảy ra.
Tôi đã làm việc đó.
Giả sử bạn có một đối tượng datetime Python, d , được tạo bằng datetime.now (). Giá trị của nó là:
datetime.datetime(2011, 5, 25, 13, 34, 5, 787000)
Bạn có thể tuần tự hóa nó thành JSON dưới dạng chuỗi thời gian ISO 8601:
import json
json.dumps(d.isoformat())
Đối tượng datetime ví dụ sẽ được tuần tự hóa thành:
'"2011-05-25T13:34:05.787000"'
Giá trị này, một khi nhận được trong lớp Javascript, có thể xây dựng một đối tượng Ngày:
var d = new Date("2011-05-25T13:34:05.787000");
Kể từ Javascript 1.8.5, các đối tượng Date có phương thức toJSON, trả về một chuỗi ở định dạng chuẩn. Do đó, để tuần tự hóa đối tượng Javascript ở trên trở lại JSON, lệnh sẽ là:
d.toJSON()
Mà sẽ cung cấp cho bạn:
'2011-05-25T20:34:05.787Z'
Chuỗi này, một khi đã nhận được trong Python, có thể được giải tuần tự trở lại đối tượng datetime:
datetime.strptime('2011-05-25T20:34:05.787Z', '%Y-%m-%dT%H:%M:%S.%fZ')
Điều này dẫn đến đối tượng datetime sau, giống với đối tượng bạn đã bắt đầu và do đó chính xác:
datetime.datetime(2011, 5, 25, 20, 34, 5, 787000)
Khi sử dụng json
, bạn có thể phân lớp JSONEncoder và ghi đè phương thức () mặc định để cung cấp các trình tuần tự tùy chỉnh của riêng bạn:
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)
Sau đó, bạn có thể gọi nó như thế này:
>>> DateTimeJSONEncoder().encode([datetime.datetime.now()])
'["2010-06-15T14:42:28"]'
obj.isoformat()
. Bạn cũng có thể sử dụng dumps()
cuộc gọi phổ biến hơn , trong đó có các đối số hữu ích khác (như indent
): simplejson.dumps (myobj, cls = JSONEncoder, ...)
Đây là một giải pháp khá hoàn chỉnh để mã hóa và giải mã đệ quy các đối tượng datetime.datetime và datetime.date bằng json
mô-đun thư viện chuẩn . Điều này cần Python> = 2.6 vì %f
mã định dạng trong chuỗi định dạng datetime.datetime.strptime () chỉ được hỗ trợ kể từ đó. Đối với hỗ trợ Python 2.5, hãy bỏ %f
và tách các micro giây khỏi chuỗi ngày ISO trước khi thử chuyển đổi nó, nhưng dĩ nhiên, bạn sẽ mất độ chính xác của micro giây. Để có khả năng tương tác với các chuỗi ngày ISO từ các nguồn khác, có thể bao gồm tên múi giờ hoặc bù UTC, bạn cũng có thể cần phải loại bỏ một số phần của chuỗi ngày trước khi chuyển đổi. Để biết trình phân tích cú pháp hoàn chỉnh cho chuỗi ngày ISO (và nhiều định dạng ngày khác), hãy xem mô-đun dateutil của bên thứ ba .
Giải mã chỉ hoạt động khi các chuỗi ngày ISO là các giá trị trong ký hiệu đối tượng bằng chữ JavaScript hoặc trong các cấu trúc lồng nhau trong một đối tượng. Chuỗi ngày ISO, là các mục của mảng cấp cao nhất sẽ không được giải mã.
Tức là công việc này:
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'}
Và điều này cũng vậy:
>>> 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)}]
Nhưng điều này không hoạt động như mong đợi:
>>> 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']
Đây là mã:
__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"
vậy, nó sẽ giống hệt như những gì JSON.opesify () tạo ra trong javascript
Nếu bạn chắc chắn rằng chỉ Javascript sẽ tiêu thụ JSON, tôi thích vượt qua Javascript Date
trực tiếp các đối tượng .
Các ctime()
phương pháp trên datetime
đối tượng sẽ trả về một chuỗi Javascript ngày đối tượng có thể hiểu được.
import datetime
date = datetime.datetime.today()
json = '{"mydate":new Date("%s")}' % date.ctime()
Javascript sẽ vui vẻ sử dụng nó như một đối tượng theo nghĩa đen và bạn đã xây dựng đối tượng Date của mình ngay trong đó.
.ctime()
là một cách RẤT xấu để truyền thông tin thời gian, .isoformat()
tốt hơn nhiều. Điều gì .ctime()
làm là vứt bỏ múi giờ và tiết kiệm ánh sáng ban ngày như chúng không tồn tại. Chức năng đó nên bị giết.
Cuối trò chơi ... :)
Một giải pháp rất đơn giản là vá mặc định mô-đun json. Ví dụ:
import json
import datetime
json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)
Bây giờ, bạn có thể sử dụng json.dumps () như thể nó luôn hỗ trợ datetime ...
json.dumps({'created':datetime.datetime.now()})
Điều này có ý nghĩa nếu bạn yêu cầu tiện ích mở rộng này cho mô-đun json luôn luôn khởi động và muốn không thay đổi cách bạn hoặc người khác sử dụng tuần tự hóa json (trong mã hiện có hoặc không).
Lưu ý rằng một số có thể coi việc vá các thư viện theo cách đó là thực tiễn xấu. Cần đặc biệt cẩn thận trong trường hợp bạn có thể muốn mở rộng ứng dụng của mình theo nhiều cách - là một trường hợp như vậy, tôi đề nghị sử dụng giải pháp bằng ramen hoặc JT và chọn phần mở rộng json thích hợp trong từng trường hợp.
None
. Bạn có thể muốn ném một ngoại lệ thay thế.
Không có nhiều để thêm vào câu trả lời wiki cộng đồng, ngoại trừ dấu thời gian !
Javascript sử dụng định dạng sau:
new Date().toJSON() // "2016-01-08T19:00:00.123Z"
Phía Python (đối với json.dumps
trình xử lý, xem các câu trả lời khác):
>>> 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'
Nếu bạn bỏ Z đó ra, các khung giao diện như góc không thể hiển thị ngày theo múi giờ của trình duyệt cục bộ:
> $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"
Lời khuyên của tôi là sử dụng một thư viện. Có một số có sẵn tại pypi.org.
Tôi sử dụng cái này, nó hoạt động tốt: https://pypi.python.org/pypi/asjson
Rõ ràng Định dạng ngày của JSON bên phải JSON JSON (cũng JavaScript) là 2012-04-23T18: 25: 43.511Z - UTC và "Z". Nếu không có JavaScript này sẽ sử dụng múi giờ cục bộ của trình duyệt web khi tạo đối tượng Date () từ chuỗi.
Đối với thời gian "ngây thơ" (cái mà Python gọi là thời gian không có múi giờ và giả định này là cục bộ), bên dưới sẽ buộc múi giờ cục bộ để sau đó nó có thể được chuyển đổi chính xác thành 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)
tại sao nó lại khó thế này.
Để chuyển đổi ngày Python sang JavaScript, đối tượng ngày cần phải ở định dạng ISO cụ thể, tức là định dạng ISO hoặc số UNIX. Nếu định dạng ISO thiếu một số thông tin, thì bạn có thể chuyển đổi sang số Unix bằng Date.parse trước. Hơn nữa, Date.parse cũng hoạt động với React trong khi Date mới có thể kích hoạt một ngoại lệ.
Trong trường hợp bạn có một đối tượng DateTime không có mili giây, những điều sau đây cần được xem xét. :
var unixDate = Date.parse('2016-01-08T19:00:00')
var desiredDate = new Date(unixDate).toLocaleDateString();
Ngày ví dụ có thể là một biến trong đối tượng result.data sau lệnh gọi API.
Để biết các tùy chọn hiển thị ngày ở định dạng mong muốn (ví dụ: để hiển thị các ngày trong tuần dài), hãy xem tài liệu MDN .