ACTUALIZACIÓN: he agregado una solución al final de esta pregunta.¿Cuál es la manera más elegante de obtener el final del día (fecha y hora)?
Actualmente estoy escribiendo un código de informe que permite a los usuarios especificar opcionalmente un rango de fechas. La forma en que funciona (simplificado) es:
- Un usuario (opcionalmente) especifica un año.
- Un usuario (opcionalmente) especifica un mes.
- Un usuario (opcionalmente) especifica un día.
He aquí un fragmento de código, junto con los comentarios que describen lo que había como hacer:
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.
Estoy tratando de encontrar la manera más elegante de escribir el código anterior - I He estado tratando de encontrar una manera de hacerlo con timedelta, pero parece que no puedo resolverlo. Cualquier consejo sería apreciado.
Gracias.
EDITAR, SOLUCIÓN agregó:
Después de ver algunas de las respuestas aquí, y en realidad no encontrar nada muy elegante, hice un poco de hurgar la biblioteca estándar, y encontré mi solución actual (que me gusta bastante bien): dateutil.
Así es como yo implementé:
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 ...
Lo que me gusta de esta aplicación, es dateutil.relativedata.relativedata del pitón que funciona muy bien en casos extremos. Hace que los días/meses/años sean correctos. Si tengo month = 12 y do datos relativos (meses = 1), aumentará el año y establecerá el mes en 1 (funciona bien).
También: en la implementación anterior, si el usuario no especifica ninguna de las fechas opcionales (año, mes o día), recurriremos a un buen valor predeterminado (start_time = esta mañana, stop_time = esta noche), De manera predeterminada, haremos cosas solo para el día actual.
Gracias a todos por sus respuestas, fueron útiles en mi investigación.
El fin de cualquier día dado siempre sería '23: 59: 59.999' –
@MarcB Eso no es cierto durante los segundos intercalares, que son a las 23:59:60. –
Cierto, pero luego es bastante fácil agregar cheques para junio/diciembre: son lo suficientemente raros como para no preocupar a la mayoría de los sistemas. O ajuste la lógica de fecha para que sea '