为什么Django设置时区为TIME_ZONE = Asia/Shanghai USE_TZ = True后,存入mysql中的时间只能是UTC时间

这个问题的解释还得看Django官方文档。其实是我理解错了,因为Mysql存储的时间不能灵活设置时区,不像datetime对象有一项参数专门指定时区,所以为了统一全球的时间,必须使用国际标准时间UTC,否则就会乱套。所有时间在存如数据库前,必须转换成UTC时间。比如北京时间8点,存入mysql变成0点(UTC)。

一般不跨时区的应用,可以不使用时区,即在settings.py设置

USE_TZ = False

这样存储的时间就是无时区的时间,英文叫naive datetime (datetime with no timezoneinformation)

一开始不理解,以为设了TIME_ZONE = ‘Asia/Shanghai’,数据库中存储的所有时间就会自动转为北京时间,或者数据库存储UTC时间在读取时自动转为北京时间(只有前台会自动转换,后台需要手动转换)。

看了官方文档,https://docs.djangoproject.com/en/2.1/topics/i18n/timezones/

当启用了时区支持时,Django在数据库中以UTC的形式存储日期时间信息,在内部使用可识别时区的日期时间对象,并在模板和表单中将它们转换为最终用户的时区。如果您的用户生活在多个时区,并且您想根据每个用户的挂钟显示日期时间信息,那么这是非常方便的。即使你的网站只在一个时区可用,在你的数据库中以UTC格式存储数据仍然是一个好习惯。主要原因是日光节约时间(DST)。许多国家都有夏时制,时钟在春天调快,在秋天调慢。如果你是在当地时间工作,你可能会遇到错误一年两次,当过渡发生的时候。(pytz文档更详细地讨论了这些问题。)这对你的博客来说可能并不重要,但如果你每年两次多收或少收一个小时的账单,那就有问题了。这个问题的解决方案是在代码中使用UTC,并且只在与最终用户交互时使用本地时间。默认情况下禁用时区支持。要启用它,请在设置文件中设置USE_TZ = True。时区支持使用pytz,它是在安装Django时安装的。

第一句话就醍醐灌顶:

Time zones¶

Overview¶

When support for time zones is enabled, Django stores datetime information inUTC in the database, uses time-zone-aware datetime objects internally, andtranslates them to the end user’s time zone in templates and forms.

翻译一下:当使用时区时,Django存储在数据库中的所有日期时间信息都以UTC时区为准,在后台使用有时区的datetime,前台用户使用时,在网页上翻译成用户所在的时区。
看完后,一切疑虑都消除了,不是Django设置有误,也不是Mysql设置有误。

使用时区相对来说比较麻烦,设置时区后,怎么让时区起作用呢?

Usage¶
I have a string “2012-02-21 10:28:45” and I know it’s in the"Europe/Helsinki" time zone. How do I turn that into an awaredatetime?

This is exactly what pytz is for.

from django.utils.dateparse import parse_datetime
naive = parse_datetime(“2012-02-21 10:28:45”)
import pytz
pytz.timezone(“Europe/Helsinki”).localize(naive, is_dst=None)
datetime.datetime(2012, 2, 21, 10, 28, 45, tzinfo=<DstTzInfo ‘Europe/Helsinki’ EET+2:00:00 STD>)
Note that localize is a pytz extension to the tzinfoAPI. Also, you may want to catch pytz.InvalidTimeError. Thedocumentation of pytz contains more examples. You should review itbefore attempting to manipulate aware datetimes.

How can I obtain the local time in the current time zone?

Well, the first question is, do you really need to?

You should only use local time when you’re interacting with humans, and thetemplate layer provides filters and tagsto convert datetimes to the time zone of your choice.

Furthermore, Python knows how to compare aware datetimes, taking intoaccount UTC offsets when necessary. It’s much easier (and possibly faster)to write all your model and view code in UTC. So, in most circumstances,the datetime in UTC returned by django.utils.timezone.now() will besufficient.

For the sake of completeness, though, if you really want the local timein the current time zone, here’s how you can obtain it:

from django.utils import timezone
timezone.localtime(timezone.now())
datetime.datetime(2012, 3, 3, 20, 10, 53, 873365, tzinfo=<DstTzInfo ‘Europe/Paris’ CET+1:00:00 STD>)
In this example, the current time zone is “Europe/Paris”.

我自己试了试从mysql取数后,在后台如何转换成当前时区,虽然官网说这样做没有必要,但是我想了解清楚:

sh = pytz.timezone(‘Asia/Shanghai’)
Mro.objects.first().TimeStamp.astimezone(sh)
datetime.datetime(2018, 4, 28, 8, 54, 4, tzinfo=<DstTzInfo ‘Asia/Shanghai’ CST+8:00:00 STD>)
Mro.objects.first().TimeStamp
datetime.datetime(2018, 4, 28, 0, 54, 4, tzinfo=)

后台向数据库输入日期时间时,日期时间应该带有时区信息,如果没有,输入数据库时会有警告,RuntimeWarning: DateTimeField received a naivedatetime (YYYY-MM-DD HH:MM:SS) while time zone support is active

可以使用pytz的localize将无时区信息的时间转为指定时区的datetime对象

具体的说明在pytz的官方说明中:

This library only supports two ways of building a localized time. Thefirst is to use the localize() method provided by the pytz library.This is used to localize a naive datetime (datetime with no timezoneinformation):

loc_dt = eastern.localize(datetime(2002, 10, 27, 6, 0, 0))
print(loc_dt.strftime(fmt))
2002-10-27 06:00:00 EST-0500
The second way of building a localized time is by converting an existinglocalized time using the standard astimezone() method:

ams_dt = loc_dt.astimezone(amsterdam)
ams_dt.strftime(fmt)
‘2002-10-27 12:00:00 CET+0100’
创建一个本地时间的两种方式:1、localize()将无时区的日期转为有时区的,2、astimezone()将有时区的日期时间从一个时区转为另一个时区。

This library also allows you to do date arithmetic using localtimes, although it is more complicated than working in UTC as youneed to use the normalize() method to handle daylight saving timeand other timezone transitions. In this example, loc_dt is setto the instant when daylight saving time ends in the US/Easterntimezone.

before = loc_dt - timedelta(minutes=10)
before.strftime(fmt)
‘2002-10-27 00:50:00 EST-0500’

eastern.normalize(before).strftime(fmt)
‘2002-10-27 01:50:00 EDT-0400’

after = eastern.normalize(before + timedelta(minutes=20))
after.strftime(fmt)
‘2002-10-27 01:10:00 EST-0500’
DST是Daylight Saving Time的缩写,即夏时制,夏时制的转换使用normalize()

夏时制在10月27日凌晨1点结束,所以0点50分时,使用夏时制转换函数转换后时间变为1点50,但1点10分再转换夏时制,结果还是1点10分。

实际上,按照Django的设计,不需要手动转换时区,而是再模板中加入语句,显示时区时自动转换。

Selecting the current time zone¶
The current time zone is the equivalent of the current locale for translations. However, there’s no equivalent of theAccept-Language HTTP header that Django could use to determine the user’stime zone automatically. Instead, Django provides time zone selectionfunctions. Use them to build the time zoneselection logic that makes sense for you.

Most websites that care about time zones just ask users in which time zone theylive and store this information in the user’s profile. For anonymous users,they use the time zone of their primary audience or UTC. pytz provideshelpers, like a list of time zones per country, that you can use to pre-selectthe most likely choices.

Here’s an example that stores the current timezone in the session. (It skipserror handling entirely for the sake of simplicity.)

Add the following middleware to MIDDLEWARE:

import pytz

from django.utils import timezone
from django.utils.deprecation import MiddlewareMixin

class TimezoneMiddleware(MiddlewareMixin):
def process_request(self, request):
tzname = request.session.get(‘django_timezone’)
if tzname:
timezone.activate(pytz.timezone(tzname))
else:
timezone.deactivate()
Create a view that can set the current timezone:

from django.shortcuts import redirect, render

def set_timezone(request):
if request.method == ‘POST’:
request.session[‘django_timezone’] = request.POST[‘timezone’]
return redirect(’/’)
else:
return render(request, ‘template.html’, {‘timezones’: pytz.common_timezones})
Include a form in template.html that will POST to this view:

{% load tz %}
{% get_current_timezone as TIME_ZONE %}

{% csrf_token %} {% for tz in timezones %}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值