What's the most elegant way to get the end of the day (datetime)?

rdegges picture rdegges · Nov 2, 2011 · Viewed 8.5k times · Source

I'm currently writing some reporting code that allows users to optionally specify a date range. The way it works (simplified), is:

  • A user (optionally) specifies a year.
  • A user (optionally) specifies a month.
  • A user (optionally) specifies a day.

Here's a code snippet, along with comments describing what I'd like to do:

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.

I'm trying to find the most elegant way to write the code above--I've been trying to find a way to do it with timedelta, but can't seem to figure it out. Any advice would be appreciated.

Answer

Raymond Hettinger picture Raymond Hettinger · Nov 2, 2011

Using dict.get can simplify your code. It is a bit cleaner than using datetime.replace and timedelta objects.

Here's something to get you started:

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)