python中的UTC与本地时区处理

在通过sqlalchemy使用sqlite3数据库的过程中,发现日期时间字段默认值为CURRENT_TIMESTAMP,但是查出的值少了8个小时。很明显是遇到时区问题了。

mysql的TIMESTAMP字段类型和sqlite3一样使用UTC时间保存,因为在存取时自动进行了本地时间与UTC时间互转,所以不会遇到时区问题。但是sqlite3没有自动进行这一转换,需要在sql中自行转换:

select datetime(CURRENT_TIMESTAMP, 'localtime')

进一步google后,找到了这篇文章:《Dealing with Timezones in Python》,文章大意是python中的datetime库默认不携带时区信息,而加上时区后又与不带时区的datetime对象无法一起工作(如:比较),另外像datetime.datetime.utcnow()返回的utc时间和datetime.datetime.now()返回的本地时间也是不携带时区信息的(tzinfo属性为None),容易引起混淆,因此处理的简单性,内部最好统一使用UTC标准时间,和用户交互时再转换为本地时间。

下面是互转的算法:

#/usr/bin/env python

import datetime
import time
import sys

if sys.version >= '3.2.':
    localtimezone = datetime.timezone(datetime.timedelta(seconds=-time.timezone), time.tzname[0])
    utctimezone = datetime.timezone.utc
else:
    from dateutil import tz
    localtimezone = tz.tzlocal()
    utctimezone = tz.gettz('UTC')

def parsedatetime(dt, fmt="%Y-%m-%d %H:%M:%S"):
    """parse local datetime string as utc datetime object"""
    return datetime.datetime.strptime(dt, fmt).replace(tzinfo=localtimezone).astimezone(utctimezone)

def formatdatetime(dt, fmt="%Y-%m-%d %H:%M:%S"):
    """format utc datetime object as local datetime string"""
    return dt.replace(tzinfo=utctimezone).astimezone(localtimezone).strftime(fmt)

if __name__ == '__main__':
    input_local_datetime = '2012-01-02 03:04:05'
    parsed_utc_datetime = parsedatetime(input_local_datetime)
    assert(formatdatetime(parsed_utc_datetime) == input_local_datetime)