关于python:从电子邮件解析带时区的日期?

Parsing date with timezone from an email?

我正在尝试从电子邮件中检索日期。一开始很容易:

1
2
3
message = email.parser.Parser().parse(file)
date = message['Date']
print date

我收到:

1
'Mon, 16 Nov 2009 13:32:02 +0100'

但我需要一个好的日期时间对象,所以我使用:

1
datetime.strptime('Mon, 16 Nov 2009 13:32:02 +0100', '%a, %d %b %Y %H:%M:%S %Z')

它使ValueError, since %Z isn't format for +0100上升。但是我在文档中找不到适合时区的格式,只有这个%Z代表时区。有人能帮我吗?


用途:email.utils.parsedate_tz(date)

1
2
3
4
5
6
7
8
9
msg=email.message_from_file(open(file_name))
date=None
date_str=msg.get('date')
if date_str:
    date_tuple=email.utils.parsedate_tz(date_str)
    if date_tuple:
        date=datetime.datetime.fromtimestamp(email.utils.mktime_tz(date_tuple))
if date:
    ... # valid date found


有一email.utilsparsedate()函数的格式是RFC 2822,只要我知道是不过时的。

1
2
3
4
5
6
7
8
9
>>> import email.utils
>>> import time
>>> import datetime
>>> email.utils.parsedate('Mon, 16 Nov 2009 13:32:02 +0100')
(2009, 11, 16, 13, 32, 2, 0, 1, -1)
>>> time.mktime((2009, 11, 16, 13, 32, 2, 0, 1, -1))
1258378322.0
>>> datetime.datetime.fromtimestamp(1258378322.0)
datetime.datetime(2009, 11, 16, 13, 32, 2)

请注意,但是,它是parsedate法不需要考虑的时间和本地区time.mktime时总是expects元组AS提到这里。

1
2
3
>>> (time.mktime(email.utils.parsedate('Mon, 16 Nov 2009 13:32:02 +0900')) ==
... time.mktime(email.utils.parsedate('Mon, 16 Nov 2009 13:32:02 +0100'))
True

所以你还需要解析出的时区当地时间和需要考虑的差分,太。

1
2
3
4
>>> REMOTE_TIME_ZONE_OFFSET = +9 * 60 * 60
>>> (time.mktime(email.utils.parsedate('Mon, 16 Nov 2009 13:32:02 +0900')) +
... time.timezone - REMOTE_TIME_ZONE_OFFSET)
1258410122.0


在Python email+3.3 CAN的报文头,为你解析:

1
2
3
4
5
6
import email
import email.policy

headers = email.message_from_file(file, policy=email.policy.default)
print(headers.get('date').datetime)
# -> 2009-11-16 13:32:02+01:00

因为Python 3.2 +,它有%Z:如果你%Zreplace

1
2
3
4
5
>>> from datetime import datetime
>>> datetime.strptime("Mon, 16 Nov 2009 13:32:02 +0100",
...                  "%a, %d %b %Y %H:%M:%S %z")
datetime.datetime(2009, 11, 16, 13, 32, 2,
                  tzinfo=datetime.timezone(datetime.timedelta(0, 3600)))

或使用email(Python包+3.3):

1
2
3
4
>>> from email.utils import parsedate_to_datetime
>>> parsedate_to_datetime("Mon, 16 Nov 2009 13:32:02 +0100")
datetime.datetime(2009, 11, 16, 13, 32, 2,
                  tzinfo=datetime.timezone(datetime.timedelta(0, 3600)))

如果是指定的-0000UTC偏移和天真的DateTime对象那就返回一个代表在UTC时间,否则它返回到一个相应的tzinfoDateTime对象集。

分析RFC 5322日期时间字符串在Python的早期版本(2 +):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from calendar import timegm
from datetime import datetime, timedelta, tzinfo
from email.utils import parsedate_tz

ZERO = timedelta(0)
time_string = 'Mon, 16 Nov 2009 13:32:02 +0100'
tt = parsedate_tz(time_string)
#NOTE: mktime_tz is broken on Python < 2.7.4,
#  see https://bugs.python.org/issue21267
timestamp = timegm(tt) - tt[9] # local time - utc offset == utc time
naive_utc_dt = datetime(1970, 1, 1) + timedelta(seconds=timestamp)
aware_utc_dt = naive_utc_dt.replace(tzinfo=FixedOffset(ZERO, 'UTC'))
aware_dt = aware_utc_dt.astimezone(FixedOffset(timedelta(seconds=tt[9])))
print(aware_utc_dt)
print(aware_dt)
# -> 2009-11-16 12:32:02+00:00
# -> 2009-11-16 13:32:02+01:00

FixedOffset是基于tzinfodatetime文档:收藏指正

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class FixedOffset(tzinfo):
   """Fixed UTC offset: `time = utc_time + utc_offset`."""
    def __init__(self, offset, name=None):
        self.__offset = offset
        if name is None:
            seconds = abs(offset).seconds
            assert abs(offset).days == 0
            hours, seconds = divmod(seconds, 3600)
            if offset < ZERO:
                hours = -hours
            minutes, seconds = divmod(seconds, 60)
            assert seconds == 0
            #NOTE: the last part is to remind about deprecated POSIX
            #  GMT+h timezones that have the opposite sign in the
            #  name; the corresponding numeric value is not used e.g.,
            #  no minutes
            self.__name = '<%+03d%02d>GMT%+d' % (hours, minutes, -hours)
        else:
            self.__name = name
    def utcoffset(self, dt=None):
        return self.__offset
    def tzname(self, dt=None):
        return self.__name
    def dst(self, dt=None):
        return ZERO
    def __repr__(self):
        return 'FixedOffset(%r, %r)' % (self.utcoffset(), self.tzname())

你可以使用Python 3个parsedate _到_ datetime函数:

1
2
3
4
>>> from email.utils import parsedate_to_datetime
>>> parsedate_to_datetime('Mon, 16 Nov 2009 13:32:02 +0100')
...
datetime.datetime(2009, 11, 16, 13, 32, 2, tzinfo=datetime.timezone(datetime.timedelta(0, 3600)))

你有没有试过

1
rfc822.parsedate_tz(date) # ?

更多在RFC822,http://docs.python.org /图书馆/ rfc822.html

它(现在是过时的parsedate _ TZ在email.utils.parsedate_tz),虽然。

但答案是:论文帮助

  • 如何解析一个日期字符串在Python的行动时区?

  • Python的时间timezones时代Part 2


1
2
3
4
5
6
7
8
9
10
11
12
# Parses Nginx' format of"01/Jan/1999:13:59:59 +0400"
# Unfortunately, strptime doesn't support %z for the UTC offset (despite what
# the docs actually say), hence the need # for this function.
def parseDate(dateStr):
    date = datetime.datetime.strptime(dateStr[:-6],"%d/%b/%Y:%H:%M:%S")
    offsetDir = dateStr[-5]
    offsetHours = int(dateStr[-4:-2])
    offsetMins = int(dateStr[-2:])
    if offsetDir =="-":
        offsetHours = -offsetHours
        offsetMins = -offsetMins
    return date + datetime.timedelta(hours=offsetHours, minutes=offsetMins)


对于那些想获得正确的本地时间,这是我做的:

1
2
3
4
5
6
7
8
from datetime import datetime
from email.utils import parsedate_to_datetime

mail_time_str = 'Mon, 16 Nov 2009 13:32:02 +0100'

local_time_str = datetime.fromtimestamp(parsedate_to_datetime(mail_time_str).timestamp()).strftime('%Y-%m-%d %H:%M:%S')

print(local_time_str)

ValueError: 'z' is a bad directive in format...

(注:我要到Python 2.7粘在我的案例)

我有类似的问题,在分析提交日期输出git log --date=iso8601这实际上不是一iso8601格式(四)以后的版本中添加--date=iso8601-strictA)。

因为我很有djangoI CAN杠杆定位工具。

http:/ / / / / github.com Django Django Django的BLOB /硕士/ dateparse.py/utils/

1
2
3
>>> from django.utils.dateparse import parse_datetime
>>> parse_datetime('2013-07-23T15:10:59.342107+01:00')
datetime.datetime(2013, 7, 23, 15, 10, 59, 342107, tzinfo=+0100)

"你可以用你自己的strptime正则表达式。