lenguaje - python tutorial
Cómo redondear el minuto de un objeto python datetime (8)
Basado en Stijn Nevens y modificado para uso de Django para redondear la hora actual a los 15 minutos más cercanos.
from datetime import date, timedelta, datetime, time
def roundTime(dt=None, dateDelta=timedelta(minutes=1)):
roundTo = dateDelta.total_seconds()
if dt == None : dt = datetime.now()
seconds = (dt - dt.min).seconds
# // is a floor division, not a comment on following line:
rounding = (seconds+roundTo/2) // roundTo * roundTo
return dt + timedelta(0,rounding-seconds,-dt.microsecond)
dt = roundTime(datetime.now(),timedelta(minutes=15)).strftime(''%H:%M:%S'')
dt = 11:45:00
si necesita fecha y hora completas, simplemente elimine .strftime(''%H:%M:%S'')
Tengo un objeto datetime producido usando strptime ().
>>> tm
datetime.datetime(2010, 6, 10, 3, 56, 23)
Lo que tengo que hacer es redondear el minuto al décimo minuto más cercano. Lo que he estado haciendo hasta este momento fue tomar el valor de los minutos y usar round () en él.
min = round(tm.minute, -1)
Sin embargo, como en el ejemplo anterior, da un tiempo no válido cuando el valor de los minutos es mayor que 56. Ejemplo: 3:60
¿Cuál es una mejor manera de hacer esto? ¿Datetime apoya esto?
De la mejor respuesta que modifiqué a una versión adaptada usando solo objetos de fecha y hora, esto evita tener que hacer la conversión a segundos y hace que el código de llamada sea más legible:
def roundTime(dt=None, dateDelta=datetime.timedelta(minutes=1)):
"""Round a datetime object to a multiple of a timedelta
dt : datetime.datetime object, default now.
dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
Author: Thierry Husson 2012 - Use it as you want but don''t blame me.
Stijn Nevens 2014 - Changed to use only datetime objects as variables
"""
roundTo = dateDelta.total_seconds()
if dt == None : dt = datetime.datetime.now()
seconds = (dt - dt.min).seconds
# // is a floor division, not a comment on following line:
rounding = (seconds+roundTo/2) // roundTo * roundTo
return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)
Muestras con redondeo de 1 hora y redondeo de 15 minutos:
print roundTime(datetime.datetime(2012,12,31,23,44,59),datetime.timedelta(hour=1))
2013-01-01 00:00:00
print roundTime(datetime.datetime(2012,12,31,23,44,49),datetime.timedelta(minutes=15))
2012-12-31 23:30:00
Esto obtendrá el ''piso'' de un objeto datetime
almacenado en tm redondeado a la marca de 10 minutos antes de tm
.
tm = tm - datetime.timedelta(minutes=tm.minute % 10,
seconds=tm.second,
microseconds=tm.microsecond)
Si desea el redondeo clásico a la marca de 10 minutos más cercana, haga esto:
discard = datetime.timedelta(minutes=tm.minute % 10,
seconds=tm.second,
microseconds=tm.microsecond)
tm -= discard
if discard >= datetime.timedelta(minutes=5):
tm += datetime.timedelta(minutes=10)
o esto:
tm += datetime.timedelta(minutes=5)
tm -= datetime.timedelta(minutes=tm.minute % 10,
seconds=tm.second,
microseconds=tm.microsecond)
Función general para redondear una fecha y hora en cualquier momento vueltas en segundos:
def roundTime(dt=None, roundTo=60):
"""Round a datetime object to any time laps in seconds
dt : datetime.datetime object, default now.
roundTo : Closest number of seconds to round to, default 1 minute.
Author: Thierry Husson 2012 - Use it as you want but don''t blame me.
"""
if dt == None : dt = datetime.datetime.now()
seconds = (dt.replace(tzinfo=None) - dt.min).seconds
rounding = (seconds+roundTo/2) // roundTo * roundTo
return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)
Muestras con redondeo de 1 hora y redondeo de 30 minutos:
print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=60*60)
2013-01-01 00:00:00
print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=30*60)
2012-12-31 23:30:00
No es el mejor para la velocidad cuando se detecta la excepción, sin embargo, esto funcionaría.
def _minute10(dt=datetime.utcnow()):
try:
return dt.replace(minute=round(dt.minute, -1))
except ValueError:
return dt.replace(minute=0) + timedelta(hours=1)
Tiempos
%timeit _minute10(datetime(2016, 12, 31, 23, 55))
100000 loops, best of 3: 5.12 µs per loop
%timeit _minute10(datetime(2016, 12, 31, 23, 31))
100000 loops, best of 3: 2.21 µs per loop
Usé el código de Stijn Nevens con gran efecto (gracias Stijn) y tenía un pequeño complemento para compartir. Redondeando, bajando y redondeando al más cercano.
def round_time(dt=None, date_delta=timedelta(minutes=1), to=''average''):
"""
Round a datetime object to a multiple of a timedelta
dt : datetime.datetime object, default now.
dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
from: http://.com/questions/3463930/how-to-round-the-minute-of-a-datetime-object-python
"""
round_to = date_delta.total_seconds()
if dt is None:
dt = datetime.now()
seconds = (dt - dt.min).seconds
if to == ''up'':
# // is a floor division, not a comment on following line (like in javascript):
rounding = (seconds + round_to) // round_to * round_to
elif to == ''down'':
rounding = seconds // round_to * round_to
else:
rounding = (seconds + round_to / 2) // round_to * round_to
return dt + timedelta(0, rounding - seconds, -dt.microsecond)
si no desea usar la condición, puede usar el operador de modulo
:
minutes = int(round(tm.minute, -1)) % 60
ACTUALIZAR
¿Querías algo como esto?
def timeround10(dt):
a, b = divmod(round(dt.minute, -1), 60)
return ''%i:%02i'' % ((dt.hour + a) % 24, b)
timeround10(datetime.datetime(2010, 1, 1, 0, 56, 0)) # 0:56
# -> 1:00
timeround10(datetime.datetime(2010, 1, 1, 23, 56, 0)) # 23:56
# -> 0:00
.. si quieres el resultado como una cadena. para obtener un resultado de fecha y hora, es mejor usar timedelta - ver otras respuestas;)
def get_rounded_datetime(self, dt, freq, nearest_type=''inf''):
if freq.lower() == ''1h'':
round_to = 3600
elif freq.lower() == ''3h'':
round_to = 3 * 3600
elif freq.lower() == ''6h'':
round_to = 6 * 3600
else:
raise NotImplementedError("Freq %s is not handled yet" % freq)
# // is a floor division, not a comment on following line:
seconds_from_midnight = dt.hour * 3600 + dt.minute * 60 + dt.second
if nearest_type == ''inf'':
rounded_sec = int(seconds_from_midnight / round_to) * round_to
elif nearest_type == ''sup'':
rounded_sec = (int(seconds_from_midnight / round_to) + 1) * round_to
else:
raise IllegalArgumentException("nearest_type should be ''inf'' or ''sup''")
dt_midnight = datetime.datetime(dt.year, dt.month, dt.day)
return dt_midnight + datetime.timedelta(0, rounded_sec)