Dengan Python, bagaimana Anda mengubah objek `datetime` menjadi detik?

226

Permintaan maaf untuk pertanyaan sederhana ... Saya baru mengenal Python ... Saya telah mencari-cari dan sepertinya tidak ada yang berhasil.

Saya memiliki banyak objek datetime dan saya ingin menghitung jumlah detik sejak waktu yang tetap di masa lalu untuk masing-masing (misalnya sejak 1 Januari 1970).

import datetime
t = datetime.datetime(2009, 10, 21, 0, 0)

Ini tampaknya hanya membedakan antara tanggal yang memiliki hari yang berbeda:

t.toordinal()

Bantuan apa pun sangat kami hargai.

Nathan Lippi
sumber
2
Saya mungkin akan mengubah keduanya menjadi S sejak zaman dan pergi dari sana: int(t.timestamp())
nerdwaller
untuk operasi yang berlawanan buka di sini: convert-seconds-since-epoch-to-a-datetime-object
Trevor Boyd Smith

Jawaban:

233

Untuk tanggal khusus 1 Januari 1970 ada beberapa opsi.

Untuk tanggal mulai lainnya, Anda perlu mendapatkan perbedaan antara kedua tanggal dalam detik. Mengurangkan dua tanggal memberikan timedeltaobjek, yang pada Python 2.7 memiliki total_seconds()fungsi.

>>> (t-datetime.datetime(1970,1,1)).total_seconds()
1256083200.0

Tanggal mulai biasanya ditentukan dalam UTC, jadi untuk hasil yang tepat datetimeAnda memasukkan ke dalam formula ini juga harus dalam UTC. Jika Anda datetimebelum menggunakan UTC, Anda harus mengonversinya sebelum menggunakannya, atau melampirkan tzinfokelas yang memiliki offset yang tepat.

Seperti disebutkan dalam komentar, jika Anda memiliki tzinfolampiran pada Anda datetimemaka Anda akan memerlukannya pada tanggal mulai juga atau pengurangan akan gagal; untuk contoh di atas saya akan menambahkan tzinfo=pytz.utcjika menggunakan Python 2 atau tzinfo=timezone.utcjika menggunakan Python 3.

Mark tebusan
sumber
1
Python sekarang memperingatkan saya: "TypeError: tidak bisa mengurangi offset-naif dan offset-sadar" Apa solusi terbaik untuk memperbaikinya?
Aaron Ash
2
@ Chrisbdis, coba datetime.datetime(1970,1,1,tzinfo=pytz.utc).
Mark Ransom
9
Pertimbangkan untuk menggunakan: datetime.datetime.utcfromtimestamp(0) Saya telah menggunakan ini untuk mendapatkan 'zaman' dengan mudah. Perhatikan bahwa zaman tidak selalu sama di semua sistem.
DA
3
Berhati-hatilah dengan zona waktu di sini. Saya di UTC + 2, yang berarti bahwa output time.time()dan datetime.now() - datetime(1970, 1, 1)berbeda dengan 7200 detik. Sebaliknya gunakan (t - datetime.datetime.fromtimestamp(0)).total_seconds(). Jangan tidak menggunakan utcfromtimestamp(0)jika Anda ingin mengkonversi datetime di zona waktu lokal Anda.
Carl
2
@DA: Python tidak mendukung zaman non-POSIX . Semua sistem tempat python bekerja menggunakan Zaman yang sama: 1970-01-01 00:00:00 UTC
jfs
130

Untuk mendapatkan waktu Unix (detik sejak 1 Januari 1970):

>>> import datetime, time
>>> t = datetime.datetime(2011, 10, 21, 0, 0)
>>> time.mktime(t.timetuple())
1319148000.0
Mark Byers
sumber
22
berhati-hatilah saat menggunakan time.mktime untuk mengekspresikan waktu setempat dan tergantung pada platform
Shih-Wen Su
7
Berhati-hatilah. Ini menggigit saya ke pantat saya waktu besar
Arg
itu menganggap itu tadalah waktu setempat. Pengimbangan UTC untuk zona waktu lokal mungkin berbeda di masa lalu dan jika mktime()(perpustakaan C) tidak memiliki akses ke data zona waktu historis pada platform tertentu daripada yang mungkin gagal ( pytzadalah cara portabel untuk mengakses basis data tz). Juga, waktu lokal mungkin ambigu misalnya, selama transisi DST - Anda perlu info tambahan untuk mengacaukan mis., Jika Anda tahu bahwa nilai tanggal / waktu berturut-turut akan meningkat dalam file log
jfs
1
Hati-hati saat menggunakan ini dengan waktu yang memiliki sepersekian detik. time.mktime(datetime.datetime(2019, 8, 3, 4, 5, 6, 912000).timetuple())hasil 1564819506.0, diam-diam menjatuhkan milidetik, tetapi datetime.datetime(2019, 8, 3, 4, 5, 6, 912000).timestamp()(jawaban Andrzej Pronobis) menghasilkan 1564819506.912, hasil yang diharapkan.
Alex
128

Mulai dari Python 3.3 ini menjadi sangat mudah dengan datetime.timestamp()metode ini. Ini tentu saja hanya akan berguna jika Anda membutuhkan jumlah detik dari 1970-01-01 UTC.

from datetime import datetime
dt = datetime.today()  # Get timezone naive now
seconds = dt.timestamp()

Nilai pengembalian akan berupa float yang mewakili fraksi genap sedetik. Jika datetime adalah naif zona waktu (seperti pada contoh di atas), akan diasumsikan bahwa objek datetime mewakili waktu lokal, yaitu Ini akan menjadi jumlah detik dari waktu saat ini di lokasi Anda ke 1970-01-01 UTC.

Andrzej Pronobis
sumber
3
Siapa pun yang menurunkan ini, bisakah Anda jelaskan alasannya?
Andrzej Pronobis
5
Saya berasumsi, downvote disebabkan oleh tag python-2.7 pada pertanyaan (itu hanya tebakan).
jfs
3
Ini harus menjadi jawaban yang diterima / jawaban yang diterima harus diperbarui.
DreamFlasher
11
Waktu untuk meningkatkan, saya kira;)
DreamFlasher
apakah mungkin untuk menghitung jarak ini dari tanggal mulai yang lain? (maksud saya mengubah tanggal 1970-01-01)
pellerossa pelles
29

Mungkin di luar topik: untuk mendapatkan waktu UNIX / POSIX dari datetime dan mengubahnya kembali:

>>> import datetime, time
>>> dt = datetime.datetime(2011, 10, 21, 0, 0)
>>> s = time.mktime(dt.timetuple())
>>> s
1319148000.0

# and back
>>> datetime.datetime.fromtimestamp(s)
datetime.datetime(2011, 10, 21, 0, 0)

Perhatikan bahwa zona waktu yang berbeda berdampak pada hasil, misalnya pengembalian TZ / DST saya saat ini:

>>>  time.mktime(datetime.datetime(1970, 1, 1, 0, 0).timetuple())
-3600 # -1h

oleh karena itu orang harus mempertimbangkan untuk menormalkan ke UTC dengan menggunakan versi fungsi UTC.

Perhatikan bahwa hasil sebelumnya dapat digunakan untuk menghitung offset UTC zona waktu Anda saat ini. Dalam contoh ini, ini + 1j, yaitu UTC + 0100.

Referensi:

Robert Lujo
sumber
mktime()mungkin gagal . Secara umum, Anda perlu pytzmengonversi waktu lokal ke utc, untuk mendapatkan cap waktu POSIX.
jfs
calendar.timegm () tampaknya merupakan versi utc dari time.mktime ()
frankster
27

int (t.strftime("%s")) juga berfungsi

dan3
sumber
1
Bekerja untuk saya di Python 2.7, dengan import datetime; t = datetime.datetime(2011, 10, 21, 0, 0)(seperti yang ditentukan oleh OP). Tapi sungguh, saya ragu% s adalah format waktu yang baru ditambahkan.
dan3
1
@ dan3: salah. %stidak didukung (ini dapat bekerja pada beberapa platform iff tadalah objek waktu naif yang mewakili waktu lokal dan jika perpustakaan C lokal memiliki akses ke database tz kalau tidak hasilnya mungkin salah). Jangan gunakan itu.
jfs
%stidak didokumentasikan di mana pun. Saya menaburnya dalam kode nyata dan bertanya-tanya apa ini dan lihat di dokumentasi dan tidak ada yang namanya %s. Hanya ada dengan S besar hanya untuk detik.
VStoykov
13

dari python docs:

timedelta.total_seconds()

Kembalikan jumlah total detik yang terkandung dalam durasi. Setara dengan

(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6

dihitung dengan pembagian yang benar diaktifkan.

Perhatikan bahwa untuk interval waktu yang sangat besar (lebih dari 270 tahun pada kebanyakan platform) metode ini akan kehilangan akurasi mikrodetik.

Fungsi ini baru dalam versi 2.7.

Michael
sumber
1
ada masalah kecil dengan perhitungan itu harus 10 6 bukannya 10 * 6 ... td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 6) / 10 ** 6
sdu
@du menangkap besar - tanda bintang ganda ada di jawaban saya tetapi stackoverflow mengkonsumsinya, upaya untuk memperbaiki hanya memberanikan teks.
Michael
2

Untuk mengonversi objek datetime yang mewakili waktu dalam UTC ke stempel waktu POSIX :

from datetime import timezone

seconds_since_epoch = utc_time.replace(tzinfo=timezone.utc).timestamp()

Untuk mengonversi objek datetime yang mewakili waktu di zona waktu lokal ke stempel waktu POSIX:

import tzlocal # $ pip install tzlocal

local_timezone = tzlocal.get_localzone()
seconds_since_epoch = local_timezone.localize(local_time, is_dst=None).timestamp()

Lihat Bagaimana cara mengubah waktu lokal ke UTC dengan Python? Jika basis data tz tersedia pada platform tertentu; solusi stdlib-only dapat berfungsi .

Ikuti tautan jika Anda membutuhkan solusi untuk <3.3versi Python.

jfs
sumber
1

Saya mencoba kalender.timegm perpustakaan standar dan berfungsi dengan baik:

# convert a datetime to milliseconds since Epoch
def datetime_to_utc_milliseconds(aDateTime):
    return int(calendar.timegm(aDateTime.timetuple())*1000)

Ref: https://docs.python.org/2/library/calendar.html#calendar.timegm

Shaohong Li
sumber
itu mengupas pecahan sepersekian detik. Diasumsikan bahwa aDateTimeini adalah waktu UTC
jfs