Python strptime () ve zaman dilimleri?


157

IPDDump kullanılarak oluşturulan bir Blackberry IPD yedeklemesinden bir CSV dökümü var. Buradaki tarih / saat dizeleri şuna benzer ( ESTAvustralya saat dilimi nerede ):

Tue Jun 22 07:46:22 EST 2010

Bu tarihi Python'da çözümleyebilmem gerekiyor. İlk başta, strptime()datettime fonksiyonunu kullanmaya çalıştım .

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

Ancak, bir nedenden ötürü, datetimegeri dönen nesnenin tzinfokendisiyle ilişkili olduğu görülmemektedir .

Görünüşe göre sessizce atılan bu sayfada okudum , ancak belgeleri kontrol ettim ve bu belgede burada belgelenen hiçbir şey bulamıyorum .datetime.strptimetzinfo

Tarihi bir üçüncü taraf Python kitaplığı, dateutil kullanarak ayrıştırılmış elde edebildim , ancak yine de dahili olarak nasıl strptime()yanlış kullandığımı merak ediyorum ? strptime()Zaman dilimleri ile güzel oynamak için herhangi bir yolu var mı ?


1
Tüm tarihleri ​​GMT'ye dönüştüremez misiniz?
Robus

2
@Robus: Hmm, bunu yapmayı umuyordum - ama strftime / datetime'ın bir şekilde bunu yapabileceğini varsayıyordum? Her iki durumda da, tarihlerin EST saat diliminde veya bana ne olursa olsun saat diliminde olduğu gerçeğini saklamam / ayrıştırmam gerekiyor. Komut dosyasının genel tarih saatlerini saat dilimi bilgileriyle ayrıştırması gerekir (örn. ETC başka bir saat dilimi olabilir).
victorhooi

3
EST aynı zamanda ABD saat dilimi kısaltmasıdır. (Benzer şekilde BST hem İngiltere hem de Brezilya saat dilimi kısaltmasıdır.) Bu tür kısaltmalar doğası gereği belirsizdir. Bunun yerine UTC / GMT'ye göre ofsetleri kullanın. (Kısaltmaları desteklemeniz gerekiyorsa, eşlemeyi yerel ayarlara bağımlı hale getirmeniz gerekir ve bu dağınık bir sıçan deliğidir.)
Donal Fellows

Yanıtlar:


58

datetimeModül belgelerine diyor ki:

Formata göre ayrıştırılan date_string öğesine karşılık gelen bir tarih / saat döndürür. Bu eşdeğerdir datetime(*(time.strptime(date_string, format)[0:6])).

Gördün [0:6]mü? Bu seni alır (year, month, day, hour, minute, second). Başka hiçbir şey. Zaman dilimlerinden bahsedilmiyor.

İlginç bir şekilde, [Win XP SP2, Python 2.6, 2.7] örneğinizi iletmek time.strptimeişe yaramaz ancak "% Z" ve "EST" leri kaldırırsanız çalışır. Ayrıca "EST" yerine "UTC" veya "GMT" kullanarak çalışır. "PST" ve "MEZ" çalışmıyor. Şaşırtıcı.

Bunun sürüm 3.2'den beri güncellendiğini ve şimdi aynı belgelerin şunları da belirttiğini belirtmek gerekir:

% Z yönergesi strptime () yöntemine sağlandığında, bilinçli bir datetime nesnesi üretilir. Sonucun tzinfo'su bir saat dilimi örneğine ayarlanır.

Bunun% Z ile çalışmadığını unutmayın, bu nedenle durum önemlidir. Aşağıdaki örneğe bakın:

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


354

Python-dateutil kullanmanızı öneririm . Ayrıştırıcı, şu ana kadar attığım her tarih biçimini ayrıştırabildi.

>>> 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)

ve bunun gibi. strptime()Biçim saçma ile uğraşmak yok ... sadece bir tarih atmak ve doğru olanı yapar.

Güncelleme : Hata! Kullandığınızdan bahsettiğiniz orijinal sorunuzda özledim, bunun için dateutilüzgünüm. Ama umarım bu cevap, tarih ayrıştırma soruları olduğunda ve bu modülün faydasını gördüğünde bu soruya rastlayan diğer insanlar için hala yararlıdır.


Pek çok insanın python-dateutil kullanmaya eğilimli olduğu düşünüldüğünde, bize bu lib'in bir sınırlamasını göstermek istiyorum. >>> 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 Son virgül ile nokta değiştirmelisiniz. Sonraparser.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
@flyingfoxlee, evet, anlıyorum. Sadece insanlara python-dateutil'in sınırlamasını söylemek istiyorum. Sihirli şeyler yapar, ancak bazen bunu yapamaz. Yani "sadece bir tarih atın ve doğru olanı yapar." % 100 doğru değil.
wanghq

4
dateutil.parser.parse("10-27-2016 09:06 AM PDT")döner: datetime.datetime(2016, 10, 27, 9, 6)saat dilimini
anlayamıyor

2
Bu kişinin amacına bağlıdır. dateutil parserkullanımı basit olabilir, ancak strptime()daha hızlıdır. Ayrıca, formatlarını öğrenmek oldukça kolaydır.
rapture

9

Saat dizeniz , rfc 2822'deki saat biçimine (e-postadaki tarih biçimi, http başlıkları) benzer . Yalnızca stdlib kullanarak ayrıştırabilirsiniz:

>>> 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)

Çeşitli Python sürümleri için saat dilimine uygun tarih-saat nesneleri veren çözümlere bakın: tarihi bir e-postadan saat dilimi ile ayrıştırma .

Bu formatta ESTanlamsal olarak eşdeğerdir-0500 . Genel olarak, bir zaman dilimini kısaltmak için bir zaman dilimi kısaltması yeterli değildir .


0

Tam olarak bu problemle karşılaştı.

Sonunda ne yaptım:

# 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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.