{"id":8679,"library":"sqlalchemy-utc","title":"SQLAlchemy UTC Datetime Type","description":"SQLAlchemy-UTC provides a `UtcDateTime` type for SQLAlchemy that reliably stores and retrieves timezone-aware `datetime` objects in UTC. It acts as a robust replacement for SQLAlchemy's built-in `DateTime(timezone=True)`, particularly for databases like SQLite and MySQL that lack native `timestamptz` support by converting values to and from UTC. The library also includes a `utcnow()` helper function for server-side default generation. The current version is 0.14.0, released in September 2021.","status":"active","version":"0.14.0","language":"en","source_language":"en","source_url":"https://github.com/spoqa/sqlalchemy-utc","tags":["SQLAlchemy","ORM","datetime","timezone","UTC","database"],"install":[{"cmd":"pip install sqlalchemy-utc","lang":"bash","label":"Install with pip"}],"dependencies":[{"reason":"Core ORM library that sqlalchemy-utc extends.","package":"SQLAlchemy"}],"imports":[{"symbol":"UtcDateTime","correct":"from sqlalchemy_utc import UtcDateTime"},{"note":"The standard `datetime.utcnow()` is deprecated in Python 3.13+ and does not return timezone-aware objects. `sqlalchemy_utc.utcnow` provides a dialect-aware UTC function.","wrong":"from datetime import datetime; datetime.utcnow()","symbol":"utcnow","correct":"from sqlalchemy_utc import utcnow"}],"quickstart":{"code":"import datetime\nfrom sqlalchemy import create_engine, Column, Integer, String\nfrom sqlalchemy.orm import sessionmaker, declarative_base\nfrom sqlalchemy_utc import UtcDateTime, utcnow\n\n# Setup database (using SQLite for simplicity)\nengine = create_engine('sqlite:///./test.db')\nBase = declarative_base()\n\nclass Event(Base):\n    __tablename__ = 'events'\n    id = Column(Integer, primary_key=True)\n    name = Column(String)\n    created_at = Column(UtcDateTime, default=utcnow)\n    updated_at = Column(UtcDateTime, default=utcnow, onupdate=utcnow)\n\n    def __repr__(self):\n        return f\"<Event(id={self.id}, name='{self.name}', created_at={self.created_at}, updated_at={self.updated_at})>\"\n\n# Create tables\nBase.metadata.create_all(engine)\n\nSession = sessionmaker(bind=engine)\nsession = Session()\n\n# Create a new event\nnew_event = Event(name='Meeting Start')\nsession.add(new_event)\nsession.commit()\nprint(f\"Created event: {new_event}\")\n\n# Retrieve and verify timezone\nretrieved_event = session.query(Event).filter_by(name='Meeting Start').first()\nprint(f\"Retrieved event: {retrieved_event}\")\nassert retrieved_event.created_at.tzinfo == datetime.timezone.utc\nprint(\"Created_at is UTC aware.\")\n\n# Update an event\nretrieved_event.name = 'Meeting Concluded'\nsession.add(retrieved_event)\nsession.commit()\nprint(f\"Updated event: {retrieved_event}\")\nassert retrieved_event.updated_at.tzinfo == datetime.timezone.utc\nprint(\"Updated_at is UTC aware.\")\n\nsession.close()","lang":"python","description":"This quickstart demonstrates defining a SQLAlchemy model with `UtcDateTime` columns, using `utcnow()` for default and on-update values. It then creates, retrieves, and updates an event, verifying that the `datetime` objects returned are always timezone-aware and in UTC."},"warnings":[{"fix":"Always pass `datetime.datetime.now(datetime.timezone.utc)` or equivalent timezone-aware objects. Convert local times to UTC explicitly before passing to UtcDateTime columns if necessary.","message":"UtcDateTime strictly requires and returns timezone-aware `datetime` objects. Passing naive `datetime` objects (those without `tzinfo`) will lead to unexpected behavior or errors, as `UtcDateTime` will convert them to UTC assuming they are local time.","severity":"gotcha","affected_versions":"All"},{"fix":"For MySQL, use `default=utcnow` instead of `server_default=utcnow` when defining `UtcDateTime` columns. The `default` parameter handles client-side defaults.","message":"When using `sqlalchemy_utc.utcnow` with MySQL, it cannot be used with `server_default` for columns. MySQL does not support functions in `server_default` values for SQLAlchemy.","severity":"gotcha","affected_versions":"All"},{"fix":"Prefer `datetime.datetime.now(datetime.timezone.utc)` for standard library UTC timestamps, or specifically use `sqlalchemy_utc.utcnow` for column defaults as intended by the library.","message":"Python's built-in `datetime.datetime.utcnow()` is deprecated starting in Python 3.13 and is scheduled for removal. Using it will issue `DeprecationWarning`s.","severity":"breaking","affected_versions":"Python 3.13+"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure all `datetime` objects interacting with `UtcDateTime` columns are timezone-aware, e.g., `datetime.datetime.now(datetime.timezone.utc)`.","cause":"Attempting to assign a naive `datetime` object to a `UtcDateTime` column or performing an operation that assumes `tzinfo` on a naive object returned from a non-UtcDateTime column.","error":"AttributeError: 'datetime.datetime' object has no attribute 'tzinfo'"},{"fix":"Replace `DateTime(timezone=True)` with `UtcDateTime` from `sqlalchemy-utc`. This library explicitly handles the conversions to ensure UTC storage and timezone-aware retrieval on these databases.","cause":"The underlying database (SQLite/MySQL) does not natively support `TIMESTAMP WITH TIME ZONE`, causing SQLAlchemy's default `DateTime(timezone=True)` to often store/retrieve naive datetimes or local times without proper conversion.","error":"SQLAlchemy's DateTime(timezone=True) loses timezone information when fetching from SQLite/MySQL."},{"fix":"Configure the SQLAlchemy engine to ensure connections use UTC, e.g., `create_engine('postgresql://user:pass@host/db', connect_args={'options': '-c timezone=utc'})` or verify that PostgreSQL's `TimeZone` setting is 'UTC'.","cause":"PostgreSQL connections have an associated timezone, which defaults to the system's timezone. If not explicitly set to UTC, `TIMESTAMP WITHOUT TIME ZONE` values (which is how `UtcDateTime` might map on some systems) will be interpreted as local time on retrieval, or `TIMESTAMP WITH TIME ZONE` might be converted.","error":"Timestamps retrieved from PostgreSQL are in local time instead of UTC, even if stored as UTC."}]}