barplot - Agregue un mes a una fecha determinada(día redondeado después) con Python
pandas plot (3)
Me gustaría agregar un mes a una fecha determinada
import datetime
dt = datetime.datetime(year=2014, month=5, day=2)
entonces debería obtener
datetime.datetime(year=2014, month=6, day=2)
pero con
dt = datetime.datetime(year=2015, month=1, day=31)
Debería obtener
datetime.datetime(year=2015, month=3, day=1)
porque no hay 2015-02-31 (y quiero que mi resultado sea redondo un día después )
¡Algunos meses tienen 31 días, otros 30, 29 y 28!
así que agregar un datetime.timedelta
probablemente no sea una buena manera de hacerlo (porque no sabemos la cantidad de días para agregar)
Noté que los pandas tienen un concepto interesante de DateOffset
http://pandas.pydata.org/pandas-docs/stable/timeseries.html#dateoffset-objects
pero no encontré una compensación de Month
, solo MonthBegin
o MonthEnd
También veo esta publicación. ¿Cómo calculo la fecha de seis meses a partir de la fecha actual usando el módulo Python de datetime?
así que probé dateutil.relativedelta
pero
from dateutil.relativedelta import relativedelta
datetime.datetime(year=2015, month=1, day=31)+relativedelta(months=1)
devoluciones
datetime.datetime(2015, 2, 28, 0, 0)
por lo que el resultado fue redondeado un día antes .
¿Hay una forma (limpia) de redondear el día después ?
editar: di un ejemplo con un mes para agregar, pero también quiero poder agregar, por ejemplo: 2 años y 6 meses (usando una relativedelta(years=2, months=6)
)
Esto parece funcionar Está bastante limpio, pero no es hermoso:
def add_month(now):
try:
then = (now + relativedelta(months=1)).replace(day=now.day)
except ValueError:
then = (now + relativedelta(months=2)).replace(day=1)
return then
for now in [datetime(2015, 1, 20), datetime(2015, 1, 31), datetime(2015, 2, 28)]:
print now, add_month(now)
huellas dactilares:
2015-01-20 00:00:00 2015-02-20 00:00:00
2015-01-31 00:00:00 2015-03-01 00:00:00
2015-02-28 00:00:00 2015-03-28 00:00:00
Agrega un mes e intenta reemplazar el día con el día original. Si tiene éxito, no es un caso especial. Si falla (ValueError), tenemos que agregar otro mes y pasar al primer día.
Puede usar dateutil.relativedelta.relativedelta
y verificar manualmente el atributo datetime.day
, si el día original es mayor que el nuevo día, luego agregue un día.
La función a continuación acepta un objeto datetime
y relativedelta
objeto relativedelta
. Tenga en cuenta que el siguiente código solo funciona durante años y meses, no creo que funcione si utiliza algo por debajo de eso (días, horas, etc.). Podría modificar fácilmente esta función para tomar years
y months
como argumentos y luego construir la relativedelta
dentro de la función misma.
from datetime import datetime
from dateutil.relativedelta import relativedelta
def add_time(d, rd):
day = relativedelta(days=+1)
out = d + rd
if d.day > out.day:
out = out + day
return out
# Check that it "rolls over"
print(add_time(datetime(year=2015, month=1, day=29), relativedelta(years=+4, months=+1))) # 2019-03-01 00:00:00
print(add_time(datetime(year=2015, month=3, day=31), relativedelta(years=+0, months=+2))) # 2015-05-01 00:00:00
# Check that it handles "normal" scenarios
print(add_time(datetime(year=2015, month=6, day=19), relativedelta(months=+1))) # 2015-07-19 00:00:00
print(add_time(datetime(year=2015, month=6, day=30), relativedelta(years=+2, months=+1))) # 2017-07-30 00:00:00
# Check across years
print(add_time(datetime(year=2015, month=12, day=25), relativedelta(months=+1))) # 2016-01-25 00:00:00
# Check leap years
print(add_time(datetime(year=2016, month=1, day=29), relativedelta(years=+4, months=+1))) # 2020-02-29 00:00:00
Solución rápida:
import datetime
import calendar
dt = datetime.datetime(year=2014, month=5, day=2)
d = calendar.monthrange(dt.year,dt.month+1)[1]
print dt+datetime.timedelta(days=d+1)
Salida para la primera entrada (year=2014, month=5, day=2)
:
2014-06-02 00:00:00
Salida para la segunda entrada (year=2015, month=1, day=31)
:
2015-03-01 00:00:00