2012-01-09 19 views
21

我有一個JSON對象的字符串表示形式。如何使用JSON.loads轉換爲Python日期時間對象?

dumped_dict = '{"debug": false, "created_at": "2020-08-09T11:24:20"}' 

當我用這個對象調用json.loads;

json.loads(dumped_dict) 

我得到;

{'created_at': '2020-08-09T11:24:20', 'debug': False} 

這裏沒有什麼不對。不過,我想知道是否有與json.loads上述對象轉換爲這樣的方式:不久

{'created_at': datetime.datetime(2020, 08, 09, 11, 24, 20), 'debug': False} 

,我們是否有能力爲datetime字符串轉換爲實際datetime.datetime對象,而 通話json.loads?

回答

17

我到目前爲止的解決方案:

>>> json_string = '{"last_updated": {"$gte": "Thu, 1 Mar 2012 10:00:49 UTC"}}' 
>>> dct = json.loads(json_string, object_hook=datetime_parser) 
>>> dct 
{u'last_updated': {u'$gte': datetime.datetime(2012, 3, 1, 10, 0, 49)}} 


def datetime_parser(dct): 
    for k, v in dct.items(): 
     if isinstance(v, basestring) and re.search("\ UTC", v): 
      try: 
       dct[k] = datetime.datetime.strptime(v, DATE_FORMAT) 
      except: 
       pass 
    return dct 

有關使用object_hook進一步參考:​​

在我的情況下,JSON字符串是從GET請求我的REST API的到來。該解決方案可以讓我「獲取日期權」透明,不強迫客戶和用戶爲硬編碼前綴像__date__成JSON,只要輸入字符串符合DATE_FORMAT是:

DATE_FORMAT = '%a, %d %b %Y %H:%M:%S UTC' 

正則表達式模式應該可能會進一步改進

PS:如果您想知道,json_string是一個MongoDB/PyMongo查詢。

+0

請提供比普通-1其他一些反饋/建議,所以我可以學到一些東西,至少:) – 2012-05-24 09:04:48

+0

絕對救了我。 – David 2013-03-12 12:16:14

+0

@NicolaIarocci看起來像一個真棒的解決方案,然而,這不是,這也迫使客戶硬編碼後綴「UTC」到他們的JSON? – 2014-01-20 16:49:30

1

據我所知,沒有開箱即用的解決方案。

首先,解決方案應考慮到json schema以正確區分字符串和日期時間。在某種程度上,您可以使用json模式推理器(google for json schema inferencer github)來猜測模式,然後修復真正日期時間的地方。

如果模式已知,那麼創建一個解析json並用datetime替換字符串表示的函數應該很容易。代碼的某些靈感可能從validictory產品中找到(並且json模式驗證可能也是個好主意)。

3

您提問的方式,沒有跡象表明json該字符串是日期值。這比其具有示例串JSON的文檔不同:

'{"__complex__": true, "real": 1, "imag": 2}' 

此字符串具有可用於推斷數據的類型的指示符"__complex__": true,但除非有這樣的指示器,一個字符串是隻是一個字符串,你所能做的就是對所有字符串進行正則表達式化,並決定它們是否看起來像日期。

在你的情況下,如果你的格式可用,你應該明確地使用一個模式。

+0

json的確切文檔建議使用雙下劃線名稱?例如,我曾見過\ _ \ _類型,但所有這些看起來都像使用有限的約定。 – 2012-01-09 19:49:51

+0

該示例取自'json'包文檔。 – 2012-01-13 11:45:21

14

您需要通過一個object_hook。從documentation

object_hook是將與任何對象文字解碼(一個字典)的 結果被調用的可選功能。將使用返回值 object_hook而不是字典。

像這樣:

import datetime 
import json 

def date_hook(json_dict): 
    for (key, value) in json_dict.items(): 
     try: 
      json_dict[key] = datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S") 
     except: 
      pass 
    return json_dict 

dumped_dict = '{"debug": false, "created_at": "2020-08-09T11:24:20"}' 
loaded_dict = json.loads(dumped_dict, object_hook=date_hook) 

如果你也想處理的時區,你將不得不使用的dateutil代替strptime。

+1

使用try/catch作爲控制結構並不理想。 – Maciej 2016-09-15 14:23:02

1

你可以使用正則表達式來決定你是否要到一定的字段轉換爲datetime,像這樣:

def date_hook(json_dict): 
    for (key, value) in json_dict.items(): 
     if type(value) is str and re.match('^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d*$', value): 
      json_dict[key] = datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%f") 
     elif type(value) is str and re.match('^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$', value): 
      json_dict[key] = datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S") 
     else: 
      pass 

    return json_dict 

然後你可以使用object_hook參數傳入您的呼叫json.loads引用date_hook功能():

json_data = '{"token": "faUIO/389KLDLA", "created_at": "2016-09-15T09:54:20.564"}' 
data_dictionary = json.loads(json_data, object_hook=date_hook) 
3

我會做同樣的尼古拉 2條修改建議:

  1. 使用dateutil.parser而不是datetime.datetime.strptime
  2. 明確定義我想要捕捉的異常。我一般建議不惜一切代價避免有一個空except:

或者代碼:

import dateutil.parser 

def datetime_parser(json_dict): 
    for (key, value) in json_dict.items(): 
     try: 
      json_dict[key] = dateutil.parser.parse(value) 
     except (ValueError, AttributeError): 
      pass 
    return json_dict 

str = "{...}" # Some JSON with date 
obj = json.loads(str, object_hook=datetime_parser) 
print(obj) 
+0

有趣的嘗試方向。但是在json中的每個項目上運行日期時間解析看起來有點慢。大多數項目不會是日期時間值。 – swdev 2017-04-29 06:58:07

0

由Nicola的answer啓發和適應python3(STR而不是即basestring):

import re 
from datetime import datetime 
datetime_format = "%Y-%m-%dT%H:%M:%S" 
datetime_format_regex = re.compile(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$') 


def datetime_parser(dct): 
    for k, v in dct.items(): 
     if isinstance(v, str) and datetime_format_regex.match(v): 
      dct[k] = datetime.strptime(v, datetime_format) 
    return dct 

這避免了使用try/except機制。 在OP的測試代碼:

>>> import json 
>>> json_string = '{"debug": false, "created_at": "2020-08-09T11:24:20"}' 
>>> json.loads(json_string, object_hook=datetime_parser) 
{'created_at': datetime.datetime(2020, 8, 9, 11, 24, 20), 'debug': False} 

正則表達式和datetime_format變量可以被容易地調整以適應其他圖案,例如沒有T在中間。

要轉換保存在isoformat(因此存儲有微秒)的字符串返回日期時間對象,請參閱this question

相關問題