Python strptime () và múi giờ?


157

Tôi có một tệp kết xuất CSV từ bản sao lưu Blackberry IPD, được tạo bằng IPDDump. Các chuỗi ngày / thời gian ở đây trông giống như thế này (nơi ESTlà múi giờ của Úc):

Tue Jun 22 07:46:22 EST 2010

Tôi cần có thể phân tích ngày này bằng Python. Lúc đầu, tôi đã thử sử dụng strptime()hàm từ datettime.

>>> datetime.datetime.strptime('Tue Jun 22 12:10:20 2010 EST', '%a %b %d %H:%M:%S %Y %Z')

Tuy nhiên, vì một số lý do, datetimeđối tượng quay trở lại dường như không có bất kỳ tzinfoliên quan nào với nó.

Tôi đã đọc trên trang này mà dường như datetime.strptimeâm thầm loại bỏ tzinfo, tuy nhiên, tôi đã kiểm tra tài liệu và tôi không thể tìm thấy bất cứ điều gì cho hiệu ứng đó được ghi lại ở đây .

Tôi đã có thể lấy ngày được phân tích cú pháp bằng thư viện Python của bên thứ ba, dateutil , tuy nhiên tôi vẫn tò mò về cách tôi sử dụng strptime()không đúng cách? Có cách nào strptime()để chơi độc đáo với múi giờ không?


1
Bạn không thể ... chuyển đổi tất cả các ngày sang GMT?
Robus

2
@Robus: Hmm, tôi đã hy vọng làm điều đó - nhưng tôi đã giả định rằng strftime / datetime bằng cách nào đó có thể làm điều đó? Dù bằng cách nào, tôi cần lưu trữ / phân tích thực tế rằng các mốc thời gian nằm trong múi giờ EST hoặc bất kỳ múi giờ nào chúng xảy ra với tôi. Kịch bản cần có khả năng phân tích thời gian dữ liệu chung với thông tin múi giờ (ví dụ ETC có thể là bất kỳ múi giờ nào khác).
victorhooi

3
EST cũng là tên viết tắt múi giờ của Hoa Kỳ. (Tương tự BST vừa là một từ viết tắt múi giờ của Anh và Brazil.) Các chữ viết tắt như vậy chỉ là mơ hồ. Thay vào đó, sử dụng bù đắp liên quan đến UTC / GMT. (Nếu bạn cần hỗ trợ viết tắt, bạn cần đặt bản đồ phụ thuộc vào bản đồ và đó là một lỗ chuột lộn xộn.)
Donal Fellows

Câu trả lời:


58

Các datetimetài liệu mô-đun nói:

Trả về một datetime tương ứng với date_ chuỗi, được phân tích cú pháp theo định dạng. Điều này tương đương với datetime(*(time.strptime(date_string, format)[0:6])).

Thấy [0:6]chưa Điều đó có được bạn (year, month, day, hour, minute, second). Không có gì khác. Không đề cập đến múi giờ.

Thật thú vị, [Win XP SP2, Python 2.6, 2.7] chuyển ví dụ của bạn sang time.strptimekhông hoạt động nhưng nếu bạn loại bỏ "% Z" và "EST" thì nó hoạt động. Cũng sử dụng "UTC" hoặc "GMT" thay vì "EST" hoạt động. "PST" và "MEZ" không hoạt động. Bối rối.

Điều đáng chú ý là điều này đã được cập nhật kể từ phiên bản 3.2 và hiện tại tài liệu tương tự cũng nêu rõ như sau:

Khi lệnh% z được cung cấp cho phương thức strptime (), một đối tượng datetime nhận thức sẽ được tạo ra. Tzinfo của kết quả sẽ được đặt thành một thể hiện múi giờ.

Lưu ý rằng điều này không hoạt động với% Z, vì vậy trường hợp này rất quan trọng. Xem ví dụ sau:

In [1]: from datetime import datetime

In [2]: start_time = datetime.strptime('2018-04-18-17-04-30-AEST','%Y-%m-%d-%H-%M-%S-%Z')

In [3]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: None

In [4]: start_time = datetime.strptime('2018-04-18-17-04-30-+1000','%Y-%m-%d-%H-%M-%S-%z')

In [5]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: UTC+10:00


353

Tôi khuyên bạn nên sử dụng python-dateutil . Trình phân tích cú pháp của nó đã có thể phân tích cú pháp mọi định dạng ngày mà tôi đã ném vào nó cho đến nay.

>>> from dateutil import parser
>>> parser.parse("Tue Jun 22 07:46:22 EST 2010")
datetime.datetime(2010, 6, 22, 7, 46, 22, tzinfo=tzlocal())
>>> parser.parse("Fri, 11 Nov 2011 03:18:09 -0400")
datetime.datetime(2011, 11, 11, 3, 18, 9, tzinfo=tzoffset(None, -14400))
>>> parser.parse("Sun")
datetime.datetime(2011, 12, 18, 0, 0)
>>> parser.parse("10-11-08")
datetime.datetime(2008, 10, 11, 0, 0)

và như thế. Không phải đối phó với strptime()định dạng vô nghĩa ... chỉ cần ném một ngày vào đó và nó đúng.

Cập nhật : Rất tiếc. Tôi đã bỏ lỡ trong câu hỏi ban đầu của bạn mà bạn đề cập rằng bạn đã sử dụng dateutil, xin lỗi về điều đó. Nhưng tôi hy vọng câu trả lời này vẫn hữu ích cho những người khác vấp phải câu hỏi này khi họ có câu hỏi phân tích ngày và xem tiện ích của mô-đun đó.


Cho rằng rất nhiều người có xu hướng sử dụng python-dateutil, tôi muốn chỉ cho chúng tôi một hạn chế của lib đó. >>> parser.parse("Thu, 25 Sep 2003 10:49:41,123 -0300") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Users/wanghq/awscli/lib/python2.7/site-packages/dateutil/parser.py", line 748, in parse return DEFAULTPARSER.parse(timestr, **kwargs) File "/Users/wanghq/awscli/lib/python2.7/site-packages/dateutil/parser.py", line 310, in parse res, skipped_tokens = self._parse(timestr, **kwargs) TypeError: 'NoneType' object is not iterable
wanghq

1
@wanghq bạn cần thay dấu phẩy cuối cùng bằng dấu chấm. Sau đóparser.parse("Thu, 25 Sep 2003 10:49:41.123 -0300") returns: datetime.datetime(2003, 9, 25, 10, 49, 41, 123000, tzinfo=tzoffset(None, -10800))
Flyingfoxlee

7
@fellingfoxlee, vâng, tôi hiểu điều đó. Tôi chỉ muốn nói với mọi người về giới hạn của python-dateutil. Nó làm những điều kỳ diệu, nhưng đôi khi không làm được điều đó. Vì vậy, "chỉ cần ném một ngày vào nó và nó không đúng." không đúng 100%
wanghq

4
dateutil.parser.parse("10-27-2016 09:06 AM PDT")trả về: datetime.datetime(2016, 10, 27, 9, 6)không tìm ra múi giờ ...
HaPsantran

2
Nó phụ thuộc vào mục tiêu của một người. dateutil parsercó thể đơn giản để sử dụng, nhưng strptime()nhanh hơn. Bên cạnh đó, định dạng của nó khá dễ học.
mừng

9

Chuỗi thời gian của bạn tương tự như định dạng thời gian trong rfc 2822 (định dạng ngày trong email, tiêu đề http) . Bạn có thể phân tích cú pháp bằng cách chỉ sử dụng stdlib:

>>> from email.utils import parsedate_tz
>>> parsedate_tz('Tue Jun 22 07:46:22 EST 2010')
(2010, 6, 22, 7, 46, 22, 0, 1, -1, -18000)

Xem các giải pháp mang lại các đối tượng thời gian nhận biết múi giờ cho các phiên bản Python khác nhau: phân tích ngày với múi giờ từ email .

Trong định dạng này, ESTlà tương đương về mặt ngữ nghĩa với-0500 . Mặc dù, nói chung, viết tắt múi giờ là không đủ, để xác định một múi giờ duy nhất .


0

Chạy vào vấn đề chính xác này.

Cuối cùng tôi đã làm gì:

# starting with date string
sdt = "20190901"
std_format = '%Y%m%d'

# create naive datetime object
from datetime import datetime
dt = datetime.strptime(sdt, sdt_format)

# extract the relevant date time items
dt_formatters = ['%Y','%m','%d']
dt_vals = tuple(map(lambda formatter: int(datetime.strftime(dt,formatter)), dt_formatters))

# set timezone
import pendulum
tz = pendulum.timezone('utc')

dt_tz = datetime(*dt_vals,tzinfo=tz)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.