Как укоротить время на объекте DateTime в Python?

251

Что такое классный способ обрезать объект даты и времени Python?

В данном конкретном случае до дня. Таким образом, в общем случае установка часов, минут, секунд и микросекунд на 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 документы и состояние , что replace()метод возвращает объект DateTime, поэтому правильное заклинание будет:dt = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
Брэд M
3
OP хочет datetime, а не dateобъект (который вы можете получить с помощью dt.date()call (нет необходимости использовать явный конструктор)). .replace()Метод может потерпеть неудачу , если datetimeдобавляет поддержку наносекунд . Вы могли бы использовать datetime.combine()вместо этого .
Jfs
@ chrisw Почему бы просто не написать это в одну строку datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)?
3
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
С учетом timezone с учетом timezone 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()
ZX81
источник
20

Вы не можете усечь объект datetime, потому что он неизменен .

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

newdatetime = now.replace(hour=0, minute=0, second=0, microsecond=0)
ʇsәɹoɈ
источник
1
+1: если вы поставите replaceопцию первым, так как это, вероятно, то, что они хотят.
S.Lott
Это неправильно использовать tzinfo=now.tzinfo. В tzinfoполночь может отличаться, например, смещение utc в 2012-04-01 00:09:00(9: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 может быть другим в полночь, например, из-за перехода на летнее время, и поэтому простое решение (установка tzinfoатрибута времени) может потерпеть неудачу. См. Как я могу получить время UTC «полуночи» для данного часового пояса?

JFS
источник
7

Вы можете использовать панды для этого (хотя это может быть накладные расходы для этой задачи). Вы можете использовать round , floor и 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.strftime, чтобы извлечь день, месяц, год ...

Пример :

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
Сандро Мунда
источник
Ну, дело в том, что я уже делаю это один раз, так что это может потребовать больше времени, чем просто установка поля min и т. Д. В объекте datetime.
Кайл Брандт
Хех, это странный способ сделать это, вы можете просто сделать d.day и т. Д.
Йохен Ритцель,
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>)
DmitrySemenov
источник
он возвращает неправильное время (неправильное смещение utc), если время результата имеет другое смещение utc, например, из-за перехода DST. См. Как я могу получить время UTC «полуночи» для данного часового пояса?
Jfs
1

Есть модуль datetime_truncate, который обрабатывает это для вас. Он просто вызывает datetime.replace.

Kyrre
источник
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
>>> import datetime
>>> dt = datetime.datetime.now()
>>> datetime.datetime.date(dt)
datetime.date(2019, 4, 2)
markling
источник
1

Вы можете просто использовать

datetime.date.today()

Это свет и возвращает именно то, что вы хотите.

Bordotti
источник
Такой же ответ был дан раньше, ничего нового.
slfan
Извините @slfan, но я не увидел ни одного поста с вашим именем, даже используя "поиск" из браузера.
Бордотти
1
Не мной, zx81 3 года назад. поиск datetime.date.today (). Если ответ правильный, вы должны проголосовать, а не отвечать снова.
slfan
0

Если вы имеете дело с Series типа 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())
Валентин Б.
источник