我有一个JSON对象的字符串表示。
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?
答案 0 :(得分:21)
到目前为止我的解决方案:
>>> 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 encoder and decoder
在我的例子中,json字符串来自对我的REST API的GET请求。此解决方案允许我透明地“正确获取日期”,而不会强制客户端和用户将__date__
等硬编码前缀添加到JSON中,只要输入字符串符合DATE_FORMAT即:
DATE_FORMAT = '%a, %d %b %Y %H:%M:%S UTC'
正则表达式模式应该进一步细化
PS:如果您想知道,json_string是MongoDB / PyMongo查询。
答案 1 :(得分:16)
您需要传递 object_hook 。来自documentation:
object_hook 是一个可选函数,将使用 任何对象文字解码的结果(一个字典)。的返回值 将使用object_hook而不是dict。
像这样:
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。
答案 2 :(得分:3)
提出问题的方式,没有迹象表明json字符串是日期值。这与具有示例字符串的json的文档不同:
'{"__complex__": true, "real": 1, "imag": 2}'
此字符串有一个指示符"__complex__": true
,可用于推断数据的类型,但除非有这样的指示符,否则字符串只是一个字符串,你所能做的只是以你的方式正则表达式通过所有字符串并决定它们是否看起来像日期。
在您的情况下,如果您的格式可用,则绝对应该使用架构。
答案 3 :(得分:3)
我会像 Nicola 一样建议进行2次更改:
dateutil.parser
代替datetime.datetime.strptime
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)
答案 4 :(得分:2)
您可以使用正则表达式来确定是否要将某个字段转换为日期时间,如下所示:
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
然后你可以在调用json.loads()时使用object_hook参数引用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)
答案 5 :(得分:1)
据我所知,没有开箱即用的解决方案。
首先,解决方案应该考虑json schema来正确区分字符串和日期时间。在某种程度上,您可以使用json架构推理器(google for json schema inferencer github)猜测架构,然后修复真正的日期时间。
如果模式已知,那么创建一个函数应该非常容易,该函数解析json并用datetime替换字符串表示。可以从validictory产品中找到代码的一些灵感(并且json模式验证也可能是个好主意)。
答案 6 :(得分:0)
受尼古拉的answer启发并改编为python3(str而不是basetring):
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。
答案 7 :(得分:0)
该方法以日期时间格式实现递归字符串搜索
import json
from dateutil.parser import parse
def datetime_parser(value):
if isinstance(value, dict):
for k, v in value.items():
value[k] = datetime_parser(v)
elif isinstance(value, list):
for index, row in enumerate(value):
value[index] = datetime_parser(row)
elif isinstance(value, str) and value:
try:
value = parse(value)
except (ValueError, AttributeError):
pass
return value
json_to_dict = json.loads(YOUR_JSON_STRING, object_hook=datetime_parser)