2012-05-23 23 views
50

Tại sao serialization json không hoạt động cho các đối tượng datetime. Khi tôi hiểu tuần tự hóa json ý tưởng cơ bản cho bất kỳ đối tượng nào có thể gọi hàm dựng sẵn __str__ và sau đó urlencode đối tượng mà bạn nhận được dưới dạng phản hồi. Nhưng trong trường hợp của datetime tôi nhận được lỗi sauTại sao serialization json của các đối tượng datetime trong python không làm việc ra khỏi hộp cho các đối tượng datetime

TypeError: datetime.datetime(2012, 5, 23, 18, 38, 23, 37566) is not JSON serializable 

trong khi có một __str__ tức là một cách để stringifying đối tượng đã có sẵn, nhưng nó có vẻ như là một quyết định có ý thức để không làm điều đó, tại sao điều đó sẽ là trường hợp ?

+8

Bạn hiểu sai cách hoạt động của json. Nó không liên quan gì đến phương thức __str__. JSON không có kiểu ngày tháng, thời gian, do đó không thể mất mã hóa ngày giờ trong JSON một cách mất mát, mà không có một số loại logic đặc biệt nào trên đầu nhận. Do đó thư viện (logic) làm cho bạn tự làm điều đó bằng cách chuyển đổi sang một dấu thời gian Unix hoặc chuỗi ngày ISO hoặc một cái gì đó và làm cho nó rõ ràng rằng chuyển đổi là cần thiết. –

+3

@TylerEaves Đây là bất cứ điều gì nhưng hợp lý. Có thể mất mã hóa datetime thành chuỗi hoặc int và nhiều trường hợp sử dụng để chuyển đổi từ dict sang json thành dict không bao giờ rời khỏi hệ sinh thái python, nhưng mô đun json không thể xử lý trường hợp này mà không cần tùy chỉnh xử lý datetime? Có thật không?! Nhìn vào số lượng lớn các câu hỏi stackoverflow về chủ đề, tôi muốn nói rằng tôi không đơn độc trong sự hoài nghi của tôi. –

Trả lời

88

Không nó không hoạt động theo cách đó trong json module. Mô-đun cung cấp cho bạn bộ mã hóa mặc định: json.JSONEncoder. Bạn cần mở rộng quy trình này để cung cấp phương pháp default của bạn để tuần tự hóa các đối tượng. Một cái gì đó như thế này:

import json 
import datetime 
from time import mktime 

class MyEncoder(json.JSONEncoder): 

    def default(self, obj): 
     if isinstance(obj, datetime.datetime): 
      return int(mktime(obj.timetuple())) 

     return json.JSONEncoder.default(self, obj) 

print json.dumps(obj, cls=MyEncoder) 

Như những người khác một cách chính xác chỉ ra, lý do là các standard for json không xác định như thế nào thời gian cập nhật có thể được biểu.

+3

Câu trả lời hay. Cảm ơn –

+4

cách giải mã datetime này tại giao diện người dùng? tôi đang hỏi về giải mã thập phân này. – Clayton

+1

@Clayton, những gì bạn sẽ nhận được trong phản hồi JSON là dấu thời gian unix. [Câu hỏi này] (http://stackoverflow.com/questions/847185/convert-a-unix-timestamp-to-time-in-javascript) trả lời cách chuyển đổi dấu thời gian unix cho đến nay. – Vikas

10

Làm thế nào bạn muốn họ được tuần tự?

JSON không chỉ định cách xử lý ngày, do đó thư viện python json không thể đưa ra quyết định về cách đại diện cho chúng cho bạn. Điều đó hoàn toàn phụ thuộc vào cách bên kia (trình duyệt, kịch bản, bất cứ điều gì) xử lý các ngày trong JSON là tốt.

+2

Với một chuỗi tuần tự hóa mặc định không nhất thiết phải quan tâm. Bạn chỉ cần có thể vào được định dạng json và quay trở lại mà không gặp quá nhiều rắc rối. Chắc chắn thất bại về datetime hoàn toàn được đảm bảo là câu trả lời sai. –

+0

@JoshuaKolden: nhưng trong một định dạng * trao đổi * bạn cần phải quan tâm. Thư viện JSON trong Java hoặc trong một ứng dụng JavaScript muốn ngày tháng như thế nào? –

+1

Sau đó, đó là khi một trong những sẽ cần phải tùy chỉnh. Ra khỏi hộp nếu tôi chỉ đi từ python sang json đến python, không hoạt động theo mặc định trên các kiểu dữ liệu chung chỉ cần thêm phí không cần thiết. Ngoài ra, các ngôn ngữ khác cũng có chuyển đổi tiêu chuẩn thành json, vì vậy, người ta có thể bắt đầu bằng cách đó là mặc định tốt. –

8

Cách đơn giản để vá mô-đun json sao cho việc tuần tự hóa đó sẽ hỗ trợ datetime.

import json 
import datetime 

json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None) 

Sử dụng quá trình tuần tự hóa json như bạn thường làm - lần này với ngày giờ được nối tiếp là isoformat.

json.dumps({'created':datetime.datetime.now()}) 

Hệ quả là: '{ "tạo ra": "2015-08-26T14: 21: 31,853855"}'

Xem thêm chi tiết và một số chú ý tại địa chỉ: StackOverflow: JSON datetime between Python and JavaScript

+0

Giải pháp tốt nhất mà tôi đã xem. Một dòng vá. –

2

Nếu bạn muốn nhận mã hóa và giải mã các thời gian biểu mà không phải triển khai nó, bạn có thể sử dụng json_tricks, đây là trình bao bọc thêm mã hóa và giải mã cho nhiều loại phổ biến khác nhau. Chỉ cần cài đặt:

pip install json_tricks 

và sau đó nhập từ json_tricks thay vì json, ví dụ .:

from json_tricks import dumps, loads 
json = dumps({'name': 'MyName', 'birthday': datetime.datetime(1992, 5, 23, 18, 38, 23, 37566)}) 
me = loads(json) 

Disclaimer: nó được thực hiện bởi tôi. Bởi vì tôi có cùng một vấn đề.


Nếu bạn muốn tự động serialize bất cứ điều gì có thể được chuyển đổi thành chuỗi, bạn có thể làm điều đó chỉ với việc thực hiện tiêu chuẩn rất dễ dàng:

dumps(obj, default=str) 

Nhưng lưu ý rằng điều này có nhược điểm, ví dụ không ai trong số đó sẽ được deserialized mà không cần nỗ lực thêm, và đôi khi bạn chỉ không muốn serialize một cái gì đó (như một chức năng của một mảng lớn numpy) nhưng nhận được một cảnh báo thay vào đó, phương pháp này sẽ im lặng.

+0

Rất tốt khi đề cập đến mặc định = str. Sửa chữa dễ dàng nhất cho các tình huống phổ biến nhất. – JJC

Các vấn đề liên quan