【问题标题】:Strange Timezone behaviour Django奇怪的时区行为 Django
【发布时间】:2017-03-23 23:44:10
【问题描述】:

这里有些奇怪,我无法理解:

鉴于这些设置:

>>> from django.conf import settings
>>> settings.TIME_ZONE
'Europe/London'
>>> settings.USE_TZ
False

给定模型:

HALF_YEAR = timedelta(days=30*6)

class ProductManager(models.Manager):
    def get_queryset(self):
        from_date = datetime.now() - HALF_YEAR
        return super(ProductManager, self).get_queryset().filter(start_date_time__gt=from_date)

class Product(models.Model):
    product_number = models.CharField(max_length=45)
    start_date_time = models.DateTimeField()
    cover_renewal_date = models.DateField()
    objects = ProductManager()

这给了我们数据库表:

shopapp=>\d shop_product

        Column         |           Type           |                        Modifiers
-----------------------+--------------------------+----------------------------------------------------------
 id                    | integer                  | not null default nextval('shop_product_id_seq'::regclass)
 product_number        | character varying(45)    | not null
 start_date_time       | timestamp with time zone | not null


shopapp=> show timezone;
 TimeZone
----------
 UTC
(1 row)

有以下数据:

        shopapp=> select product_number, start_date_time 
from shop_product 
where product_number in ('PN63145707', 'PN57284554', 'PN57291674', 'PN66177827');

 product_number | start_date_time
---------------+------------------------
 PN57284554     | 2013-04-05 00:00:00+00
 PN57284554     | 2014-04-05 00:00:00+00
 PN57284554     | 2015-04-05 00:00:00+00
 PN57284554     | 2016-04-05 00:00:00+00
 PN57284554     | 2017-04-05 00:00:00+00
 PN57291674     | 2013-04-04 00:00:00+00
 PN57291674     | 2014-04-04 00:00:00+00
 PN57291674     | 2015-04-04 00:00:00+00
 PN57291674     | 2016-04-04 00:00:00+00
 PN57291674     | 2017-04-04 00:00:00+00
 PN63145707     | 2015-03-25 00:00:00+00
 PN63145707     | 2016-03-25 00:00:00+00
 PN63145707     | 2017-03-25 00:00:00+00
 PN66177827     | 2017-03-25 00:00:00+00
(14 rows)

但是运行这段代码:

now = datetime.now().date()
start_time = now - timedelta(days=1)
end_time = now + timedelta(days=14)
res = Product.objects.filter(start_date_time__range=(start_time, end_time), product_number__in=['PN63145707', 'PN57284554', 'PN57291674', 'PN66177827'])
for item in res:
    print(item.product_number, str(item.start_date_time))

给我结果

(u'PN63145707', '2017-03-25 00:00:00')
(u'PN57284554', '2017-04-05 01:00:00')
(u'PN57291674', '2017-04-04 01:00:00')
(u'PN66177827', '2017-03-25 00:00:00')

BST(3 月 26 日)之后的任何 start_date_time 似乎都显示为凌晨 1 点。如果 USE_TZ 设置为 False,为什么会这样?

谢谢。

版本: django-1.10.4, postgresql psql (9.4.10, 服务器 9.6.1)

编辑: 当我在我们的测试服务器上以相同的设置运行相同的代码时,结果是不一样的:

In [20]: settings.TIME_ZONE
Out[20]: 'Europe/London'

In [21]: settings.USE_TZ
Out[21]: False

(u'PN63145707', '2017-03-25 00:00:00')
(u'PN66177827', '2017-03-25 00:00:00')
(u'PN57291674', '2017-04-04 00:00:00')
(u'PN57284554', '2017-04-05 00:00:00')

为什么这些记录没有像生产服务器上的值一样调整为欧洲/伦敦时区?

【问题讨论】:

  • 忘了说-(很明显)-我在本地看不到这种行为,只有在我部署到生产环境之后。

标签: python django postgresql django-orm


【解决方案1】:

您看到的行为与documentation 中描述的完全一样。这是 Django 坚持使用 postgresql timestamptz 而不是 timestamp 的副产品。

在内部,Postgresql timestamptz 以 UTC 格式存储日期时间。查询时返回转换为请求者时区的时间戳。

documentation 指出,当USE_TZ 设置为false 时,数据库连接时区将设置为TIMEZONE(或欧洲/伦敦在您的情况下)。这将导致 Postgresql 将存储的 UTC 时间戳转换为伦敦时间,然后再将它们提供给 Django。

【讨论】:

  • 明白。根据您的说法,prod 服务器的行为正确(我同意)。但是请查看我的编辑 - 我想问题是测试服务器是否无法转换回时区
  • 我想我知道为什么,测试服务器在 Ubuntu 14.04 上运行,而 Prod 正在运行 Ubuntu 16.04 - 操作系统时区设置会有所不同吗?
  • 在您的测试服务器案例中,检查 postgresql 中的实际 UTC 日期是什么...timestamptz 是一个敢于尝试的恶魔,它在存储日期时将日期转换为 UTC(使用连接时区如果没有日期本身),然后在查询时再次返回。如果您在 dev/prod 中插入和选择没有使用相同的时区,您将看到系统之间的差异。
【解决方案2】:

datetime.now() 返回当前的本地日期和时间,在您的情况下,它返回的是生产服务器的日期和时间。您应该将其转换为您的特定时区Europe/London,或者您可以使用django.utils.timezone.now,这将尊重您的settings.py 配置:

from django.utils import timezone
now = timezone.now().date()

请注意,django.utils.timezone.now 的行为因USE_TZ 的值而异

【讨论】:

    猜你喜欢
    • 2012-07-01
    • 2017-01-30
    • 2014-09-27
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多