개요
이 가이드에서는 PyMongo에서 Python datetime 객체를 처리하는 방법을 배울 수 있습니다.
용어
Python 은 전용 데이터 유형datetime.datetime 을(를) 사용하여 날짜와 시간을 나타냅니다. MongoDB 는 영국 런던을 기준으로 하는 글로벌 시간 표준 인 협정 세계시(UTC) 를 기준으로 datetime 값을 저장합니다.
Naive Datetimes
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 로 전달합니다.timezone객체에서localize()메서드를 호출하고datetime값을 전달하여 현지화합니다.
다음 코드 예시에서는 datetime 값을 8시간 오프셋인 "US/Pacific" 표준 시간대로 현지화합니다.
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 인스턴스를 저장할 수 없습니다. 모든 date 객체를 datetime 객체로 변환한 후 MongoDB 에 저장합니다.
날짜/시간 읽기
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 객체를 만듭니다. 그런 다음 CodecOptions 객체를 만들고 생성자에 다음 인수를 전달합니다.
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
팁
앞의 예제에서는 컬렉션 수준에서 코덱 옵션을 지정합니다. 클라이언트 또는 데이터베이스 수준에서 코덱 옵션을 지정할 수도 있습니다.
날짜/시간 저장
일관성 을 위해 MongoDB 에 UTC datetime 값만 저장 합니다. 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 (1~9999년) 사이의 datetime 값만 표현할 수 있습니다. Unix epoch의 모든비트 밀리초 값을 허용하는 BSON 사용하면 훨씬 더 넓은 범위 의 날짜와 시간을 표현할 수 있습니다.64
PyMongo 로 BSON 시간을 표현하려면 Python의 내장 int 유형에 대한 래퍼인 datetime_ms.DatetimeMS 객체 를 만듭니다. 다음 값 중 하나를 전달하여 DatetimeMS 객체 를 수동으로 만들 수 있습니다.
Unix epoch 이후의 밀리초 수를 나타내는
int입니다.datetime객체
다음 코드 예시에서는 연도를 나타내는 int 값( datetime 범위를 벗어난 날짜인146136543)을 전달하여 DatetimeMS 객체를 구성합니다.
from bson.datetime_ms import DatetimeMS out_of_range = DatetimeMS(-(2**62))
PyMongo가 UTC datetime 값을 DatetimeMS 객체로 자동으로 디코딩하도록 지시할 수도 있습니다. 이렇게 하려면 CodecOptions 의 datetime_conversion 매개 변수를 datetime_ms.DatetimeConversion 열거형의 값으로 설정합니다. 다음 섹션에서는 이러한 값에 대해 설명합니다.
팁
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 범위 내에 있더라도 PyMongo가 DatetimeMS 객체만 반환하도록 지시합니다.
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 범위에 있는 날짜/시간 하나와 범위 외부에 있는 날짜/시간 하나를 인코딩 및 디코딩합니다.
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 범위보다 한 날짜 시간 일찍 인코딩 및 디코딩하고 datetime 범위보다 한 날짜 시간 나중에 인코딩 및 디코딩합니다. 결과 값은 허용된 범위의 시작과 끝에 있습니다.
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)}
문제 해결
다른 언어 드라이버에 의해 저장된 날짜 디코딩 시 OverflowError가 발생합니다.
PyMongo는 BSON datetime 값을 Python의 datetime.datetime 클래스 인스턴스로 디코딩합니다. datetime.datetime 의 인스턴스는 datetime.MINYEAR (1)에서 datetime.MAXYEAR (9999) 사이의 연도로 제한됩니다. 일부 MongoDB 드라이버는 datetime.datetime 에서 지원하는 것보다 훨씬 큰 연도 값으로 BSON 날짜/시간을 저장할 수 있습니다.
이 문제를 해결하는 방법에는 몇 가지가 있습니다. PyMongo 4.3 부터 bson.decode 는 네 가지 방법 중 하나로 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 설정을 포함하지 않는 또 다른 옵션은 ~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 문서를 참조하세요.
datetimedocs.python.org에서pytzpypi.org에서