I am working with SQLAlchemy, and I'm not yet sure which database I'll use under it, so I want to remain as DB-agnostic as possible. How can I store a timezone-aware datetime object in the DB without tying myself to a specific database? Right now, I'm making sure that times are UTC before I store them in the DB, and converting to localized at display-time, but that feels inelegant and brittle. Is there a DB-agnostic way to get a timezone-aware datetime out of SQLAlchemy instead of getting naive datatime objects out of the DB?
naive vs aware So a datetime object can be either offset naive or offset aware. A timezone's offset refers to how many hours the timezone is from Coordinated Universal Time (UTC). A naive datetime object contains no timezone information. The easiest way to tell if a datetime object is naive is by checking tzinfo.
To fix TypeError: can't compare offset-naive and offset-aware datetimes with Python, we can use the utc. localize method to convert both times to aware datetimes. to call utc. localize to convert datetime_start and datetime_end to time zone aware datetimes.
There is a timezone
parameter to DateTime
column time, so there is no problem with storing timezone-aware datetime
objects. However I found convenient to convert stored datetime
to UTC automatically with simple type decorator:
from sqlalchemy import types from datetime import datetime, timezone class UTCDateTime(types.TypeDecorator): impl = types.DateTime def process_bind_param(self, value, engine): if value is None: return if value.utcoffset() is None: raise ValueError( 'Got naive datetime while timezone-aware is expected' ) return value.astimezone(timezone.utc) def process_result_value(self, value, engine): if value is not None: return value.replace(tzinfo=timezone.utc)
Note, that is behaves nicely when you use naive datetime
by accident (meaning it will raise a ValueError).
I am addressing the desire to have datetime-aware in my code by using UTC in all internal instances. The only issue I came up with was when reading the database. Despite writing datetime-aware to the database, when retrieving the format is naive. My fix was:
import pytz dt = mydb.query.filter_by(name='test').first().last_update.replace(tzinfo=pytz.utc)
dt
is the variable that will store the last_update retrieved in datetime formatmydb
is the name of my db tablename
is one of the columns in the tablelast_update
is a column that is stored in the format datetimeThe trick is replace(tzinfo=pytz.utc)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With