Python中的timezone
1、问题来源
最近折腾django做网站,发现存储到数据库中的时间在本机和vps上显示出来是不一样的。牵引出时区的相关问题。
2、时区的作用
一言以蔽之,就是世界通用。
单独一个时间,没有时区信息,可能不同地方的人会觉得是不同的时间。没有时区的时间可以认作是信息不全的。
假如去国外参加一个国际会议,时区用错,岂不白瞎。
3、哪个时区最通用
UTC时间。这里加了“最”。。。。为啥这么说。有2个原因。
1). pytz官方文档说了些内容。链接在这。
The major problem we have to deal with is that certain datetimes may occur twice in a year. For example, in the US/Eastern timezone on the last Sunday morning in October, the following sequence happens:
01:00 EDT occurs
1 hour later, instead of 2:00am the clock is turned back 1 hour and 01:00 happens again (this time 01:00 EST)
In fact, every instant between 01:00 and 02:00 occurs twice. This means that if you try and create a time in the ‘US/Eastern’ timezone the standard datetime syntax, there is no way to specify if you meant before of after the end-of-daylight-saving-time transition.
大意是某时区某天的某个时间一年内会出现2次。转换时间、初始化时间可能会出时差。。。。具体没有深究其内部原理。。。。
2). 某些时区名字未统一
比如你用某些字符串如”CST”、”CCT”、”PRC”表示某个时区。可能会有歧义然后导致时区设定失败。或者你用pytz构造的时区来设定时区,也很有可能会设置失败。还是pytz的doc文档指出的。
Unfortunately using the tzinfo argument of the standard datetime constructors ‘’does not work’’ with pytz for many timezones.
所以,如果带时区,原始的数据还是以UTC格式存储比较好。显示时可以转换为指定时区再格式化成字符串。
4、Python中时区相关库
推荐顺序,dateutil > pytz > datetime。
1) dateutil
解析时间
- 不用去操心strptime的格式了。模块自己推导。
- 可以在解析时就附加上时区信息。
>>> from dateutil.parser import parse
>>> parse("2018 01-06 10:32")
datetime.datetime(2018, 1, 6, 10, 32)
>>> parse("18 01-06 10:32")
datetime.datetime(2006, 1, 18, 10, 32)
>>> parse("2018 01 06 10:32")
datetime.datetime(2018, 1, 6, 10, 32)
>>> parse(" 10:32")
datetime.datetime(2018, 1, 8, 10, 32)
>>> from dateutil.tz import gettz,tzlocal
>>> tzinfos = {"BRST": -10800, "CST": gettz("America/Chicago")}
>>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST',
-10800))
>>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
datetime.datetime(2012, 1, 19, 17,21,tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))
- 获取当前时区
from datetime import datetime
from dateutil.tz import *
>>> datetime.now(tzlocal()).tzname()
'CST'
- 构造一个指定时区
>>> from dateutil.tz import *
>>> gettz("Asia/Shanghai")
tzfile('/usr/share/zoneinfo/Asia/Shanghai')
2)pytz
- 构造时区
>>> pytz.timezone("Asia/Shanghai")
<DstTzInfo 'Asia/Shanghai' LMT+8:06:00 STD>
3)datetime
- 转换时区 ——- astimezone
>>> from datetime import datetime
>>> datetime.now()
datetime.datetime(2018, 1, 8, 21, 18, 59, 8709)
>>> datetime.now().astimezone(pytz.timezone("UTC"))
datetime.datetime(2018, 1, 8, 13, 19, 14, 831614, tzinfo=<UTC>)