Overview
このガイドでは、PyMongo で Python datetimeオブジェクトを処理する方法を学習できます。
用語
Python は日付と時刻を表すために専用のデータ型datetime.datetimeを使用します。 MongoDB は、英国ロード フィールドを対象としたグローバル タイム標準(UTC)にdatetime値を保存します。
ネイティブ日時
UTC オフセットやタイムゾーンに関する追加情報が含まれていない場合、 datetime値はネイティブではありません。 以下は、ネイティブのdatetimeオブジェクトの例です。
datetime(2002, 10, 27, 14, 0, 0)
認識済み日時
datetime値は、 tzinfo属性が含まれている場合に認識されます。 この属性は、UTC 時間からの値のオフセット、そのタイムゾーン、夏時間が有効になっているかどうかを示します。 以下は、認識されているdatetimeオブジェクトの例です。
datetime(2002, 10, 27, 6, 0, tzinfo=<DstTzInfo 'US/Pacific' PST-1 day, 16:00:00 STD>)
ローカライズ
ローカライズとは、 datetimeの値に時間を追加したり、その値から時間を減算してその値を別のタイムゾーンに変換するプロセスです。 datetime値をローカライズするには、次の手順を実行します。
pip を使用して、Python 環境に
pytzライブラリをインストールします。pip install pytzpytz.timezoneオブジェクトを作成します。 ターゲット タイム ゾーンを string としてコンストラクターに渡します。ローカライズするための
datetime値を渡して、timezoneオブジェクトでlocalize()メソッドを呼び出します。
次のコード例では、 datetime値を"US/Pacific"タイムゾーン(8 時間のオフセット)にローカライズします。
from datetime import datetime from pytz import timezone utc_datetime = datetime(2002, 10, 27, 6, 0, 0) pacific = timezone("US/Pacific") local_datetime = pacific.localize(utc_datetime) print(f"UTC datetime: {utc_datetime}") print(f"Local datetime: {local_datetime}")
UTC datetime: 2002-10-27 06:00:00 Local datetime: 2002-10-27 06:00:00-08:00
タイムゾーン文字列の標準リストについては、 タイムゾーン データベース または Wikipedia の対応する記事を参照してください。
重要
PyMongo では、時刻のない日付の BSON 型がないため、 datetime.dateインスタンスを保存できません。 MongoDB に保存する前に、すべてのdateオブジェクトをdatetimeオブジェクトに変換します。
日時の読み取り
PyMongo を使用してdatetime値を取得する場合、ドライバーはネイティブ UTC、認識済み UTC、またはローカライズされた値としてそれを形式できます。 次のセクションでは、各種類の値を取得する方法について説明します。
これらのセクションでは、 sample_collectionという名前の MongoDB コレクションに次のドキュメントが含まれていることを前提としています。 "date"フィールドの値は UTC datetime値です。
{"date": datetime(2002, 10, 27, 14, 0, 0)}
ネイティブ UTC 日時
デフォルトでは 、 PyMongo は追加情報のない UTC datetime 値を検索します。次のコード例では、サンプルドキュメントを取得し、datetime 値を出力します。出力される値は、サンプルドキュメントの と同じです。対応するコードを表示するには、Synchronous タブまたは Asynchronousタブを選択します。
from datetime import datetime collection = database["sample_collection"] find_result = collection.find_one()["date"] print(f"datetime: {find_result}") print(f"datetime.tzinfo: {find_result.tzinfo}")
datetime: 2002-10-27 14:00:00 datetime.tzinfo: None
from datetime import datetime collection = database["sample_collection"] find_result = (await collection.find_one())["date"] print(f"datetime: {find_result}") print(f"datetime.tzinfo: {find_result.tzinfo}")
datetime: 2002-10-27 14:00:00 datetime.tzinfo: None
認識済み UTC 日時
PyMongo に認識済みのdatetime値を取得するよう指示するには、 CodecOptionsオブジェクトを作成し、 tz_aware = Trueをコンストラクターに渡します。 次に、 CodecOptionsオブジェクトをget_collection()メソッドに渡します。
次のコード例では、サンプルドキュメントから datetime の値を認識済みの datetime として取得します。対応するコードを表示するには、Synchronous タブまたは Asynchronousタブを選択します。
from pymongo import MongoClient from datetime import datetime from bson.codec_options import CodecOptions options = CodecOptions(tz_aware = True) collection = database.get_collection("sample_collection", options) find_result = collection.find_one()["date"] print(f"datetime: {find_result}") print(f"datetime.tzinfo: {find_result.tzinfo}")
datetime: 2002-10-27 14:00:00+00:00 datetime.tzinfo: <bson.tz_util.FixedOffset object at 0x104db2b80>
from pymongo import MongoClient from datetime import datetime from bson.codec_options import CodecOptions options = CodecOptions(tz_aware = True) collection = database.get_collection("sample_collection", options) find_result = (await collection.find_one())["date"] print(f"datetime: {find_result}") print(f"datetime.tzinfo: {find_result.tzinfo}")
datetime: 2002-10-27 14:00:00+00:00 datetime.tzinfo: <bson.tz_util.FixedOffset object at 0x104db2b80>
ローカライズされた日時
ユーザーにdatetime値を表示する予定の場合は、MongoDB から読み取られたすべての時間を特定のタイムゾーンに自動的に変換するように PyMongo に指示できます。 そのためには、「用語」セクションで説明されているように、ターゲット タイムゾーン用のtimezoneオブジェクトを作成します。 Then, create a CodecOptions object and pass the following arguments to the constructor:
tz_aware:Trueに設定します。tzinfo:timezoneオブジェクト。
次のコード例では、サンプルドキュメントを取得していますが、tz_aware と tzinfo 引数を使用して datetime の値を "US/Pacific" タイムゾーンに自動的にローカライズします。対応するコードを表示するには、Synchronous タブまたは Asynchronousタブを選択します。
from pymongo import MongoClient from datetime import datetime from bson.codec_options import CodecOptions import pytz from pytz import timezone pacific = timezone("US/Pacific") options = CodecOptions(tz_aware = True, tzinfo = pacific) collection = database.get_collection("sample_collection", options) find_result = collection.find_one()["date"] print(f"datetime: {find_result}") print(f"datetime.tzinfo: {find_result.tzinfo}")
datetime: 2002-10-27 06:00:00-08:00 datetime.tzinfo: US/Pacific
from pymongo import MongoClient from datetime import datetime from bson.codec_options import CodecOptions import pytz from pytz import timezone pacific = timezone("US/Pacific") options = CodecOptions(tz_aware = True, tzinfo = pacific) collection = database.get_collection("sample_collection", options) find_result = (await collection.find_one())["date"] print(f"datetime: {find_result}") print(f"datetime.tzinfo: {find_result.tzinfo}")
datetime: 2002-10-27 06:00:00-08:00 datetime.tzinfo: US/Pacific
Tip
上記の例では、コレクション レベルでコーデック オプションを指定しています。 クライアント レベルまたはデータベース レベルでコーデック オプションを指定することもできます。
日時の保存
整合性のために、UTC datetime値のみを MongoDB に保存します。 PyMongo を使用してdatetime値を含むフィールドを作成または更新すると、ドライバーは最初にdatetime値がネイティブか認識されているかを確認します。
datetimeがネイティブの場合、PyMongo はdatetimeが UTC であると想定し、それを変更せずに MongoDB に保存します。datetimeが認識されている場合、PyMongo は MongoDB に保存する前に時間を自動的に UTC に変換します。
次のコード例では、 "US/Pacific" タイムゾーンにローカライズされた datetime 値を含むドキュメントを挿入します。PyMongo は、付属のタイムゾーンを使用してローカル時間を UTC に変換します。ドキュメントがMongoDBから取得された場合、datetime 値は UTC です。対応するコードを表示するには、Synchronous タブまたは Asynchronousタブを選択します。
from pymongo import MongoClient from datetime import datetime from pytz import timezone utc_datetime = datetime(2002, 10, 27, 6, 0, 0) pacific = timezone("US/Pacific") local_datetime = pacific.localize(utc_datetime) print(f"datetime before storage: {local_datetime}") collection.insert_one({"date": local_datetime}) find_result = collection.find_one()["date"] print(f"datetime after storage: {find_result}")
datetime before storage: 2002-10-27 06:00:00-08:00 datetime after storage: 2002-10-27 14:00:00
from pymongo import MongoClient from datetime import datetime from pytz import timezone utc_datetime = datetime(2002, 10, 27, 6, 0, 0) pacific = timezone("US/Pacific") local_datetime = pacific.localize(utc_datetime) print(f"datetime before storage: {local_datetime}") await collection.insert_one({"date": local_datetime}) find_result = (await collection.find_one())["date"] print(f"datetime after storage: {find_result}")
datetime before storage: 2002-10-27 06:00:00-08:00 datetime after storage: 2002-10-27 14:00:00
重要
datetime.now()
引数なしでdatetime.now()メソッドを呼び出すのは避けてください。 これにより、現在のローカル時間が返されます。
代わりに、UTC で現在時刻を返すdatetime.now(tz=datetime.timezone.utc)メソッドを常に呼び出します。
範囲外の日時の処理
Python の datetimeクラスは、datetime.min から datetime.max までの datetime 値のみを表すことができます(1-9999 年)。BSONを使用すると、はるかに大きな日付と時刻の範囲を表すことができます。これにより、Unix エポックからの任意の64 ビット ミリ秒値が利用できます。
PyMongo で BSON 時間を表すには、Python の組み込みint型のラッパーであるdatetime_ms.DatetimeMSオブジェクトを作成します。 次のいずれかの値を渡すことで、 DatetimeMSオブジェクトを手動で作成できます。
UNIX エポックからのミリ秒数を表す
intdatetimeオブジェクト
次のコード例では、年 - 146136543 ( datetimeの範囲外の日付)を表すint値を渡してDatetimeMSオブジェクトを構築します。
from bson.datetime_ms import DatetimeMS out_of_range = DatetimeMS(-(2**62))
また、UTC datetime値をDatetimeMSオブジェクトとして自動的にデコードするように PyMongo に指示することもできます。 そのためには、 CodecOptionsのdatetime_conversionパラメータをdatetime_ms.DatetimeConversion列挙型の値に設定します。 次のセクションでは、これらの値について説明します。
Tip
DatetimeMS オブジェクトは、 DatetimeMSの他のインスタンスに対する豊富な比較メソッドをサポートします。 また、 DatetimeMS.to_datetime()メソッドを使用してこれらをdatetimeオブジェクトに変換することもできます。
DatetimeConversion.DATETIME
DatetimeConversion.DATETIME は、デフォルト値です。 この値により、次の例に示すように、PyMongo は範囲外の日付をデコードしようとするとエラーを発生させます。
from datetime import datetime from bson import encode, decode from bson.datetime_ms import DatetimeMS out_of_range = DatetimeMS(-(2**62)) val = encode({"date": out_of_range}) decoded = decode(val) print(decoded)
... bson.errors.InvalidBSON: year -146136543 is out of range (Consider Using CodecOptions(datetime_conversion=DATETIME_AUTO) or MongoClient(datetime_conversion='DATETIME_AUTO')). ...
DatetimeConversion.DATETIME_MS
この値は、日付がdatetimeの範囲内であっても、 DatetimeMSオブジェクトのみを返すように PyMongo に指示します。
from datetime import datetime from bson import encode, decode from bson.datetime_ms import DatetimeMS from bson.codec_options import CodecOptions, DatetimeConversion val = encode({"date": datetime(1970, 1, 2)}) codec_ms = CodecOptions(datetime_conversion=DatetimeConversion.DATETIME_MS) decoded = decode(val, codec_options=codec_ms) print(decoded)
{"date": DatetimeMS(86400000)}
DatetimeConversion.DATETIME_Auto
この値は、値がdatetimeの範囲内にある場合はdatetimeオブジェクトを返し、それ以外の場合はDatetimeMSオブジェクトを返すように PyMongo に指示します。 次のコード例では、 datetime範囲内の 1 つの日時と範囲外の日時をエンコードおよびデコードします。
from datetime import datetime from bson import encode, decode from bson.datetime_ms import DatetimeMS from bson.codec_options import CodecOptions, DatetimeConversion in_range = encode({"date": datetime(1970, 1, 1)}) out_of_range = encode({"date": DatetimeMS(-(2**62))}) codec_auto = CodecOptions(datetime_conversion=DatetimeConversion.DATETIME_AUTO) in_decoded = decode(in_range, codec_options=codec_auto) out_decoded = decode(out_of_range, codec_options=codec_auto) print(f"in-range date: {in_decoded}") print(f"out-of-range date: {out_decoded}")
in-range date: {"date": datetime.datetime(1970, 1, 1, 0, 0)} out-of-range date: {'x': DatetimeMS(-4611686018427387904)}
DatetimeConversion.DATETIME_CLAMP
この値は結果のdatetimeオブジェクトを「ロック」し、それらをdatetimeの範囲( 999 、 000マイクロ秒に削除)内に収まるようにします。
次のコード例では、 datetime範囲より前の 1 つの日時とdatetime範囲より後の 1 つの日時をエンコードおよびデコードします。 結果の値は、許可された範囲の先頭と末尾にあります。
from datetime import datetime from bson import encode, decode from bson.datetime_ms import DatetimeMS from bson.codec_options import CodecOptions, DatetimeConversion before = encode({"date": DatetimeMS(-(2**62))}) after = encode({"date": DatetimeMS(2**62)}) codec_clamp = CodecOptions(datetime_conversion=DatetimeConversion.DATETIME_CLAMP) before_decoded = decode(before, codec_options=codec_clamp) after_decoded = decode(after, codec_options=codec_clamp) print(f"datetime before the range: {before_decoded}") print(f"datetime after the range: {after_decoded}")
datetime before the range: {"date": datetime.datetime(1, 1, 1, 0, 0)} datetime after the range: {"date": datetime.datetime(9999, 12, 31, 23, 59, 59, 999000)}
トラブルシューティング
別の言語のドライバーによって保存された日付をデコードするときにオーバーフローエラーが発生する
PyMongo は BSON datetime値を Python のdatetime.datetimeクラスのインスタンスにデコードします。 datetime.datetimeのインスタンスは、 datetime.MINYEAR ( 1 )からdatetime.MAXYEAR ( 9999 )までの年に制限されています。 一部の MongoDB ドライバーは、 datetime.datetimeでサポートされている値より大幅に外側の年値を持つ BSON 日時を保存できます。
この問題を回避する方法がいくつかあります。 PyMongo 4.3以降、 bson.decodeは 4 つの方法のいずれかで BSON datetime値を復号化できます。 変換方法は、 ~bson.codec_options.CodecOptionsのdatetime_conversionパラメータを使用して指定できます。
デフォルトの変換オプションは ~bson.codec_options.DatetimeConversion.DATETIME です。これにより、値が datetime.datetime としてデコードされ、範囲外の日付で ~builtin.OverflowError が発生できるようになります。~bson.codec_options.DatetimeConversion.DATETIME_AUTO はこの動作を変更して、表現が範囲外の場合には代わりに ~bson.datetime_ms.DatetimeMS を返し、以前のように ~datetime.datetime オブジェクトを返します。対応するコードを表示するには、Synchronous タブまたは Asynchronousタブを選択します。
from datetime import datetime from bson.datetime_ms import DatetimeMS from bson.codec_options import DatetimeConversion from pymongo import MongoClient client = MongoClient(datetime_conversion=DatetimeConversion.DATETIME_AUTO) client.db.collection.insert_one({"x": datetime(1970, 1, 1)}) client.db.collection.insert_one({"x": DatetimeMS(2**62)}) for x in client.db.collection.find(): print(x)
{'_id': ObjectId('...'), 'x': datetime.datetime(1970, 1, 1, 0, 0)} {'_id': ObjectId('...'), 'x': DatetimeMS(4611686018427387904)}
from datetime import datetime from bson.datetime_ms import DatetimeMS from bson.codec_options import DatetimeConversion from pymongo import MongoClient client = AsyncMongoClient(datetime_conversion=DatetimeConversion.DATETIME_AUTO) await client.db.collection.insert_one({"x": datetime(1970, 1, 1)}) await client.db.collection.insert_one({"x": DatetimeMS(2**62)}) async for x in client.db.collection.find(): print(x)
{'_id': ObjectId('...'), 'x': datetime.datetime(1970, 1, 1, 0, 0)} {'_id': ObjectId('...'), 'x': DatetimeMS(4611686018427387904)}
その他のオプションについては、DatetimeConversionクラスのAPIドキュメントを参照してください。
datetime_conversion の設定に関係のないもう 1 つのオプションは、~datetime.datetime でサポートされている範囲外のドキュメント値をフィルタリングで除外することです。対応するコードを表示するには、Synchronous タブまたは Asynchronousタブを選択します。
from datetime import datetime coll = client.test.dates cur = coll.find({'dt': {'$gte': datetime.min, '$lte': datetime.max}})
from datetime import datetime coll = client.test.dates cur = coll.find({'dt': {'$gte': datetime.min, '$lte': datetime.max}})
datetime の値が必要ない場合は、そのフィールドのみをフィルタリングで除外できます。対応するコードを表示するには、Synchronous タブまたは Asynchronousタブを選択します。
cur = coll.find({}, projection={'dt': False})
cur = coll.find({}, projection={'dt': False})
API ドキュメント
PyMongo での日付と時刻の操作の詳細については、次の API ドキュメントを参照してください。
datetime(docs.python.org)pytz(pypi.org)