【问题标题】:How to store timezone aware datetime values in SqlAlchemy / Mysql?如何在 SqlAlchemy / Mysql 中存储时区感知日期时间值?
【发布时间】:2020-07-19 15:58:51
【问题描述】:

我想在 mysql 数据库中存储一个 Python 时区感知日期时间属性。我使用 SqlAlchemy。在 SqlAlchemy 类定义中,我通过以下方式指定列:

    a_utcDatetime = Column(DATETIME(fsp=6))

我意识到在数据库中该列不再有时区信息。 此外,从数据库中读取后,该变量也丢失了其时区信息。

有什么方法可以在定义时将a_utcDatetime 配置为时区感知?

【问题讨论】:

    标签: python mysql datetime sqlalchemy pytz


    【解决方案1】:

    如果您真的想存储时区偏移量(而不仅仅是遵循将所有日期/时间值存储为 UTC 的约定),那么您需要一个单独的列来存储该偏移量值。我刚刚用 MySQL 试过这个,它似乎工作:

    from datetime import datetime, timezone, timedelta
    
    from sqlalchemy import (
        create_engine,
        Column,
        Integer,
        String,
        text,
        __version__ as sa_version,
        DATETIME,
    )
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.orm import sessionmaker
    
    connection_uri = "mysql+pymysql://root:toot@localhost:3307/mydb"
    engine = create_engine(connection_uri, echo=False)
    Base = declarative_base()
    
    with engine.begin() as conn:
        conn.execute(text("DROP TABLE IF EXISTS event_log"))
    
    
    class EventLog(Base):
        __tablename__ = "event_log"
        id = Column(Integer, primary_key=True)
        event = Column(String(50))
        local_datetime = Column(DATETIME)
        tz_offset_minutes = Column(Integer)
    
        @property
        def dt_aware(self):
            return self.local_datetime.replace(
                tzinfo=timezone(timedelta(minutes=self.tz_offset_minutes))
            )
    
        @dt_aware.setter
        def dt_aware(self, value):
            self.local_datetime = value.replace(tzinfo=None)
            self.tz_offset_minutes = (
                value.tzinfo.utcoffset(value).total_seconds() // 60
            )
    
        def __repr__(self):
            return (
                f"<EventLog(id={self.id}, "
                f"event={repr(self.event)}, "
                f"str(dt_aware)='{self.dt_aware}'>"
            )
    
    
    Base.metadata.create_all(engine)
    
    Session = sessionmaker(bind=engine)
    session = Session()
    
    my_event_start = datetime(
        2020, 4, 20, 16, 20, 0, tzinfo=timezone(timedelta(hours=-7))
    )
    my_event = EventLog(id=1, event="an event", dt_aware=my_event_start)
    
    session.add(my_event)
    session.commit()
    
    # check results by querying database directly
    sql = text("SELECT * FROM event_log ORDER BY id")
    with engine.begin() as conn:
        result = conn.execute(sql).fetchall()
    print(result)
    """ console output:
    [(1, 'an event', datetime.datetime(2020, 4, 20, 16, 20), -420)]
    """
    
    print(my_event)
    """ console output:
    <EventLog(id=1, event='an event', str(dt_aware)='2020-04-20 16:20:00-07:00'>
    """
    
    print(type(my_event.dt_aware))  # <class 'datetime.datetime'>
    

    【讨论】:

    • 我可以在 Stackoverflow 上找到多少帅哥。精彩的!所以这个解决方案看起来很不错。谢谢你。也许我更容易听从您的建议,将值作为纯 UTC 保存在数据库中。
    猜你喜欢
    • 2021-08-29
    • 2020-12-03
    • 2016-08-24
    • 2020-11-20
    • 2012-06-30
    • 1970-01-01
    • 2019-01-18
    • 2016-08-06
    • 2013-11-19
    相关资源
    最近更新 更多