BLOG
Enjoy when you can, and endure when you must.
FEB 13, 2014/Python
Python中时间字符串的转换和时区的处理

在Python中,与时间相关的库有好些,可以帮助我们快速的处理与时间相关的需求和问题。

这里想和大家分享一下如何将时间字符串转换为datetime以方便使用和处理。

其实相关的文章可以找到很多,不过感觉很多介绍的是类似于“2014-02-13 20:53:21”这样的时间,这借助于datetime标准库中的strptime方法即可快速转换。不过如果是遇到ISO 8601中有一种日期和时间的组合表示法所表示的时间,如:

2014-02-13 17:33:41.817981+08:00

这里面还包含着时区,处理起来貌似要麻烦一点。

其实我们无非是需要构造时间的每个部分,因此可以找一些方法将以上时间字符串分解开来,然后再用datetime中的方法来构造时间即可。以下是django中的一个实现方法,学习一下还是很不错:

import datetime
import re
import pytz


datetime_re = re.compile(
    r'(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})'
    r'[T ](?P<hour>\d{1,2}):(?P<minute>\d{1,2})'
    r'(?::(?P<second>\d{1,2})(?:\.(?P<microsecond>\d{1,6})\d{0,6})?)?'
    r'(?P<tzinfo>Z|[+-]\d{2}:?\d{2})?$'
)

def parse_datetime(value):
    match = datetime_re.match(value)
    if match:
        kw = match.groupdict()
        if kw['microsecond']:
            kw['microsecond'] = kw['microsecond'].ljust(6, '0')
        tzinfo = kw.pop('tzinfo')
        if tzinfo == 'Z':
            tzinfo = pytz.utc
        elif tzinfo is not None:
            offset = 60 * int(tzinfo[1:3]) + int(tzinfo[-2:])
            if tzinfo[0] == '-':
                offset = -offset
            tzinfo = FixedOffset(offset)
        kw = dict((k, int(v)) for k, v in six.iteritems(kw) if v is not None)
        kw['tzinfo'] = tzinfo
        return datetime.datetime(**kw)

这里使用正则匹配获取到时间的各个部分,然后构造tzinfo,其中的FixedOffset代码如下:

from datetime import timedelta, tzinfo

class FixedOffset(tzinfo):
    "Fixed offset in minutes east from UTC."
    def __init__(self, offset):
        if isinstance(offset, timedelta):
            self.__offset = offset
            offset = self.__offset.seconds // 60
        else:
            self.__offset = timedelta(minutes=offset)

        sign = '-' if offset < 0 else '+'
        self.__name = "%s%02d%02d" % (sign, abs(offset) / 60., abs(offset) % 60)

    def __repr__(self):
        return self.__name

    def __getinitargs__(self):
        return self.__offset,

    def utcoffset(self, dt):
        return self.__offset

    def tzname(self, dt):
        return self.__name

    def dst(self, dt):
        return timedelta(0)

这样就可以很顺利的得到datetime对象了。

另外,一个很好的第三方包也为我们想到了这一点,那就是python-dateutil,它里面提供的方法也只需要我们将字符串传入即可得到想要的结果,使用示例如下:

>>> import dateutil.parse
>>> t = dateutil.parser.parse('2014-02-13 17:33:41.817981+08:00')
>>> t
datetime.datetime(2014, 2, 13, 17, 33, 41, 817981, tzinfo=tzoffset(None, 28800))

最后再分享一下时区转换:

>>> from dateutil import tz
>>> utc = tz.tzutc()
>>> t.astimezone(utc)
datetime.datetime(2014, 2, 13, 9, 33, 41, 817981, tzinfo=tzutc())
>>> to_zone = tz.gettz('America/Chicago')
>>> t.astimezone(to_zone)
datetime.datetime(2014, 2, 13, 3, 33, 41, 817981, tzinfo=tzfile('America/Chicago'))
COMMENTS
LEAVE COMMNT