xticks barplot python pandas calendar timedelta python-dateutil

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