Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can SQLAlchemy DateTime Objects Only Be Naive?

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?

like image 719
Brighid McDonnell Avatar asked Mar 27 '10 05:03

Brighid McDonnell


People also ask

What is offset naive and offset aware Datetimes?

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.

Can't compare offset naive offset aware date?

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.


2 Answers

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).

like image 173
Denis Otkidach Avatar answered Sep 21 '22 00:09

Denis Otkidach


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 format
  • mydb is the name of my db table
  • name is one of the columns in the table
  • last_update is a column that is stored in the format datetime

The trick is replace(tzinfo=pytz.utc)

like image 21
rpontual Avatar answered Sep 22 '22 00:09

rpontual