Какой самый элегантный способ получить конец дня (datetime)?
UPDATE: я добавил решение в нижней части этого вопроса.
В настоящее время я пишу некоторый код отчетности, который позволяет пользователям дополнительно указывать диапазон дат. Способ его работы (упрощенный):
- Пользователь (необязательно) указывает год.
- Пользователь (необязательно) указывает месяц.
- Пользователь (необязательно) указывает день.
Вот фрагмент кода, а также комментарии, описывающие, что мне нравится:
from datetime import datetime, timedelta
# ...
now = datetime.now()
start_time = now.replace(hour=0, minute=0, second=0, microsecond=0)
stop_time = now
# If the user enters no year, month, or day--then we'll simply run a
# report that only spans the current day (from the start of today to now).
if options['year']:
start_time = start_time.replace(year=options['year'], month=0, day=0)
stop_time = stop_time.replace(year=options['year'])
# If the user specifies a year value, we should set stop_time to the last
# day / minute / hour / second / microsecond of the year, that way we'll
# only generate reports from the start of the specified year, to the end
# of the specified year.
if options['month']:
start_time = start_time.replace(month=options['month'], day=0)
stop_time = stop_time.replace(month=options['month'])
# If the user specifies a month value, then set stop_time to the last
# day / minute / hour / second / microsecond of the specified month, that
# way we'll only generate reports for the specified month.
if options['day']:
start_time = start_time.replace(day=options['day'])
stop_time = stop_time.replace(day=options['day'])
# If the user specifies a day value, then set stop_time to the last moment of
# the current day, so that reports ONLY run on the current day.
Я пытаюсь найти самый элегантный способ написать код выше - я пытался найти способ сделать это с timedelta, но, похоже, не понял этого. Любые советы будут оценены.
Спасибо.
ИЗМЕНИТЬ, ДОБАВЛЕНИЕ РЕШЕНИЯ:
Посмотрев на некоторые из ответов здесь, и на самом деле не найдя ничего необычайно элегантного, я немного подшутил вокруг стандартной библиотеки и нашел свое текущее решение (которое мне очень нравится): dateutil.
Вот как я его реализовал:
from datetime import date
from dateutil.relativedelta import relativedelta
now = date.today()
stop_time = now + relativedelta(days=1)
start_time = date(
# NOTE: I'm not doing dict.get() since in my implementation, these dict
# keys are guaranteed to exist.
year = options['year'] or now.year,
month = options['month'] or now.month,
day = options['day'] or now.day
)
if options['year']:
start_time = date(year=options['year'] or now.year, month=1, day=1)
stop_time = start_time + relativedelta(years=1)
if options['month']:
start_time = date(
year = options['year'] or now.year,
month = options['month'] or now.month,
day = 1
)
stop_time = start_time + relativedelta(months=1)
if options['day']:
start_time = date(
year = options['year'] or now.year,
month = options['month'] or now.month,
day = options['day'] or now.day,
)
stop_time = start_time + relativedelta(days=1)
# ... do stuff with start_time and stop_time here ...
Что мне нравится в этой реализации, так это то, что python dateutil.relativedata.relativedata отлично работает с красными случаями. Он возвращает дни/месяцы/годы. Если у меня есть месяц = 12 и сделайте relativedata (месяцы = 1), он увеличит год и установит месяц на 1 (отлично работает).
Также: в приведенной выше реализации, если пользователь не указывает ни одну из факультативных дат (год, месяц или день) - мы отменим хороший по умолчанию (start_time = сегодня утром, stop_time = сегодня), таким образом мы по умолчанию будем делать вещи только для текущего дня.
Спасибо всем за их ответы - они были полезны в моих исследованиях.
Ответы
Ответ 1
Использование dict.get
может упростить ваш код. Это немного чище, чем использование объектов datetime.replace и timedelta.
Здесь вы можете начать:
from datetime import datetime
options = dict(month=5, day=20)
now = datetime.now()
start_time = datetime(year=options.get('year', now.year),
month=options.get('month', 1),
day=options.get('day', 1)
hour=0,
minute=0,
second=0)
stop_time = datetime(year=options.get('year', now.year),
month=options.get('month', now.month),
day=options.get('day', now.day),
hour=now.hour,
minute=now.minute,
second=now.second)
Ответ 2
Чтобы установить stop_time
, заблаговременно продвигайте start_time
один год, месяц или день, а затем вычтите один timedelta(microseconds=1)
if options['year']:
start_time = start_time.replace(year=options['year'], month=1, day=1)
stop_time = stop_time.replace(year=options['year']+1)-timedelta(microseconds=1)
elif options['month']:
start_time = start_time.replace(month=options['month'], day=1)
months=options['month']%12+1
stop_time = stop_time.replace(month=months,day=1)-timedelta(microseconds=1)
else:
start_time = start_time.replace(day=options['day'])
stop_time = stop_time.replace(day=options['day'])+timedelta(days=1,microseconds=-1)
Ответ 3
today = datetime.date.today()
begintime = today.strftime("%Y-%m-%d 00:00:00")
endtime = today.strftime("%Y-%m-%d 23:59:59")