round python math datetime ceil

python round up



Python-Ceil a datetime para el próximo cuarto de hora (4)

¡Éste tiene en cuenta los microsegundos!

import math def ceil_dt(dt): # how many secs have passed this hour nsecs = dt.minute*60 + dt.second + dt.microsecond*1e-6 # number of seconds to next quarter hour mark # Non-analytic (brute force is fun) way: # delta = next(x for x in xrange(0,3601,900) if x>=nsecs) - nsecs # analytic way: delta = math.ceil(nsecs / 900) * 900 - nsecs #time + number of seconds to quarter hour mark. return dt + datetime.timedelta(seconds=delta) t1 = datetime.datetime(2017, 3, 6, 7, 0) assert ceil_dt(t1) == t1 t2 = datetime.datetime(2017, 3, 6, 7, 1) assert ceil_dt(t2) == datetime.datetime(2017, 3, 6, 7, 15) t3 = datetime.datetime(2017, 3, 6, 7, 15) assert ceil_dt(t3) == t3 t4 = datetime.datetime(2017, 3, 6, 7, 16) assert ceil_dt(t4) == datetime.datetime(2017, 3, 6, 7, 30) t5 = datetime.datetime(2017, 3, 6, 7, 30) assert ceil_dt(t5) == t5 t6 = datetime.datetime(2017, 3, 6, 7, 31) assert ceil_dt(t6) == datetime.datetime(2017, 3, 6, 7, 45) t7 = datetime.datetime(2017, 3, 6, 7, 45) assert ceil_dt(t7) == t7 t8 = datetime.datetime(2017, 3, 6, 7, 46) assert ceil_dt(t8) == datetime.datetime(2017, 3, 6, 8, 0)

Explicación del delta :

  • 900 segundos son 15 minutos (un cuarto de hora sin segundos de salto, lo cual no creo que datetime maneje ... )
  • nsecs / 900 es el número de trozos de cuarto de hora que han transcurrido. Tomando el ceil de este número se redondea la cantidad de trozos de cuarto de hora.
  • Multiplique el número de segmentos de cuarto de hora por 900 para calcular cuántos segundos han transcurrido desde el comienzo de la hora después del "redondeo".

Imaginemos esta fecha y hora

>>> import datetime >>> dt = datetime.datetime(2012, 10, 25, 17, 32, 16)

Me gustaría ceñirlo al siguiente cuarto de hora para obtener

datetime.datetime(2012, 10, 25, 17, 45)

Me imagino algo como

>>> quarter = datetime.timedelta(minutes=15) >>> import math >>> ceiled_dt = math.ceil(dt / quarter) * quarter

Pero claro que esto no funciona.


Solo necesita calcular los minutos correctos y agregarlos en el objeto datetime después de configurar los minutos, segundos a cero

import datetime def quarter_datetime(dt): minute = (dt.minute//15+1)*15 return dt.replace(minute=0, second=0)+datetime.timedelta(minutes=minute) for minute in [12, 22, 35, 52]: print quarter_datetime(datetime.datetime(2012, 10, 25, 17, minute, 16))

Funciona para todos los casos:

2012-10-25 17:15:00 2012-10-25 17:30:00 2012-10-25 17:45:00 2012-10-25 18:00:00


@Mark Dickinson sugirió la mejor fórmula hasta ahora:

def ceil_dt(dt, delta): return dt + (datetime.min - dt) % delta

En Python 3, para un delta de tiempo arbitrario (no solo 15 minutos):

#!/usr/bin/env python3 import math from datetime import datetime, timedelta def ceil_dt(dt, delta): return datetime.min + math.ceil((dt - datetime.min) / delta) * delta print(ceil_dt(datetime(2012, 10, 25, 17, 32, 16), timedelta(minutes=15))) # -> 2012-10-25 17:45:00

Para evitar flotadores intermedios, divmod() podría ser usado:

def ceil_dt(dt, delta): q, r = divmod(dt - datetime.min, delta) return (datetime.min + (q + 1)*delta) if r else dt

Ejemplo:

>>> ceil_dt(datetime(2012, 10, 25, 17, 32, 16), timedelta(minutes=15)) datetime.datetime(2012, 10, 25, 17, 45) >>> ceil_dt(datetime.min, datetime.resolution) datetime.datetime(1, 1, 1, 0, 0) >>> ceil_dt(datetime.min, 2*datetime.resolution) datetime.datetime(1, 1, 1, 0, 0) >>> ceil_dt(datetime.max, datetime.resolution) datetime.datetime(9999, 12, 31, 23, 59, 59, 999999) >>> ceil_dt(datetime.max, 2*datetime.resolution) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in ceil_dt OverflowError: date value out of range >>> ceil_dt(datetime.min+datetime.resolution, datetime.resolution) datetime.datetime(1, 1, 1, 0, 0, 0, 1) >>> ceil_dt(datetime.min+datetime.resolution, 2*datetime.resolution) datetime.datetime(1, 1, 1, 0, 0, 0, 2) >>> ceil_dt(datetime.max-datetime.resolution, datetime.resolution) datetime.datetime(9999, 12, 31, 23, 59, 59, 999998) >>> ceil_dt(datetime.max-datetime.resolution, 2*datetime.resolution) datetime.datetime(9999, 12, 31, 23, 59, 59, 999998) >>> ceil_dt(datetime.max-2*datetime.resolution, datetime.resolution) datetime.datetime(9999, 12, 31, 23, 59, 59, 999997) >>> ceil_dt(datetime.max-2*datetime.resolution, 2*datetime.resolution) datetime.datetime(9999, 12, 31, 23, 59, 59, 999998) >>> ceil_dt(datetime.max-timedelta(1), datetime.resolution) datetime.datetime(9999, 12, 30, 23, 59, 59, 999999) >>> ceil_dt(datetime.max-timedelta(1), 2*datetime.resolution) datetime.datetime(9999, 12, 31, 0, 0) >>> ceil_dt(datetime.min, datetime.max-datetime.min) datetime.datetime(1, 1, 1, 0, 0) >>> ceil_dt(datetime.max, datetime.max-datetime.min) datetime.datetime(9999, 12, 31, 23, 59, 59, 999999)


def ceil(dt): if dt.minute % 15 or dt.second: return dt + datetime.timedelta(minutes = 15 - dt.minute % 15, seconds = -(dt.second % 60)) else: return dt

Esto te da:

>>> ceil(datetime.datetime(2012,10,25, 17,45)) datetime.datetime(2012, 10, 25, 17, 45) >>> ceil(datetime.datetime(2012,10,25, 17,45,1)) datetime.datetime(2012, 10, 25, 18, 0) >>> ceil(datetime.datetime(2012,12,31,23,59,0)) datetime.datetime(2013,1,1,0,0)