我正在开发的应用程序除其他外还具有一些订单管理功能,并且发现了一个我认为与时区有关的问题。
背景信息
后端是用Python编写的,我们正在使用Flask和SQLAlchemy。该数据库是PostgreSQL。我们(用户和开发人员)都处于同一时区(CET / CEST)。我认为该应用程序托管在AWS上,服务器在爱尔兰。
问题的一般说明
当我检索订单并尝试按特定的日期范围进行过滤时,结果中将包含第二天的第一个小时(日期范围之外)的订单。
分步
# Very simplified version of actual code
def get_orders(self, site_id, params):
created_after = params.get('created_after')
created_before = params.get('created_before')
query = self.sess.query(Order) \
.filter(Order.site_id == site_id)
if created_after:
dt = datetime.strptime(created_after, '%Y%m%d-%H%M%S-%f')
query = query.filter(Order.created_at > self._nor_to_utc_tz(dt))
if created_before:
dt = datetime.strptime(created_before, '%Y%m%d-%H%M%S-%f')
query = query.filter(Order.created_at < self._nor_to_utz_tz(dt))
...
return result
def _nor_to_utc_tz(dt):
# Incoming datetime is always the same timezone
dt = dt.replace(tzinfo=tz.gettz('Europe/Oslo'))
# All datetimes is stored as UTC on server
dt = dt.astimezone(tz.gettz('UTC'))
return dt
SQLAlchemy模型模板
class Order(Base, ModelTemplate):
__tablename__ = 'orders'
...
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
...
结果
在本地测试时,一切正常。我已经在一天中的所有时间下达了测试订单,并且在正确的日期范围内对它们进行了过滤。
该问题发生在生产环境中。对于本应仅限于前一天创建的订单的查询,结果中将包括在当地时间午夜之后立即创建的订单。
示例
理论
我的理论基于没有其他理由,我认为没有其他适合该模式的理论,那就是postgres在过滤结果之前将日期范围转换为服务器本地时间。我相信(或推测)服务器的本地时间是UTC + 1(自爱尔兰以来),这与我得到的结果相符。
我尝试过的事情