2009-05-19 34 views
21

Tôi có một ngày của biểu mẫu được chỉ định bởi RFC 2822 - nói Fri, 15 May 2009 17:58:28 +0000, dưới dạng một chuỗi. Có một cách nhanh chóng và/hoặc tiêu chuẩn để có được nó như là một đối tượng datetime trong Python 2,5? Tôi đã cố gắng tạo ra một chuỗi định dạng strptime, nhưng trình xác định múi giờ +0000 gây nhầm lẫn cho trình phân tích cú pháp.Làm thế nào để phân tích ngày/giờ RFC 2822 thành một datetime Python?

Trả lời

27

Vấn đề là phân tích cú pháp sẽ bỏ qua bù trừ.

Làm điều này thay vì:

from email.utils import parsedate_tz 
print parsedate_tz('Fri, 15 May 2009 17:58:28 +0700') 
8

Có chức năng được phân tích cú pháp trong email.util. Nó phân tích tất cả các ngày RFC 2822 hợp lệ và một số trường hợp đặc biệt.

12
from email.utils import parsedate 
print parsedate('Fri, 15 May 2009 17:58:28 +0000') 

Documentation.

+0

+1 Tôi không biết về chức năng này, thực sự gọn gàng. –

+0

Cảm ơn bạn; điều đó có hiệu quả. :) – millenomi

7

Tôi muốn xây dựng trên câu trả lời trước. email.utils.parsedateemail.utils.parsedate_tz cả hai trở lại tuples, kể từ khi OP cần một đối tượng datetime.datetime, tôi thêm những ví dụ cho đầy đủ:

from email.utils import parsedate 
from datetime import datetime 
import time 

t = parsedate('Sun, 14 Jul 2013 20:14:30 -0000') 
d1 = datetime.fromtimestamp(time.mktime(t)) 

Hoặc:

d2 = datetime.datetime(*t[:6]) 

Lưu ý rằng d1d2 là cả hai đối tượng datetime ngây thơ , không có thông tin múi giờ nào được lưu trữ. Nếu bạn cần biết các đối tượng datetime, hãy kiểm tra tzinfodatetime() arg.

Hoặc bạn có thể sử dụng các mô-đun dateutil

4

Dường như Python 3.3 đi về phía trước có một phương pháp mới parsedate_to_datetime trong email.utils rằng sẽ chăm sóc của các bước trung gian:

email.utils. parsedate_to_datetime (ngày)

Nghịch đảo của format_datetime(). Thực hiện cùng chức năng như được phân tích cú pháp(), nhưng trên thành công trả về một ngày giờ. Nếu ngày đầu vào có múi giờ là -0000, ngày giờ sẽ là ngày giờ ngây thơ và nếu ngày đó tuân thủ đối với RFC, nó sẽ đại diện cho một thời gian trong UTC nhưng không có dấu hiệu của múi giờ nguồn thực của thư ngày bắt đầu. Nếu ngày nhập có bất kỳ chênh lệch múi giờ hợp lệ nào khác, thì giờ làm việc sẽ là một ngày giờ nhận thức với tzinfo múi giờ tương ứng.

Tính năng mới trong phiên bản 3.3.

http://python.readthedocs.org/en/latest/library/email.util.html#email.utils.parsedate_to_datetime

1

email.utils.parsedate_tz(date) là chức năng để sử dụng. Sau đây là một số biến thể.

Email chuỗi ngày/giờ (RFC 5322, RFC 2822, RFC 1123) để unix timestamp trong vài giây float:

import email.utils 
import calendar 
def email_time_to_timestamp(s): 
    tt = email.utils.parsedate_tz(s) 
    if tt is None: return None 
    return calendar.timegm(tt) - tt[9] 

import time 
print(time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(email_time_to_timestamp("Wed, 04 Jan 2017 09:55:45 -0800")))) 
# 2017-01-04T17:55:45Z 

Hãy chắc chắn rằng bạn không sử dụngmktime (mà diễn giải time_struct theo giờ địa phương của máy tính, không phải là UTC); sử dụng timegm hoặc mktime_tz thay thế (nhưng hãy cẩn thận trước cho mktime_tz trong đoạn tiếp theo).

Nếu bạn chắc chắn rằng mình có phiên bản python 2.7.4, 3.2.4, 3.3 hoặc mới hơn, thì bạn có thể sử dụng email.utils.mktime_tz(tt) thay vì calendar.timegm(tt) - tt[9]. Trước đó, mktime_tz cung cấp thời gian không chính xác khi được gọi trong quá trình chuyển đổi tiết kiệm ánh sáng ban ngày mùa thu của múi giờ địa phương (bug 14653).

Nhờ @ j-f-sebastian cho caveats about mktime and mktime_tz.

ngày Email/chuỗi thời gian (RFC 5322, RFC 2822, RFC 1123) để “nhận thức” datetime trên python 3.3:

On python 3.3 trở lên, sử dụng email.utils.parsedate_to_datetime, mà trả về một ý thức datetime với vùng gốc offset:

import email.utils 
email.utils.parsedate_to_datetime(s) 

print(email.utils.parsedate_to_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat()) 
# 2017-01-04T09:55:45-08:00 

Lưu ý: điều này sẽ ném ValueError nếu thời gian rơi vào giây nhuận email.utils.parsedate_to_datetime("Sat, 31 Dec 2016 15:59:60 -0800").

ngày Email/lần chuỗi (RFC 5322, RFC 2822, RFC 1123) để “nhận thức” datetime trong khu UTC:

này chỉ chuyển đổi để đánh dấu thời gian và sau đó đến UTC datetime:

import email.utils 
import calendar 
import datetime 
def email_time_to_utc_datetime(s): 
    tt = email.utils.parsedate_tz(s) 
    if tt is None: return None 
    timestamp = calendar.timegm(tt) - tt[9] 
    return datetime.datetime.utcfromtimestamp(timestamp) 

print(email_time_to_utc_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat()) 
# 2017-01-04T17:55:45 

ngày Email/chuỗi thời gian (RFC 5322, RFC 2822, RFC 1123) để trăn “nhận thức” datetime với bù gốc:

Trước python 3.2, trăn không đi kèm với tzinfo triển khai, vì vậy đây là một ví dụ sử dụng dateutil.tz.tzoffset (pip install dateutil):

import email.utils 
import datetime 
import dateutil.tz 
def email_time_to_datetime(s): 
    tt = email.utils.parsedate_tz(s) 
    if tt is None: return None 
    tz = dateutil.tz.tzoffset("UTC%+02d%02d"%(tt[9]//60//60, tt[9]//60%60), tt[9]) 
    return datetime.datetime(*tt[:5]+(min(tt[5], 59),), tzinfo=tz) 

print(email_time_to_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat()) 
# 2017-01-04T09:55:45-08:00 

Nếu bạn đang sử dụng python 3.2, bạn có thể sử dụng được xây dựng trong tzinfo thực hiện datetime.timezone: tz = datetime.timezone(datetime.timedelta(seconds=tt[9])) thay vì bên thứ ba dateutil.tz.tzoffset.

Nhờ @ j-f-sebastian lần nữa for note on clamping the leap second.

Các vấn đề liên quan