Cómo incrementar datetime por meses personalizados en python sin usar la biblioteca

Necesito incrementar el mes de un valor de fecha y hora.

next_month = datetime.datetime(mydate.year, mydate.month+1, 1) 

cuando el mes es 12, se convierte en 13 y genera un error “el mes debe estar en 1..12”. (Esperaba que el año boosta)

Quería usar timedelta, pero no lleva meses discutiendo. Hay un paquete de Python relativedelta , pero no quiero instalarlo solo para esto. También hay una solución usando strtotime .

 time = strtotime(str(mydate)); next_month = date("Ymd", strtotime("+1 month", time)); 

No quiero convertir de datetime a str, luego a time, y luego a datetime; por lo tanto, sigue siendo una biblioteca también

¿Alguien tiene alguna solución buena y simple como usar timedelta?

Editar : en función de su comentario de las fechas que se necesitan redondear hacia abajo si hay menos días en el próximo mes, aquí hay una solución:

 import datetime import calendar def add_months(sourcedate, months): month = sourcedate.month - 1 + months year = sourcedate.year + month // 12 month = month % 12 + 1 day = min(sourcedate.day, calendar.monthrange(year,month)[1]) return datetime.date(year, month, day) 

En uso:

 >>> somedate = datetime.date.today() >>> somedate datetime.date(2010, 11, 9) >>> add_months(somedate,1) datetime.date(2010, 12, 9) >>> add_months(somedate,23) datetime.date(2012, 10, 9) >>> otherdate = datetime.date(2010,10,31) >>> add_months(otherdate,1) datetime.date(2010, 11, 30) 

Además, si no le preocupan las horas, los minutos y los segundos, puede usar la date lugar de la date y datetime . Si le preocupan las horas, los minutos y los segundos, debe modificar mi código para usar datetime y copiar horas, minutos y segundos desde la fuente hasta el resultado.

Este es un método breve y dulce para agregar un mes a una fecha usando el relativedelta de dateutil .

 from datetime import datetime from dateutil.relativedelta import relativedelta date_after_month = datetime.today()+ relativedelta(months=1) print 'Today: ',datetime.today().strftime('%d/%m/%Y') print 'After Month:', date_after_month.strftime('%d/%m/%Y') 

Salida:

Hoy: 01/03/2013

Después del mes: 01/04/2013

Una advertencia : relativedelta(months=1) y relativedelta(month=1) tienen diferentes significados . El month=1 pasa month=1 reemplazará el mes en la fecha original a enero, mientras que los months=1 que pasan months=1 agregarán un mes a la fecha original.

Nota: esto requerirá python-dateutil . Para instalarlo necesitas ejecutarlo en el terminal de Linux.

 sudo apt-get update && sudo apt-get install python-dateutil 

Explicación: Agregar el valor del mes en Python

Aquí está mi sal:

 current = datetime.datetime(mydate.year, mydate.month, 1) next_month = datetime.datetime(mydate.year + (mydate.month / 12), ((mydate.month % 12) + 1), 1) 

Rapido y Facil 🙂

ya que nadie sugirió ninguna solución, aquí está cómo resolví hasta ahora

 year, month= divmod(mydate.month+1, 12) if month == 0: month = 12 year = year -1 next_month = datetime.datetime(mydate.year + year, month, 1) 

Use el paquete monthdelta , funciona igual que timedelta pero por meses calendario en lugar de días / horas / etc.

Aquí hay un ejemplo:

 from monthdelta import MonthDelta def prev_month(date): """Back one month and preserve day if possible""" return date + MonthDelta(-1) 

Compare eso con el enfoque de bricolaje:

 def prev_month(date): """Back one month and preserve day if possible""" day_of_month = date.day if day_of_month != 1: date = date.replace(day=1) date -= datetime.timedelta(days=1) while True: try: date = date.replace(day=day_of_month) return date except ValueError: day_of_month -= 1 

Para calcular el mes actual, anterior y siguiente:

 import datetime this_month = datetime.date.today().month last_month = datetime.date.today().month - 1 or 12 next_month = (datetime.date.today().month + 1) % 12 or 12 
 from datetime import timedelta try: next = (x.replace(day=1) + timedelta(days=31)).replace(day=x.day) except ValueError: # January 31 will return last day of February. next = (x + timedelta(days=31)).replace(day=1) - timedelta(days=1) 

Si simplemente quieres el primer día del próximo mes:

 next = (x.replace(day=1) + timedelta(days=31)).replace(day=1) 

Tal vez agregue el número de días en el mes actual usando calendar.monthrange ()?

 import calendar, datetime def increment_month(when): days = calendar.monthrange(when.year, when.month)[1] return when + datetime.timedelta(days=days) now = datetime.datetime.now() print 'It is now %s' % now print 'In a month, it will be %s' % increment_month(now) 

Esta implementación podría tener algún valor para alguien que está trabajando con la facturación.

Si está trabajando con la facturación, probablemente desee obtener “la misma fecha el próximo mes (si es posible)” en lugar de “agregar 1/12 de un año”.

Lo que es tan confuso acerca de esto es que realmente necesita tener en cuenta dos valores si está haciendo esto continuamente. De lo contrario, para cualquier fecha posterior al 27, seguirá perdiendo algunos días hasta que termine el 27 después del año bisiesto.

Los valores que debe tener en cuenta:

  • El valor que desea agregar un mes a
  • El dia que empezaste

De esta manera, si recibe un golpe desde el 31 hasta el 30 cuando agrega un mes, recibirá un salto hasta el 31 para el próximo mes que tiene ese día.

Así es como lo hice:

 def closest_date_next_month(year, month, day): month = month + 1 if month == 13: month = 1 year = year + 1 condition = True while condition: try: return datetime.datetime(year, month, day) except ValueError: day = day-1 condition = day > 26 raise Exception('Problem getting date next month') paid_until = closest_date_next_month( last_paid_until.year, last_paid_until.month, original_purchase_date.day) # The trick is here, I'm using the original date, that I started adding from, not the last one 

Similar en ideal a la solución de Dave Webb, pero sin toda esa aritmética modular modular:

 import datetime, calendar def increment_month(date): # Go to first of this month, and add 32 days to get to the next month next_month = date.replace(day=1) + datetime.timedelta(32) # Get the day of month that corresponds day = min(date.day, calendar.monthrange(next_month.year, next_month.month)[1]) return next_month.replace(day=day) 

¿Qué hay de este? (no requiere ninguna biblioteca extra)

 from datetime import date, timedelta from calendar import monthrange today = date.today() month_later = date(today.year, today.month, monthrange(today.year, today.month)[1]) + timedelta(1) 

Bueno, con algunos ajustes y uso de timedelta aquí vamos:

 from datetime import datetime, timedelta def inc_date(origin_date): day = origin_date.day month = origin_date.month year = origin_date.year if origin_date.month == 12: delta = datetime(year + 1, 1, day) - origin_date else: delta = datetime(year, month + 1, day) - origin_date return origin_date + delta final_date = inc_date(datetime.today()) print final_date.date() 

Estaba buscando resolver el problema relacionado de encontrar la fecha para el primer día del mes siguiente, independientemente del día en la fecha dada. Esto no se encuentra el mismo día 1 mes después.

Entonces, si todo lo que quieres es ponerlo en diciembre 12, 2014 (o cualquier día en diciembre) y regresar el 1 de enero de 2015, prueba esto:

 import datetime def get_next_month(date): month = (date.month % 12) + 1 year = date.year + (date.month + 1 > 12) return datetime.datetime(year, month, 1) 
 def add_month(d,n=1): return type(d)(d.year+(d.month+n-1)/12, (d.month+n-1)%12+1, 1) 

La solución más simple es ir al final del mes (siempre sabemos que los meses tienen al menos 28 días) y agregar suficientes días para pasar a la siguiente polilla:

 >>> from datetime import datetime, timedelta >>> today = datetime.today() >>> today datetime.datetime(2014, 4, 30, 11, 47, 27, 811253) >>> (today.replace(day=28) + timedelta(days=10)).replace(day=today.day) datetime.datetime(2014, 5, 30, 11, 47, 27, 811253) 

También funciona entre años:

 >>> dec31 datetime.datetime(2015, 12, 31, 11, 47, 27, 811253) >>> today = dec31 >>> (today.replace(day=28) + timedelta(days=10)).replace(day=today.day) datetime.datetime(2016, 1, 31, 11, 47, 27, 811253) 

Solo tenga en cuenta que no está garantizado que el próximo mes tenga el mismo día, por ejemplo, al pasar del 31 de enero al 31 de febrero, fallará:

 >>> today datetime.datetime(2016, 1, 31, 11, 47, 27, 811253) >>> (today.replace(day=28) + timedelta(days=10)).replace(day=today.day) Traceback (most recent call last): File "", line 1, in  ValueError: day is out of range for month 

Entonces, esta es una solución válida si necesita pasar al primer día del mes siguiente, ya que siempre sabe que el mes siguiente tiene el día 1 ( .replace(day=1) ). De lo contrario, para pasar al último día disponible, es posible que desee utilizar:

 >>> today datetime.datetime(2016, 1, 31, 11, 47, 27, 811253) >>> next_month = (today.replace(day=28) + timedelta(days=10)) >>> import calendar >>> next_month.replace(day=min(today.day, calendar.monthrange(next_month.year, next_month.month)[1])) datetime.datetime(2016, 2, 29, 11, 47, 27, 811253) 

Una solución sin el uso del calendario:

 def add_month_year(date, years=0, months=0): year, month = date.year + years, date.month + months + 1 dyear, month = divmod(month - 1, 12) rdate = datetime.date(year + dyear, month + 1, 1) - datetime.timedelta(1) return rdate.replace(day = min(rdate.day, date.day)) 

Solo usa esto:

 import datetime today = datetime.datetime.today() nextMonthDatetime = today + datetime.timedelta(days=(today.max.day - today.day)+1) 

Esto es lo que se me ocurrió

 from calendar import monthrange def same_day_months_after(start_date, months=1): target_year = start_date.year + ((start_date.month + months) / 12) target_month = (start_date.month + months) % 12 num_days_target_month = monthrange(target_year, target_month)[1] return start_date.replace(year=target_year, month=target_month, day=min(start_date.day, num_days_target_month)) 
 def month_sub(year, month, sub_month): result_month = 0 result_year = 0 if month > (sub_month % 12): result_month = month - (sub_month % 12) result_year = year - (sub_month / 12) else: result_month = 12 - (sub_month % 12) + month result_year = year - (sub_month / 12 + 1) return (result_year, result_month) def month_add(year, month, add_month): return month_sub(year, month, -add_month) >>> month_add(2015, 7, 1) (2015, 8) >>> month_add(2015, 7, 20) (2017, 3) >>> month_add(2015, 7, 12) (2016, 7) >>> month_add(2015, 7, 24) (2017, 7) >>> month_add(2015, 7, -2) (2015, 5) >>> month_add(2015, 7, -12) (2014, 7) >>> month_add(2015, 7, -13) (2014, 6) 

Ejemplo usando el objeto de tiempo:

 start_time = time.gmtime(time.time()) # start now #increment one month start_time = time.gmtime(time.mktime([start_time.tm_year, start_time.tm_mon+1, start_time.tm_mday, start_time.tm_hour, start_time.tm_min, start_time.tm_sec, 0, 0, 0])) 

Mi solución muy simple, que no requiere ningún módulo adicional:

 def addmonth(date): if date.day < 20: date2 = date+timedelta(32) else : date2 = date+timedelta(25) date2.replace(date2.year, date2.month, day) return date2