Bagaimana cara memotong waktu pada objek DateTime dengan Python?


251

Apa cara berkelas untuk memotong objek datetime python?

Dalam kasus khusus ini, hingga hari ini. Jadi pada dasarnya mengatur jam, menit, detik, dan mikrodetik ke 0.

Saya ingin output juga menjadi objek datetime, bukan string.

Jawaban:


376

Saya pikir ini yang Anda cari ...

>>> import datetime
>>> dt = datetime.datetime.now()
>>> dt = dt.replace(hour=0, minute=0, second=0, microsecond=0) # Returns a copy
>>> dt
datetime.datetime(2011, 3, 29, 0, 0)

Tetapi jika Anda benar-benar tidak peduli dengan aspek waktu dari hal-hal, maka Anda harus benar-benar hanya berkeliling datebenda ...

>>> d_truncated = datetime.date(dt.year, dt.month, dt.day)
>>> d_truncated
datetime.date(2011, 3, 29)

14
Dengan dt time-aware, datetime.datetime (dt.year, dt.month, dt.day) membuang informasi tzinfo.
ʇsәɹoɈ

1
jika Anda hanya mencari hari ini, Anda juga dapat melakukan datetime.date.today ()
galarant

4
Perhatikan bahwa python 2 dan python 3 docs keduanya menyatakan bahwa replace()metode mengembalikan objek datetime, sehingga mantera yang benar adalah:dt = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
Brad M

3
OP ingin datetime, bukan datekeberatan (bahwa Anda bisa menggunakan dt.date()panggilan (tidak perlu menggunakan konstruktor eksplisit)). The .replace()metode mungkin gagal jika datetimemenambahkan dukungan nanodetik . Anda bisa menggunakannya datetime.combine()sebagai gantinya .
jfs

@ chrisw Mengapa tidak menuliskannya dalam satu baris saja datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)?
3kstc

66

Gunakan datebukan datetimejika Anda tidak peduli waktu.

>>> now = datetime.now()
>>> now.date()
datetime.date(2011, 3, 29)

Anda dapat memperbarui datetime seperti ini:

>>> now.replace(minute=0, hour=0, second=0, microsecond=0)
datetime.datetime(2011, 3, 29, 0, 0)

9
Dengan datetimes-aware time, now.date () membuang informasi tzinfo.
ʇsәɹoɈ

1
@ ʇsәɹoɈ: inilah cara Anda bisa mendapatkan tengah malam yang sadar zona waktu
jfs

34

Empat tahun kemudian: cara lain, menghindari replace

Saya tahu jawaban yang diterima dari empat tahun lalu berhasil, tetapi ini agak lebih ringan daripada menggunakan replace:

dt = datetime.date.today()
dt = datetime.datetime(dt.year, dt.month, dt.day)

Catatan

  • Saat Anda membuat datetimeobjek tanpa meneruskan properti waktu ke konstruktor, Anda mendapatkan tengah malam.
  • Seperti yang telah dicatat orang lain, ini mengasumsikan Anda menginginkan objek datetime untuk digunakan nanti dengan timedeltas.
  • Anda tentu saja dapat mengganti ini dengan baris pertama: dt = datetime.datetime.now()

20

Anda tidak dapat memotong objek datetime karena tidak dapat diubah .

Namun, berikut adalah salah satu cara untuk membangun datetime baru dengan bidang 0 jam, menit, detik, dan mikrodetik, tanpa membuang tanggal asli atau tzinfo:

newdatetime = now.replace(hour=0, minute=0, second=0, microsecond=0)

1
+1: jika Anda menempatkan replaceopsi terlebih dahulu, karena mungkin itulah yang mereka inginkan.
S.Lott

Itu tidak benar untuk digunakan tzinfo=now.tzinfo. Pada tzinfotengah malam mungkin berbeda misalnya, utc offset pada 2012-04-01 00:09:00(09:00) di zona waktu Australia / Melbourne AEST+10:00tetapi AEDT+11:00pada 2012-04-01 00:00:00(tengah malam) - ada transisi akhir-DST pada hari itu. Anda dapat menggunakan pytzmodul untuk memperbaikinya, lihat jawaban saya.
jfs

13

Untuk mendapatkan tengah malam yang terkait dengan objek datetime tertentu, Anda bisa menggunakan datetime.combine()metode :

>>> from datetime import datetime, time
>>> dt = datetime.utcnow()
>>> dt.date()
datetime.date(2015, 2, 3)
>>> datetime.combine(dt, time.min)
datetime.datetime(2015, 2, 3, 0, 0)

Keuntungan dibandingkan dengan yang .replace()metode adalah bahwa datetime.combine()solusi berbasis akan terus bekerja bahkan jika datetimememperkenalkan modul nanodetik mendukung .

tzinfodapat dipertahankan jika perlu tetapi utc offset mungkin berbeda pada tengah malam misalnya, karena transisi DST dan karena itu solusi naif (pengaturan tzinfoatribut waktu) mungkin gagal. Lihat Bagaimana cara saya mendapatkan waktu UTC "tengah malam" untuk zona waktu tertentu?


7

Anda bisa menggunakan panda untuk itu (meskipun bisa jadi overhead untuk tugas itu). Anda bisa menggunakan round , floor , dan ceil seperti untuk nomor biasa dan frekuensi panda dari alias-offset :

import pandas as pd
import datetime as dt

now = dt.datetime.now()
pd_now = pd.Timestamp(now)

freq = '1d'
pd_round = pd_now.round(freq)
dt_round = pd_round.to_pydatetime()

print(now)
print(dt_round)

"""
2018-06-15 09:33:44.102292
2018-06-15 00:00:00
"""

4

Anda dapat menggunakan datetime.strftime untuk mengekstrak hari, bulan, tahun ...

Contoh:

from datetime import datetime
d = datetime.today()

# Retrieves the day and the year
print d.strftime("%d-%Y")

Output (untuk hari ini):

29-2011

Jika Anda hanya ingin mengambil hari, Anda dapat menggunakan atribut hari seperti:

from datetime import datetime
d = datetime.today()

# Retrieves the day
print d.day

Ouput (untuk hari ini):

29

Yah masalahnya adalah saya sudah melakukan ini sekali, sehingga mungkin memiliki lebih banyak overhead kemudian hanya mengatur bidang jam min dll dalam objek datetime.
Kyle Brandt

Heh, itu cara yang aneh untuk melakukannya, Anda sebenarnya bisa melakukannya d.daydll.
Jochen Ritzel

3

Ada perpustakaan hebat yang digunakan untuk memanipulasi tanggal: Delorean

import datetime
from delorean import Delorean
now = datetime.datetime.now()
d = Delorean(now, timezone='US/Pacific')

>>> now    
datetime.datetime(2015, 3, 26, 19, 46, 40, 525703)

>>> d.truncate('second')
Delorean(datetime=2015-03-26 19:46:40-07:00, timezone='US/Pacific')

>>> d.truncate('minute')
Delorean(datetime=2015-03-26 19:46:00-07:00, timezone='US/Pacific')

>>> d.truncate('hour')
Delorean(datetime=2015-03-26 19:00:00-07:00, timezone='US/Pacific')

>>> d.truncate('day')
Delorean(datetime=2015-03-26 00:00:00-07:00, timezone='US/Pacific')

>>> d.truncate('month')
Delorean(datetime=2015-03-01 00:00:00-07:00, timezone='US/Pacific')

>>> d.truncate('year')
Delorean(datetime=2015-01-01 00:00:00-07:00, timezone='US/Pacific')

dan jika Anda ingin mendapatkan nilai datetime kembali:

>>> d.truncate('year').datetime
datetime.datetime(2015, 1, 1, 0, 0, tzinfo=<DstTzInfo 'US/Pacific' PDT-1 day, 17:00:00 DST>)

ia mengembalikan waktu yang salah (offset utc salah) jika waktu hasil memiliki offset utc yang berbeda misalnya, karena transisi DST. Lihat Bagaimana cara saya mendapatkan waktu UTC "tengah malam" untuk zona waktu tertentu?
jfs


1

Ada modul datetime_truncate yang menangani ini untuk Anda. Itu hanya panggilan datetime.replace.


1

6 tahun kemudian ... Saya menemukan posting ini dan saya lebih suka pendekatan numpy:

import numpy as np
dates_array = np.array(['2013-01-01', '2013-01-15', '2013-01-30']).astype('datetime64[ns]')
truncated_dates = dates_array.astype('datetime64[D]')

Bersulang


1
>>> import datetime
>>> dt = datetime.datetime.now()
>>> datetime.datetime.date(dt)
datetime.date(2019, 4, 2)

1

Anda bisa menggunakannya

datetime.date.today()

Ringan dan mengembalikan apa yang Anda inginkan.


Jawaban yang sama telah diberikan sebelumnya, tidak ada yang baru.
Slfan

Maaf @ slfan tetapi saya tidak melihat kiriman dengan nama Anda, bahkan menggunakan "pencarian" dari browser.
Bordotti

1
Bukan oleh saya, oleh zx81 3 tahun lalu. cari datetime.date.today (). Jika jawaban itu benar, Anda harus mengambil alih, bukan menjawab lagi.
slfan


0

Jika Anda berurusan dengan serangkaian tipe DateTime, ada cara yang lebih efisien untuk memotongnya, khususnya ketika objek Seri memiliki banyak baris.

Anda dapat menggunakan fungsi lantai

Misalnya, jika Anda ingin memotongnya menjadi jam:

Hasilkan kisaran tanggal

times = pd.Series(pd.date_range(start='1/1/2018 04:00:00', end='1/1/2018 22:00:00', freq='s'))

Kita bisa memeriksanya membandingkan waktu berjalan antara fungsi ganti dan fungsi lantai.

%timeit times.apply(lambda x : x.replace(minute=0, second=0, microsecond=0))
>>> 341 ms ± 18.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit times.dt.floor('h')
>>>>2.26 ms ± 451 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

0

Inilah cara lain yang cocok dalam satu baris tetapi tidak terlalu elegan:

dt = datetime.datetime.fromordinal(datetime.date.today().toordinal())
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.