在通过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)