关于 django 在 views 里面 timezone 的疑问? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
hao1032
V2EX    Python

关于 django 在 views 里面 timezone 的疑问?

  •  
  •   hao1032 2016 年 9 月 5 日 4348 次点击
    这是一个创建于 3430 天前的主题,其中的信息可能已经有所发展或是发生改变。
    项目的相关配置:
    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': name,
    'USER': user,
    'PASSWORD': pwd,
    'HOST': host,
    'PORT': port,
    }
    }

    LANGUAGE_CODE = 'zh-CN'
    TIME_ZOnE= 'Asia/Shanghai'
    USE_I18N = True
    USE_L10N = True
    USE_TZ = True

    在 view 里面写的查询语句:
    now = timezone.now()
    query = models.AllItem.objects.filter(add_time__day=now.day)
    print query.count()

    生成的 sql :
    SELECT COUNT(*) AS `__count` FROM `allitem` WHERE EXTRACT(DAY FROM CONVERT_TZ(`allitem`.`add_time`, 'UTC', 'Asia/Shanghai')) = 5

    疑问:
    1.now 是用 timezone.now()获取的,这时 now 已经是 utc 时间
    2.由于配置中 USE_TZ 设置为 True ,那么保存在 add_time 里的时间也是 utc 时间( add time 在 model 中设置为 auto now add 为 True )

    那么,为什么在执行查询的时候, django 还要使用 CONVERT_TZ 函数去转换时间?导致我查询的结果都是错误的。

    真心求教真相。
    11 条回复    2016-09-09 13:21:41 +08:00
    tinypig
        1
    tinypig  
       2016 年 9 月 5 日
    from django.utils import timezone ?
    gkiwi
        2
    gkiwi  
       2016 年 9 月 5 日
    1.是对的
    2. 由于配置中 USE_TZ 设置为 True ,那么保存在 add_time 里的时间也是 utc 时间( add time 在 model 中设置为 auto now add 为 True )
    这个是不对的,参照这里: https://docs.djangoproject.com/en/1.10/ref/settings/#time-zone

    This allows interacting with third-party databases that store datetimes in local time rather than UTC. To avoid issues around DST changes, you shouldn ’ t set this option for databases managed by Django.

    When USE_TZ is Trueand the database doesn ’ t support time zones (e.g. SQLite, MySQL, Oracle), Django reads and writes datetimes in local time according to this option if it is set and in UTC if it isn ’ t.


    也就是说你数据库里面的存在不是 UTC ,而是基于 TIME_ZONE 的地区时间;所以后面才有 CONVERT_TZ 的时区转换;
    gkiwi
        3
    gkiwi  
       2016 年 9 月 5 日


    django.db.backends.mysql _convert_field_to_tz
    hao1032
        4
    hao1032  
    OP
       2016 年 9 月 6 日
    @gkiwi 感谢你的回复,一看就是常用 Django 的。我用的 Django 是 1.8 的版本,在对应的文档中没有 1.10 中描述: https://docs.djangoproject.com/en/1.8/ref/settings/#time-zone
    我在 site-packages\django\db\backends\mysql 这个文件夹下的 py 文件里面也没有找到你截图的函数。
    那么在 1.8 版本中的处理是否也是你解释的这样呢?
    gkiwi
        5
    gkiwi  
       2016 年 9 月 6 日
    @hao1032

    抱歉关于 TIME_ZONE 这个理解错了。


    整体重新说一下,虽然 1.8 版本的说明和 1.9 , 1.10 不一样,但是数据库存储的时间都是标准的 UTC 时间。(之前说的是存储的是基于 TIME_ZONE 的时间,这个是错误的)

    我本地跑了下 1.8 , 1.9 ,分别设置 TIME_ZONE 为「 UTC 」和「 Asia/Shanghai 」,后台登陆,看数据库里面的时间,也确实是 UTC 时间,现在我电脑时间是, 2016 年 09 月 06 日 12:22:37 ,但是数据库中存储的都是凌晨 4 点的,正好-8 ;

    至于你的为什么会出现 CONVERT_TZ ,是因为你开启了 USE_TIME 。
    你用的 now.day 是 UTC 时间,而 Django 认为这个时间是 TIME_ZONE 时间;
    所以生成 sql 时候,先把数据库中数据时间,转成 TIME_ZONE 时间,然后和你的 day 进行比较;

    所以你应该使用


    from django.conf import settings
    from django.utils import timezone
    import pytz

    now = timezone.now()
    tzinfo = pytz.timezone(settings.TIME_ZONE)
    now = now.replace(tzinfo=tzinfo)


    然后传入此时的 now.day ,获取到的应该就是正确的数据了
    gkiwi
        6
    gkiwi  
       2016 年 9 月 6 日
    append :

    源码部分, django/db/backends/mysql/operations.py , 1.8 和 1.9 处理逻辑一致;
    如果是 linux 的话,可以用 ack 搜下 CONVERT_TZ 就出来了。
    gkiwi
        7
    gkiwi  
       2016 年 9 月 6 日
    USE_TIME ==> USE_TZ
    gkiwi
        8
    gkiwi  
       2016 年 9 月 6 日
    如果你服务器时间就是 Asia/Shanghai 的话,直接使用 datetime.now()就好了;
    hao1032
        9
    hao1032  
    OP
       2016 年 9 月 9 日
    @gkiwi 最后我也发现问题了, now 使用 timezone.localtime(timezone.now()) 这样转换一下就行。

    我就是疑惑,就像你说的‘你用的 now.day 是 UTC 时间,而 Django 认为这个时间是 TIME_ZONE 时间;’
    django 为什么会把 utc 时间理解为 localtime ,这是一个 django 的 bug ,还是就是这样设计的?
    gkiwi
        10
    gkiwi  
       2016 年 9 月 9 日   1
    @hao1032 不是 bug ;
    你传入的是 now.day ,这个是个 int~~
    hao1032
        11
    hao1032  
    OP
       2016 年 9 月 9 日
    @gkiwi 有道理,多谢。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5624 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 02:59 PVG 10:59 LAX 18:59 JFK 21:59
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86