pytz模块-时区处理

时区介绍

近日做处理时区相关的问题,发觉通常用到的时区有:标准本地时区 和 根据日夜计算的平均本地时区,这个都是和utc时区相差的时间。

举个例如:例如Asia/Shanghai这个时区和utc相差8小时6分,如果使用pytz.timezone('Asia/Shanghai')生成的时区对象时LMT时间,LMT学名Local Mean Time,用于比较平均日出时间的。

然而标准的时区时间可以和utc相差8小时,对于在中国而然,就是CST时间,Chinese Standard Time。

为什么要使用utc时区

这一次,我看到数据库里面的时间用的是utc时区的时间,然后想了下,为什么要用utc时间呢,我觉得:

  • utc是国际标准时间,很多时区的时间是根据它来划分的
  • 通用性:时区用的是utc时间,如果做数据转移,放在其他地区也是适用的。

pytz的使用

timezone, localize, normalize, astimezone

# 获取tz对象
tz = pytz.timezone('Asia/Shanghai')

# 创建一个日期
now = datetime.datetime.now()
## output: datetime.datetime(2015, 12, 20, 23, 20, 2, 849032)

# localize是将没有时区的日期转换为对应本地时区的日期
tz.localize(now)
## output: datetime.datetime(2015, 12, 20, 23, 20, 2, 849032, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)

# normalize是将带有时区的时间转换成对应时区的时间
pytz.utc.normalize(tz.localize(now))
## output: datetime.datetime(2015, 12, 20, 15, 20, 2, 849032, tzinfo=<UTC>)

# astimezone是使用当地时区平均时区的时间进行计算
now.replace(tzinfo=tz)
## output: datetime.datetime(2015, 12, 20, 23, 20, 2, 849032, tzinfo=<DstTzInfo 'Asia/Shanghai' LMT+8:06:00 STD>)

now.replace(tzinfo=tz).astimezone(pytz.utc)
## output: datetime.datetime(2015, 12, 20, 15, 14, 2, 849032, tzinfo=<UTC>)

code>
pre>

与标准时间相比,相差了6分钟,原因就是设定timezone的方法不对,不能使用replace方法,astimezone是datetime对象的转换时间的方法

2016-07-28补

注意夏令时/冬令时问题

下面是pytz文档上的:

In addition, if you perform date arithmetic on local times that cross DST boundaries, the result may be in an incorrect timezone (ie. subtract 1 minute from 2002-10-27 1:00 EST and you get 2002-10-27 0:59 EST instead of the correct 2002-10-27 1:59 EDT). A normalize() method is provided to correct this.

关于夏令时的说明

下面引用<扬总>代码:

In [20]: from datetime import timedelta

In [21]: from pytz import timezone

In [22]: from dateutil import parser

In [23]:

In [23]: naive_dt = parser.parse('2016-03-27')

In [24]: print naive_dt
2016-03-27 00:00:00

In [25]: tz = timezone('Europe/Berlin')

In [26]: aware_dt27 = tz.localize(naive_dt)

In [27]:

In [27]: print aware_dt27, aware_dt27 + timedelta(days=1)
2016-03-27 00:00:00+01:00 2016-03-28 00:00:00+01:00

In [28]:

In [28]: print aware_dt27, tz.normalize(aware_dt27 + timedelta(days=1))
2016-03-27 00:00:00+01:00 2016-03-28 01:00:00+02:00

In [29]:

In [29]: print aware_dt27, tz.localize(naive_dt + timedelta(days=1))
2016-03-27 00:00:00+01:00 2016-03-28 00:00:00+02:00

3月27日~3月28刚好是冬令时转夏令时,导致代码中的3.28使用normalize处理,时间要比想象的往前1小时,pytz使用normalize能处理这个夏令时问题,但是如果你不想要这样子处理,就要注意了。

参考来自:Glow 技术团队博客