Як обрізати час на об’єкті DateTime в Python?


251

Який класний спосіб урізати об'єкт дата-пітону?

В даному конкретному випадку - до дня. Таким чином, встановлення години, хвилини, секунд і мікросекунд до 0.

Я хотів би, щоб вихід також був об'єктом дати, а не рядком.

Відповіді:


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.год, dt.month, dt.day) викидає інформацію про tzinfo.
ʇsәɹoɈ

1
якщо ви шукаєте просто сьогодні, ви також можете зробити datetime.date.today ()
галарант

4
Зверніть увагу , що Python 2 і Python 3 документи і стан , що replace()метод повертає об'єкт DateTime, тому правильне заклинання буде:dt = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
Бред M

3
OP хоче datetime, а не dateзаперечує (щоб ви могли отримати dt.date()дзвінки (не потрібно використовувати явний конструктор)). .replace()Метод може потерпіти невдачу , якщо datetimeдодає підтримку наносекунд . Ви можете використати datetime.combine()натомість .
jfs

@chrisw Чому б просто не записати його в один рядок datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)?
3kstc

66

Скористайтеся знаком " 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об'єкт, не передаючи властивостям часу конструктору, ви отримуєте півночі.
  • Як зазначали інші, це передбачає, що ви хочете об'єкт дати для подальшого використання з timedeltas.
  • Звичайно, ви можете замінити це першим рядком: dt = datetime.datetime.now()

20

Ви не можете обрізати об'єкт дати, оскільки він незмінний .

Однак ось один спосіб побудувати новий час дати з полями 0 годин, хвилини, секунди та мікросекунди, не відкидаючи початкову дату чи tzinfo:

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

1
+1: якщо ви поставите replaceваріант спочатку, оскільки це, мабуть, те, що вони хочуть.
С.Лотт

Неправильно використовувати tzinfo=now.tzinfo. tzinfoОпівночі може бути іншою , наприклад, зміщення в UTC 2012-04-01 00:09:00(9 ранку) в Австралії / Мельбурн часовому поясі знаходиться , AEST+10:00але це AEDT+11:00в 2012-04-01 00:00:00(опівночі) - є з вичерпаним ДСТ перехід в той же день. Ви можете використати pytzмодуль, щоб виправити це, дивіться мою відповідь.
jfs

13

Щоб отримати опівночі, що відповідає заданому об'єкту дати, ви можете використовувати 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може бути збережено при необхідності, але зміщення потужності може бути різним опівночі, наприклад, через перехід 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

Ви можете використовувати datetime.strWeather для вилучення дня, місяця, року ...

Приклад:

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

Вихід (на сьогодні):

29

Ну річ у тому, що я це вже роблю один раз, так що це може мати більше накладних витрат, ніж просто встановлення годинної хвилини тощо поля в об'єкті datetime.
Кайл Брандт

Хе, це дивний спосіб зробити це, ви насправді можете просто робити d.dayі т.д.
Jochen 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')

і якщо ви хочете повернути значення дати:

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

він повертає неправильний час (неправильне зміщення утта), якщо час результату має інше зміщення утта, наприклад, через перехід DST. Дивіться, як я можу отримати UTC за "півночі" за заданий часовий пояс?
jfs


1

Існує модуль datetime_truncate, який обробляє це для вас. Він просто називає datetime.replace.


1

Через 6 років ... Я знайшов цю посаду і мені більше сподобався нудний підступ:

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, але я не побачив жодної публікації з вашим іменем, навіть використовуючи "пошук" у браузері.
Бордотті

1
Не мені, zx81 3 роки тому. пошук datetime.date.today (). Якщо відповідь правильна, вам слід подати заяву, а не відповідати знову.
slfan


0

Якщо ви маєте справу з серією типу DateTime, існує більш ефективний спосіб їх обрізання, особливо коли об’єкт Series має багато рядків.

Ви можете використовувати підлогу функцію

Наприклад, якщо ви хочете обрізати його за години:

Створіть діапазон дат

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())
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.