Django的timezone应用心得 django timezone
中国地区幅员辽阔, 按照15度一个时区计算,中国横跨5个时区, 但是实际上我们使用的是北京时间的东八区时间, 就是在国际标准时间的基础上, 早了8个小时. 也就是说北京这边看到日出了, 8小时后位于英国的国际标准时间起点的位置才能看到日出.
django既然开始用这个时区了, 那我们也要跟上啊. 结果就是出现了很多意想不到的错误.
#1. 大量的 RuntimeWarning: DateTimeField received a naive datetime (YYYY-MM-DD HH:MM:SS) while time zone support is active
这种情况就是你的settings.py中的 USE_TZ=True 了, 一旦你设置了这个地方, 你的噩梦就开始了.哈哈, 如果为了眼不见心不烦, 你可以将它设置为False: USE_TZ = False, 这样, django1.4中出现的timezone你完全不必理会, 还是按照你以前的设置来运行程序.
#2. now.date()居然是昨天, 或者明天.
实际上, 确实会遇到这种问题.
举个实例来说吧:
有新闻(news)模块, News model有个字段为 pub_date, 然后, 你设置客户端访问该条新闻的url为 http://example.com/news/2013/08/23/10086/ 就是按照 /新闻/年/月/日/ID/ 的方式编排, 结果你发现: http://example.com/news/2013/08/23/10086/ 居然是404, 找不到这个新闻, 到数据库中一看, 实际上是存在这条新闻的, 但是为什么就是看不到这个新闻呢?
经过看文档和django源码, 我终于找到了原因:
先看News model的简单定义:
class News(models.Model): title = models.CharField(max_length=200) pub_date = models.DateTimeField('date published',blank=True,default=timezone.now) content = models.TextField() def get_absolute_url(self): return "/news/%s/%d/" % (self.pub_date.strftime("%Y/%m/%d").lower(), self.pk)
1.可以看到, pub_date我已经让它默认使用django的timezone.now函数来获取默认时间了(这个时间是支持timezone的, 这个timezone的值, 就是 settings.py中定义的 TIME_ZONE = 'Asia/Shanghai' (中国只有2个时区字符串, 一个是上海'Asia/Shanghai', 一个是重庆'Asia/Chongqing', 以前的政府所在地, 千万不要用北京, 这个在国际标准中是不存在的)
2. 那么self.pub_date应该是django中的aware_time了, 那么这个self.pub_date 的date 为啥不对, 导致找不到这条新闻呢?原因后来我终于发现了, django 在存储 self.pub_date到数据库的时候, 好像是保存为 UTC 时区的, 也就是说这个self.pub_date和你的服务器项目的settings.py中设置好的时区 'Asia/Shanghai' 是不一样的, 也就是说, 最后得到的date可能不是同一天. 所以
self.pub_date.strftime("%Y/%m/%d") 获得的日期的表示, 可能不是你的时区的日期, 而是UTC时区的日期
这里, 你的时区的日期只的是你的服务器的项目设置里面的时区, 'Asia/Shanghai' ,我设置为这个, 肯定是以服务器时间为准的, 因此, 用户访问 新闻/日期/id 的时候, 这个日期不是服务器时区的日期的时候, 会发现出现404错误. 不过因为只有8小时的时差, 这种错误有时候不会出现. 因为差了8小时也可能是同一天. 如果是凌晨1点发的, 差8小时可能就会在日期上相隔一天.因此就出现了错误.
那么你肯定要说, 那为什么不以数据库中保存的utc时区来生成url呢, 这样就不会有时区的差别了. 实际上我上面的代码就是这么做的, 那么为什么还会在date日期上有差别呢?通过找源码, 我发现了在 djangoviewsgenericdates.py 文件的292行开始的2个函数里
class DateMixin(object): 里 def _make_date_lookup_arg(self, value): """ Convert a date into a datetime when the date field is a DateTimeField. When time zone support is enabled, date is assumed to be in the current time zone, so that displayed items are consistent with the URL. """ if self.uses_datetime_field: value = datetime.datetime.combine(value, datetime.time.min) if settings.USE_TZ: value = timezone.make_aware(value, timezone.get_current_timezone()) return value def _make_single_date_lookup(self, date): """ Get the lookup kwargs for filtering on a single date. If the date field is a DateTimeField, we can't just filter on date_field=date because that doesn't take the time into account. """ print date date_field = self.get_date_field() print date_field if self.uses_datetime_field: since = self._make_date_lookup_arg(date) until = self._make_date_lookup_arg(date + datetime.timedelta(days=1)) print ' since',since print ' until',until return { '%sgte' % date_field: since, '%slt' % date_field: until, } else: # Skip self._make_date_lookup_arg, it's a no-op in this branch. return {date_field: date}
注意since 和 until, 也就是BaseDateDetailView中的get_object 最后会调用这2个函数, 实际上
BaseDateDetailView是对 新闻/年/月/日/id 进行分解调用, 解析出了 请求的url中的年与日, 再组合成 2013-08-23 这样的字符串, 然后在数据库中进行过滤, 取得 2013-08-23 到 2013-08-24 日期之间的所有新闻集, 再在这个新闻集中找 具有id的新闻.
问题就是
since 2013-08-23 00:00:00+08:00 until 2013-08-24 00:00:00+08:00
这种时间是时区为 asia/shanghai 的, 也就是你的settings.py中设置的时区, 和UTC时区相差了8个小时, 因此将数据库中的UTC时区的日期按照
settings.py中设置的时区Asia/Shanghai 来过滤, 结果居然没有这一天的新闻.
那么解决的办法就是修改 url 中的年月日生成方式, 按照 settings.py中设置好的时区, 来生成年月日的url
因此, 按照settings.py中设置好的时区, 来更正url中的年月日, 就不会再出现问题了.
def get_absolute_url(self): # 获取settings中的时区 current_tz = timezone.get_current_timezone() # 按照该时区格式化数据库中存储的UTC时区时间self.pub_date为 settings中的时区 db_local_time = current_tz.normalize(self.pub_date) # 取出date()并生成url return "/news/%s/%d/" % (db_local_time.date().strftime("%Y/%m/%d").lower(), self.pk)
来自:http://ddtcms.com/blog/archive/2013/8/23/84/django-timezone-usage-log/
更多阅读
互联网的典型应用有哪些? 互联网金融典型案例
互联网的典型应用有哪些?——简介Internet起源于美国国防部高级研究计划署DARPA的前身ARPAnet,该网于1969年投入使用。现在它已经渗透进了人们日常的学习、工作、生活、娱乐等各个方面,为我们带来了前所未有的方便。那么互联网的典型应
不是有效的win32应用程序怎么解决 不是win32文件
不是有效的win32应用程序怎么解决——简介有时,用户在双击安装某个软件时,经常会弹出“XX不是有效Win32应用程序”的错误提示。即使我们双击运行任意一个EXE格式的可执行文件,可能同样会出现这样的错误提示。那么如何解决“不是有效的w
Excel数据透视表的日常应用技巧 精 皮皮麻将透视技巧
对工作表中数据进行统计是经常需要的。一般情况我们都是使用菜单命令或函数来进行数据的统计的。可是如果要统计的工作表中记录很多,而且需要统计的项目也很多时,使用这种方法就显得力不从心了。请问还有什么更好的方法来实现吗?接下来
《Word97吴氏打印简谱法》的快捷应用 拳皇97快捷键
《Word97吴氏打印简谱法》的快捷应用不用“打谱软件”只用Word就能打印出歌谱无疑给广大音乐爱好者开辟了新天地。经过几年的使用和积累,使用复制、粘贴、模板应用等手法,使打谱的速度和质量有了显著的提高。一、简谱的基本组成就是
旋风分离器的工业应用1/2 旋风分离器
旋风分离器的工业应用一般有四大类。理解这些种类的工业应用间的区别,认识如何对一个既定的工业应用选择最为适合的旋风分离器,在对其进行合理正确选择时是非常重要的。四个主要的工业应用种类为:控制空气污染、工艺设备、作为预分离器