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}
まもなく、json.loadsを呼び出すときに、datetime文字列を実際のdatetime.datetimeオブジェクトに変換できますか?
これまでの私の解決策:
>>> 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エンコーダーおよびデコーダー
私の場合、json文字列はGETリクエストからmy REST APIに送信されます。このソリューションを使用すると、クライアントとユーザーに__date__
入力文字列がDATE_FORMATに準拠している限り、JSONに次のようになります。
DATE_FORMAT = '%a, %d %b %Y %H:%M:%S UTC'
正規表現パターンはおそらくさらに洗練されるべきです
PS:ご参考までに、json_stringはMongoDB/PyMongoクエリです。
object_hookを渡す必要があります。 ドキュメント から:
object_hookは、デコードされたオブジェクトリテラル(dict)の結果で呼び出されるオプションの関数です。 dictの代わりに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)
タイムゾーンも処理したい場合は、strptimeの代わりにdateutilを使用する必要があります。
私は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)
あなたの質問が置かれる方法では、文字列が日付値であることをjsonに示すものはありません。これは、サンプルの文字列があるjsonのドキュメントとは異なります。
'{"__complex__": true, "real": 1, "imag": 2}'
この文字列にはインジケータ"__complex__": true
これは、データのタイプを推測するために使用できますが、そのようなインジケーターがない限り、文字列は単なる文字列であり、すべての文字列を再正規化し、それらが日付のように見えるかどうかを判断するだけです。
あなたのケースでは、あなたのフォーマットにスキーマが利用可能であれば、間違いなくスキーマを使用すべきです。
次のように、正規表現を使用して、特定のフィールドを日時に変換するかどうかを決定できます。
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)
私が知る限り、これにはすぐに使える解決策はありません。
最初に、文字列と日時を正しく区別するには、ソリューションで json schema を考慮する必要があります。ある程度、jsonスキーマ推論ツール(jsonスキーマ推論ツールgithubのグーグル)でスキーマを推測し、実際に日時である場所を修正できます。
スキーマがわかっている場合は、jsonを解析して文字列表現を日時に置き換える関数を作成するのはかなり簡単です。コードのいくつかのインスピレーションは、おそらく validictory productから見つけることができます(JSONスキーマの検証も良い考えです)。
Nicolaの answer に触発されてpython3に適合(ベースストリングではなくstr):
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で保存された(したがってマイクロ秒で保存された)文字列をdatetimeオブジェクトに戻すには、 この質問 を参照してください。
このメソッドは、日時形式で再帰的な文字列検索を実装します
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)