Python strptime () dan zona waktu?

157

Saya memiliki dumpfile CSV dari cadangan IPD Blackberry, dibuat menggunakan IPDDump. String tanggal / waktu di sini terlihat seperti ini (di mana ESTzona waktu Australia):

Tue Jun 22 07:46:22 EST 2010

Saya harus dapat menguraikan tanggal ini dengan Python. Pada awalnya, saya mencoba menggunakan strptime()fungsi dari datettime.

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

Namun, untuk beberapa alasan, datetimeobjek yang kembali sepertinya tidak ada tzinfohubungannya dengan itu.

Saya memang membaca pada halaman ini yang tampaknya datetime.strptimemembuang dengan diam-diam tzinfo, namun, saya memeriksa dokumentasinya, dan saya tidak dapat menemukan apa pun mengenai efek yang didokumentasikan di sini .

Saya sudah bisa mendapatkan tanggal diuraikan menggunakan perpustakaan Python pihak ketiga, dateutil , namun saya masih penasaran bagaimana saya menggunakan in-built yang strptime()salah? Apakah ada cara untuk bisa strptime()bermain bagus dengan zona waktu?

victorhooi
sumber
1
Tidak bisakah Anda ... mengonversi semua tanggal ke GMT?
Robus
2
@Robus: Hmm, saya berharap untuk melakukan itu - tapi saya berasumsi bahwa strftime / datetime bisa melakukan itu? Either way, saya perlu menyimpan / menguraikan fakta bahwa datetimes berada di zona waktu EST, atau zona waktu apa pun yang terjadi pada saya. Skrip harus dapat mengurai data umum dengan info zona waktu (mis. ETC dapat berupa zona waktu lainnya).
victorhooi
3
EST juga merupakan singkatan zona waktu AS. (Demikian pula BST adalah singkatan dari Inggris dan zona waktu Brasil.) Singkatan semacam itu pada dasarnya tidak jelas. Gunakan offset relatif ke UTC / GMT sebagai gantinya. (Jika Anda perlu mendukung singkatan, Anda perlu membuat pemetaan bergantung pada lokal dan itu adalah lubang tikus yang berantakan).
Donal Fellows

Jawaban:

58

The datetimedokumentasi modul mengatakan:

Kembalikan datetime yang sesuai dengan date_string, diuraikan sesuai dengan format. Ini setara dengan datetime(*(time.strptime(date_string, format)[0:6])).

Lihat itu [0:6]? Itu membuat Anda (year, month, day, hour, minute, second). Tidak ada lagi. Tidak disebutkan zona waktu.

Menariknya, [Win XP SP2, Python 2.6, 2.7] meneruskan contoh Anda untuk time.strptimetidak bekerja tetapi jika Anda menghapus "% Z" dan "EST" itu berhasil. Juga menggunakan "UTC" atau "GMT" bukannya "EST" bekerja. "PST" dan "MEZ" tidak berfungsi. Membingungkan.

Perlu dicatat bahwa ini telah diperbarui pada versi 3.2 dan dokumentasi yang sama sekarang juga menyatakan sebagai berikut:

Ketika direktif% z diberikan ke metode strptime (), objek datetime sadar akan diproduksi. The tzinfo dari hasilnya akan diatur ke turunan zona waktu.

Perhatikan bahwa ini tidak bekerja dengan% Z, jadi kasing itu penting. Lihat contoh berikut:

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
John Machin
sumber
353

Saya sarankan menggunakan python-dateutil . Parsernya telah dapat mengurai setiap format tanggal yang saya berikan sejauh ini.

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

dan seterusnya. Tidak berurusan dengan strptime()format omong kosong ... cukup ajukan kencan padanya dan itu Melakukan Hal yang Benar.

Pembaruan : Ups. Saya melewatkan pertanyaan asli Anda yang Anda sebutkan tadi dateutil, maaf tentang itu. Tapi saya harap jawaban ini masih berguna bagi orang lain yang menemukan pertanyaan ini ketika mereka memiliki pertanyaan penguraian dan melihat kegunaan modul itu.

Joe Shaw
sumber
Mengingat begitu banyak orang cenderung menggunakan python-dateutil, saya ingin menunjukkan satu batasan dari lib itu kepada kami. >>> 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 Anda harus mengganti koma terakhir dengan titik. Kemudianparser.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, ya, saya mengerti itu. Saya hanya ingin memberi tahu orang-orang tentang batasan python-dateutil. Memang hal-hal ajaib, tetapi kadang-kadang gagal melakukan itu. Jadi, "cukup ajak kencan dan itu Melakukan Hal yang Benar." tidak 100% benar.
wanghq
4
dateutil.parser.parse("10-27-2016 09:06 AM PDT")pengembalian: datetime.datetime(2016, 10, 27, 9, 6)gagal menentukan zona waktu ...
HaPsantran
2
Itu tergantung pada tujuan seseorang. dateutil parsermungkin mudah digunakan, tetapi strptime()lebih cepat. Selain itu, formatnya cukup mudah dipelajari.
pengangkatan
9

String waktu Anda mirip dengan format waktu di rfc 2822 (format tanggal dalam email, tajuk http) . Anda dapat menguraikannya hanya dengan 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)

Lihat solusi yang menghasilkan objek waktu-sadar datzone untuk berbagai versi Python: menguraikan tanggal dengan zona waktu dari email .

Dalam format ini, ESTsecara semantik setara dengan-0500 . Padahal, secara umum, singkatan zona waktu tidak cukup, untuk mengidentifikasi zona waktu secara unik .

jfs
sumber
0

Berlari ke masalah yang tepat ini.

Apa yang akhirnya saya lakukan:

# 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)
Christopher
sumber