Datetimes and Timezones

These examples show how to handle Python datetime.datetime objectscorrectly in PyMongo.

Basic Usage

PyMongo uses datetime.datetime objects for representing dates and timesin MongoDB documents. Because MongoDB assumes that dates and times are in UTC,care should be taken to ensure that dates and times written to the databasereflect UTC. For example, the following code stores the current UTC date andtime into MongoDB:

  1. >>> result = db.objects.insert_one(
  2. ... {"last_modified": datetime.datetime.utcnow()})

Always use datetime.datetime.utcnow(), which returns the current time inUTC, instead of datetime.datetime.now(), which returns the current localtime. Avoid doing this:

  1. >>> result = db.objects.insert_one(
  2. ... {"last_modified": datetime.datetime.now()})

The value for last_modified is very different between these two examples, eventhough both documents were stored at around the same local time. This will beconfusing to the application that reads them:

  1. >>> [doc['last_modified'] for doc in db.objects.find()]
  2. [datetime.datetime(2015, 7, 8, 18, 17, 28, 324000),
  3. datetime.datetime(2015, 7, 8, 11, 17, 42, 911000)]

bson.codec_options.CodecOptions has a tz_aware option that enables“aware” datetime.datetime objects, i.e., datetimes that know whattimezone they’re in. By default, PyMongo retrieves naive datetimes:

  1. >>> result = db.tzdemo.insert_one(
  2. ... {'date': datetime.datetime(2002, 10, 27, 6, 0, 0)})
  3. >>> db.tzdemo.find_one()['date']
  4. datetime.datetime(2002, 10, 27, 6, 0)
  5. >>> options = CodecOptions(tz_aware=True)
  6. >>> db.get_collection('tzdemo', codec_options=options).find_one()['date']
  7. datetime.datetime(2002, 10, 27, 6, 0,
  8. tzinfo=<bson.tz_util.FixedOffset object at 0x10583a050>)

Saving Datetimes with Timezones

When storing datetime.datetime objects that specify a timezone(i.e. they have a tzinfo property that isn’t None), PyMongo will convertthose datetimes to UTC automatically:

  1. >>> import pytz
  2. >>> pacific = pytz.timezone('US/Pacific')
  3. >>> aware_datetime = pacific.localize(
  4. ... datetime.datetime(2002, 10, 27, 6, 0, 0))
  5. >>> result = db.times.insert_one({"date": aware_datetime})
  6. >>> db.times.find_one()['date']
  7. datetime.datetime(2002, 10, 27, 14, 0)

Reading Time

As previously mentioned, by default all datetime.datetime objectsreturned by PyMongo will be naive but reflect UTC (i.e. the time as stored inMongoDB). By setting the tz_aware option onCodecOptions, datetime.datetime objectswill be timezone-aware and have a tzinfo property that reflects the UTCtimezone.

PyMongo 3.1 introduced a tzinfo property that can be set onCodecOptions to convert datetime.datetimeobjects to local time automatically. For example, if we wanted to read all timesout of MongoDB in US/Pacific time:

  1. >>> from bson.codec_options import CodecOptions
  2. >>> db.times.find_one()['date']
  3. datetime.datetime(2002, 10, 27, 14, 0)
  4. >>> aware_times = db.times.with_options(codec_options=CodecOptions(
  5. ... tz_aware=True,
  6. ... tzinfo=pytz.timezone('US/Pacific')))
  7. >>> result = aware_times.find_one()
  8. datetime.datetime(2002, 10, 27, 6, 0, # doctest: +NORMALIZE_WHITESPACE
  9. tzinfo=<DstTzInfo 'US/Pacific' PST-1 day, 16:00:00 STD>)