วิธีตัดทอนเวลาบนวัตถุ DateTime ใน Python


251

อะไรคือวิธีที่ดีงามในการตัดทอนออบเจกต์ python datetime?

ในกรณีนี้โดยเฉพาะอย่างยิ่งวันที่ ดังนั้นโดยทั่วไปการตั้งค่าชั่วโมงนาทีวินาทีและไมโครวินาทีเป็น 0

ฉันต้องการให้ผลลัพธ์เป็นวัตถุ datetime ด้วยไม่ใช่สตริง

คำตอบ:


376

ฉันคิดว่านี่คือสิ่งที่คุณกำลังมองหา ...

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

แต่ถ้าคุณไม่สนใจเกี่ยวกับเวลาของสิ่งต่าง ๆ จริง ๆ แล้วคุณควรจะผ่านdateวัตถุเท่านั้น ...

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

14
ด้วย dt ที่ตระหนักถึงเขตเวลา datetime.datetime (dt.year, dt.month, dt.day) จะโยนข้อมูล tzinfo ออกไป
ʇsәɹoɈ

1
หากคุณกำลังมองหาเพียงแค่วันนี้คุณยังสามารถทำ datetime.date.today ()
galarant

4
โปรดทราบว่า python 2 และ python 3 docsระบุว่าreplace()เมธอดส่งคืนอ๊อบเจกต์ datetime ดังนั้นคาถาที่ถูกต้องจะเป็น:dt = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
Brad M

3
OP ต้องการdatetimeไม่ใช่dateวัตถุ (ที่คุณสามารถใช้dt.date()สาย (ไม่จำเป็นต้องใช้ตัวสร้างที่ชัดเจน)) .replace()วิธีการอาจล้มเหลวหากเพิ่มการสนับสนุนdatetime nanosecond คุณสามารถใช้datetime.combine()แทน
jfs

@chrisw ทำไมไม่เขียนแค่บรรทัดเดียวdatetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)ล่ะ?
3kstc

66

ใช้ a dateไม่ใช่datetimeถ้าคุณไม่สนใจเวลา

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

คุณสามารถอัปเดตช่วงเวลาเช่นนี้:

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

9
ด้วยชุดข้อมูลที่ตระหนักถึงเขตเวลา now.date () จะทิ้งข้อมูล tzinfo ไป
ʇsәɹoɈ


35

สี่ปีต่อมา: อีกวิธีหนึ่งหลีกเลี่ยง replace

ฉันรู้คำตอบที่ยอมรับได้เมื่อสี่ปีที่แล้ว แต่ดูเหมือนว่าเบากว่าการใช้replace:

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

หมายเหตุ

  • เมื่อคุณสร้างdatetimeวัตถุโดยไม่ผ่านคุณสมบัติเวลาไปยังตัวสร้างคุณจะได้รับเที่ยงคืน
  • ดังที่คนอื่น ๆ ได้กล่าวถึงสิ่งนี้ถือว่าคุณต้องการวัตถุ datetime สำหรับใช้กับ timedeltas ในภายหลัง
  • แน่นอนคุณสามารถแทนที่สิ่งนี้สำหรับบรรทัดแรก: dt = datetime.datetime.now()

20

คุณไม่สามารถตัดวัตถุ datetime เพราะมันจะไม่เปลี่ยนรูป

อย่างไรก็ตามนี่เป็นวิธีหนึ่งในการสร้างดาต้าไทม์ใหม่ด้วยฟิลด์ 0 ชั่วโมงนาทีวินาทีและไมโครวินาทีโดยไม่ต้องทิ้งวันที่ดั้งเดิมหรือ tzinfo:

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

1
+1: หากคุณใส่replaceตัวเลือกแรกเนื่องจากอาจเป็นสิ่งที่พวกเขาต้องการ
S.Lott

tzinfo=now.tzinfoมันไม่ถูกต้องที่จะใช้ tzinfoเวลาเที่ยงคืนเช่นอาจจะแตกต่างกัน UTC ชดเชยที่2012-04-01 00:09:00(09:00) ในประเทศออสเตรเลีย / เมลเบิร์นเป็นเขตเวลาAEST+10:00แต่ก็เป็นAEDT+11:00ที่2012-04-01 00:00:00(เที่ยงคืน) - มีจุดสิ้นสุดของเวลาการเปลี่ยนแปลงในวันนั้น คุณสามารถใช้pytzโมดูลเพื่อแก้ไขดูคำตอบของฉัน
jfs

13

รับเที่ยงคืนที่สอดคล้องกับวัตถุ datetime ที่กำหนดคุณสามารถใช้datetime.combine()วิธีการ :

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

ข้อได้เปรียบเมื่อเทียบกับวิธีคือวิธีการแก้ชั่นจะทำงานต่อไปแม้ว่าโมดูลแนะนำการสนับสนุนนาโนวินาที.replace()datetime.combine()datetime

tzinfoสามารถเก็บรักษาไว้ได้หากจำเป็น แต่อ็อฟเซ็ต utc อาจแตกต่างกันในเวลาเที่ยงคืนเช่นเนื่องจากการเปลี่ยน DST และวิธีการแก้ปัญหาไร้เดียงสา (การตั้งค่าtzinfoแอตทริบิวต์เวลา) อาจล้มเหลว ดูฉันจะรับเวลา UTC ของ“ เที่ยงคืน” สำหรับเขตเวลาที่กำหนดได้อย่างไร


7

คุณสามารถใช้นุ่นสำหรับมัน (แม้ว่ามันอาจจะเป็นค่าใช้จ่ายสำหรับงานนั้น) คุณสามารถใช้รอบ , พื้นและceilเช่นสำหรับตัวเลขปกติและความถี่หมีแพนด้าใด ๆ จากการชดเชยนามแฝง :

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

คุณสามารถใช้วันที่และเวลาได้เพื่อแยกวัน, เดือน, ปี ...

ตัวอย่าง:

from datetime import datetime
d = datetime.today()

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

ผลผลิต (สำหรับวันนี้):

29-2011

หากคุณต้องการเรียกคืนวันนี้คุณสามารถใช้คุณลักษณะวันเช่น:

from datetime import datetime
d = datetime.today()

# Retrieves the day
print d.day

Ouput (สำหรับวันนี้):

29

ทีนี้สิ่งที่ฉันทำไปแล้วหนึ่งครั้งเพื่อที่จะมีค่าใช้จ่ายมากขึ้นจากนั้นเพียงแค่ตั้งค่าชั่วโมงนาที ฯลฯ ในวัตถุ datetime
Kyle Brandt

Heh, thats วิธีที่แปลกที่จะทำมันคุณสามารถจริงเพียงแค่ทำd.dayฯลฯ
เช็น Ritzel

3

มีห้องสมุดที่ยอดเยี่ยมที่ใช้จัดการกับวันที่: 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')

และถ้าคุณต้องการรับค่า datetime กลับมา:

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

มันจะส่งกลับเวลาที่ผิด (อ็อฟเซ็ต utc ผิด) หากเวลาผลลัพธ์มีอ็อฟเซ็ต utc อื่นเช่นเนื่องจากการเปลี่ยน DST ดูฉันจะรับเวลา UTC ของ“ เที่ยงคืน” สำหรับเขตเวลาที่กำหนดได้อย่างไร
jfs


1

มีโมดูล datetime_truncate ที่จัดการสิ่งนี้ให้คุณ มันแค่เรียก datetime.replace


1

6 ปีต่อมา ... ฉันพบโพสต์นี้และฉันชอบ aproach จำนวนมาก:

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

ไชโย



1

คุณสามารถใช้

datetime.date.today()

มันเบาและส่งคืนสิ่งที่คุณต้องการ


ได้รับคำตอบเหมือนกันมาก่อนไม่มีอะไรใหม่
slfan

ขออภัย @slfan แต่ฉันไม่เห็นโพสต์ที่มีชื่อของคุณแม้แต่ใช้ "ค้นหา" จากเบราว์เซอร์
Bordotti

1
ไม่ใช่โดยฉันโดย zx81 3 ปีที่แล้ว ค้นหา datetime.date.today () หากคำตอบนั้นถูกต้องคุณควรโหวตไม่ตอบอีก
slfan


0

หากคุณกำลังจัดการกับชุดประเภท DateTime มีวิธีที่มีประสิทธิภาพมากขึ้นในการตัดทอนพวกเขาโดยเฉพาะอย่างยิ่งเมื่อวัตถุชุดมีแถวจำนวนมาก

คุณสามารถใช้ฟังก์ชั่นพื้น

ตัวอย่างเช่นหากคุณต้องการตัดให้เหลือชั่วโมง:

สร้างช่วงของวันที่

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

เราสามารถตรวจสอบได้โดยเปรียบเทียบเวลาทำงานระหว่างฟังก์ชั่นการแทนที่และการทำงานของพื้น

%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

นี่เป็นอีกวิธีหนึ่งที่เหมาะสมในบรรทัดเดียว แต่ไม่สง่างามเป็นพิเศษ:

dt = datetime.datetime.fromordinal(datetime.date.today().toordinal())
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.