Prueba esto:
def monthdelta(date, delta):
m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12
if not m: m = 12
d = min(date.day, [31,
29 if y%4==0 and not y%400==0 else 28,31,30,31,30,31,31,30,31,30,31][m-1])
return date.replace(day=d,month=m, year=y)
>>> for m in range(-12, 12):
print(monthdelta(datetime.now(), m))
2009-08-06 16:12:27.823000
2009-09-06 16:12:27.855000
2009-10-06 16:12:27.870000
2009-11-06 16:12:27.870000
2009-12-06 16:12:27.870000
2010-01-06 16:12:27.870000
2010-02-06 16:12:27.870000
2010-03-06 16:12:27.886000
2010-04-06 16:12:27.886000
2010-05-06 16:12:27.886000
2010-06-06 16:12:27.886000
2010-07-06 16:12:27.886000
2010-08-06 16:12:27.901000
2010-09-06 16:12:27.901000
2010-10-06 16:12:27.901000
2010-11-06 16:12:27.901000
2010-12-06 16:12:27.901000
2011-01-06 16:12:27.917000
2011-02-06 16:12:27.917000
2011-03-06 16:12:27.917000
2011-04-06 16:12:27.917000
2011-05-06 16:12:27.917000
2011-06-06 16:12:27.933000
2011-07-06 16:12:27.933000
>>> monthdelta(datetime(2010,3,30), -1)
datetime.datetime(2010, 2, 28, 0, 0)
>>> monthdelta(datetime(2008,3,30), -1)
datetime.datetime(2008, 2, 29, 0, 0)
Editar Corregido para manejar el día también.
Editar Vea también la respuesta de la perplejidad que señala un cálculo más simple para d
:
d = min(date.day, calendar.monthrange(y, m)[1])
((date.month+delta-1) % 12)+1
obras y medios laif not m: m = 12
pueden quedar eliminadodt - timedelta(days=dt.day)
como se expresó originalmente, aunque parecía que querían poder restar un número arbitrario de meses y eso es un poco más difícil.Puede utilizar el
dateutil
módulo de terceros (entrada PyPI aquí ).salida:
fuente
month
ymonths
en dateutil. Restar con parammonth
no funciona peromonths
funcionaIn [23]: created_datetime__lt - relativedelta(months=1) Out[23]: datetime.datetime(2016, 11, 29, 0, 0, tzinfo=<StaticTzInfo 'Etc/GMT-8'>) In [24]: created_datetime__lt - relativedelta(month=1) Out[24]: datetime.datetime(2016, 1, 29, 0, 0, tzinfo=<StaticTzInfo 'Etc/GMT-8'>)
months
hará una diferencia de 1 mes. El usomonth
establecerá el mes en 1 (por ejemplo, enero), independientemente del mes de la entrada.Después de la edición de la pregunta original a "cualquier objeto de fecha y hora del mes anterior", puede hacerlo con bastante facilidad restando 1 día del primero del mes.
fuente
dt.replace(day=1) - timedelta(1)
dt - timedelta(days=dt.day)
Una variación de la respuesta de Duncan (no tengo suficiente reputación para comentar), que usa calendar.monthrange para simplificar drásticamente el cálculo del último día del mes:
Información sobre el rango de meses desde Obtener el último día del mes en Python
fuente
Una solución de pandas vectorizada es muy simple:
df['date'] - pd.DateOffset(months=1)
fuente
pandas
. ¡Gracias!¿Cuál quiere que sea el resultado cuando resta un mes de, digamos, una fecha que es el 30 de marzo? Ese es el problema de sumar o restar meses: ¡los meses tienen diferentes duraciones! En algunas aplicaciones, una excepción es apropiada en tales casos, en otras está bien usar "el último día del mes anterior" (pero eso es una aritmética realmente loca, cuando restar un mes y luego agregar un mes no es en general una no operación). , en otros, sin embargo, querrá mantener, además de la fecha, alguna indicación sobre el hecho, por ejemplo, "Digo el 28 de febrero, pero realmente me gustaría el 30 de febrero si existiera", de modo que sumar o restar otro mes para que puede arreglar las cosas de nuevo (y este último obviamente requiere una clase personalizada que contenga datos más algo más).
No puede haber una solución real que sea tolerable para todas las aplicaciones, y no nos ha dicho cuáles son las necesidades específicas de su aplicación para la semántica de esta lamentable operación, por lo que no hay mucha más ayuda que podamos brindar aquí.
fuente
datetime
módulos asumen que un día son exactamente 24 horas (sin segundosCreo que la forma sencilla es usar DateOffset de Pandas así:
El resultado será un objeto de fecha y hora
fuente
Si todo lo que desea es cualquier día del último mes, lo más simple que puede hacer es restar el número de días de la fecha actual, lo que le dará el último día del mes anterior.
Por ejemplo, comenzando con cualquier fecha:
Restando los días de la fecha actual obtenemos:
Esto es suficiente para su necesidad simplificada de cualquier día del último mes.
Pero ahora que lo tiene, también puede obtener cualquier día del mes, incluido el mismo día con el que comenzó (es decir, más o menos lo mismo que restar un mes):
Por supuesto, debe tener cuidado con el 31 en un mes de 30 días o los días que faltan de febrero (y cuidar los años bisiestos), pero eso también es fácil de hacer:
fuente
Utilizo esto para los años fiscales del gobierno donde el cuarto trimestre comienza el 1 de octubre. Tenga en cuenta que convierto la fecha en trimestres y también la deshago.
fuente
Aquí hay un código para hacer precisamente eso. No lo he probado yo mismo ...
fuente
Dada una tupla (año, mes), donde el mes va del 1 al 12, intente esto:
Supone que hay 12 meses en cada año.
fuente
fuente
Usé el siguiente código para retroceder n meses desde una fecha específica:
Por ejemplo: fecha de entrada = 28/12/2015 Calcular la fecha anterior de 6 meses.
I) CALCULAR MES: Este paso le dará la fecha de inicio como 30/06/2015.
Tenga en cuenta que después del paso de cálculo del mes obtendrá el último día del mes requerido.
II) CALCULATE DAY: Condición si (start_date.day> your_date.day) comprueba si el día de input_date está presente en el mes requerido. Esto maneja la condición donde la fecha de entrada es 31 (o 30) y el mes requerido tiene menos de 31 (o 30 en el caso de feb) días. También maneja casos de años bisiestos (para febrero). Después de este paso, obtendrá el resultado 28/06/2015
Si no se cumple esta condición, start_date sigue siendo la última fecha del mes anterior. Entonces, si da 31/12/2015 como fecha de entrada y desea 6 meses de fecha anterior, le dará 30/06/2015
fuente
Puede utilizar la función dada a continuación para obtener la fecha antes / después de X mes.
fuente
Creo que esta respuesta es bastante legible:
fuente
Un trazador de líneas ?
previous_month_date = (current_date - datetime.timedelta(days=current_date.day+1)).replace(day=current_date.day)
fuente
La forma más sencilla que he probado ahora
fuente
Hace algún tiempo me encontré con el siguiente algoritmo que funciona muy bien para aumentar y disminuir los meses ya sea en una
date
odatetime
.AVISO : Esto fallará si
day
no está disponible en el nuevo mes. Lo uso en objetos de fecha dondeday == 1
siempre.Python 3.x:
Para Python 2.7, cambie
//12
a solo/12
ya que está implícita la división de enteros.Recientemente usé esto en un archivo de valores predeterminados cuando un script comenzó a obtener estos globales útiles:
fuente
Solución simple, sin necesidad de bibliotecas especiales.
fuente
Podrías hacerlo en dos líneas como esta:
recuerda las importaciones
fuente