如何在Django、SQLite与Python中处理并显示数据库时间戳
嘿,这两个问题其实是关联的,我帮你一步步理清楚,再也不用被naive/aware搞晕啦!
首先来说时区的问题:
- 你用
timezone.now()存时间,这个行为完全取决于你Django配置里的USE_TZ和TIME_ZONE参数:- 如果
USE_TZ=True(Django推荐开启),timezone.now()返回的是UTC时区的aware datetime,Django会把它转成UTC时间存入SQLite(毕竟SQLite本身不支持时区存储,存的是不带时区标记的字符串/datetime值)。但你说取出来的是洛杉矶时间,那大概率你的USE_TZ=False,此时timezone.now()等价于datetime.now(),存的是TIME_ZONE设置的America/Los_Angeles时区的naive datetime(不带时区信息),所以外部读取时自然看不到时区标记。
- 如果
- 要验证的话,直接看你
settings.py里的这两个配置就清楚了。
接下来解决这两个问题的具体步骤:
第一步:把读取到的时间转成带正确时区的aware datetime
不管存的是UTC还是洛杉矶时间,先把数据库里的字符串转成datetime对象,再给它补上时区信息,这是解决所有问题的核心:
情况1:数据库里存的是洛杉矶时区的naive时间(USE_TZ=False)
from datetime import datetime import pytz # 从SQLite拿到的时间字符串 db_time_str = "2018-03-02 17:44:17.868267" # 转成naive datetime对象 naive_dt = datetime.strptime(db_time_str, "%Y-%m-%d %H:%M:%S.%f") # 给它加上洛杉矶时区,变成aware datetime la_tz = pytz.timezone("America/Los_Angeles") aware_dt = la_tz.localize(naive_dt, is_dst=None) # is_dst=None会自动处理夏令时,避免报错
情况2:数据库里存的是UTC时间(USE_TZ=True)
如果是这种情况,你需要先把读取到的时间当成UTC,再转成洛杉矶时区:
from datetime import datetime import pytz db_time_str = "2018-03-02 17:44:17.868267" naive_dt = datetime.strptime(db_time_str, "%Y-%m-%d %H:%M:%S.%f") # 先标记为UTC时区 utc_tz = pytz.utc aware_utc = utc_tz.localize(naive_dt) # 转成洛杉矶时区 aware_la = aware_utc.astimezone(pytz.timezone("America/Los_Angeles"))
第二步:美观格式化时间
现在你有了带正确时区的aware datetime,格式化就简单了,用strftime就能自定义你想要的格式:
# 示例1:"March 02, 2018 05:44 PM (PDT)" formatted_time = aware_dt.strftime("%B %d, %Y %I:%M %p (%Z)") # 示例2:"2018-03-02 下午5:44" formatted_time = aware_dt.strftime("%Y-%m-%d %p%I:%M")
如果你是在Django环境内处理,也可以用Django自带的工具简化:
from django.utils import timezone # 转成本地时区(就是你TIME_ZONE设置的时区)再格式化 local_dt = timezone.localtime(aware_dt) formatted_time = local_dt.strftime("%B %d, %Y %I:%M %p")
最后给你个小提醒:尽量开启USE_TZ=True,这样Django内部会统一用UTC存储时间,避免夏令时或者时区切换带来的问题,外部读取时再转成你需要的时区就好啦。
内容的提问来源于stack exchange,提问作者4dummies
相关产品推荐
相关产品推荐

