Как увеличить datetime на пользовательские месяцы в python без использования библиотеки [дубликат]
этот вопрос уже есть ответ здесь:
мне нужно увеличить месяц значения даты и времени
next_month = datetime.datetime(mydate.year, mydate.month+1, 1)
когда месяц равен 12, он становится 13 и вызывает ошибку "месяц должен быть в 1..12". (Я ожидал, что год будет увеличиваться)
Я хотел использовать timedelta, но это не займет месяц аргумента.
Есть relativedelta пакет python, но я не хочу устанавливать его только для этого.
Также есть решение с помощью strtotime.
time = strtotime(str(mydate));
next_month = date("Y-m-d", strtotime("+1 month", time));
Я не хочу конвертировать из datetime в str, а затем во время, а затем в datetime; поэтому это тоже библиотека
есть ли у кого-нибудь хорошие и простой решение так же, как с помощью timedelta?
21 ответов:
Edit - на основе вашего комментария даты должны быть округлены вниз, если есть меньше дней в следующем месяце, вот решение:
>>> 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) ... >>> 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)кроме того, если вы не беспокоитесь о часах, минутах и секундах, вы можете использовать
date, а неdatetime. Если вы беспокоитесь о часах, минутах и секундах вам нужно изменить мой код, чтобы использоватьdatetimeи копировать часы, минуты и секунды от источника к результату.
это короткий и сладкий метод, чтобы добавить месяц к дате с помощью dateutil это!--2-->.
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')выход:
сегодня: 01/03/2013
Через Месяц: 01/04/2013
предупреждение:
relativedelta(months=1)иrelativedelta(month=1)есть разное значение. Передаетmonth=1будет заменить месяц в исходную дату до января при прохожденииmonths=1добавить один месяц до первоначальной даты.Примечание: это требует
python-dateutil. Для установки нужно запустить в терминале Linux.sudo apt-get update && sudo apt-get install python-dateutilобъяснение : добавить значение месяца в python
вот моя соль :
current = datetime.datetime(mydate.year, mydate.month, 1) next_month = datetime.datetime(mydate.year + (mydate.month / 12), ((mydate.month % 12) + 1), 1)быстро и легко :)
так как никто не предложил никакого решения, вот как я решил до сих пор
year, month= divmod(mydate.month+1, 12) if month == 0: month = 12 year = year -1 next_month = datetime.datetime(mydate.year + year, month, 1)
использовать monthdelta пакет, он работает так же, как timedelta, но для календарных месяцев, а не дней/часов/и т. д.
вот пример:
from monthdelta import MonthDelta def prev_month(date): """Back one month and preserve day if possible""" return date + MonthDelta(-1)сравните это с подходом DIY:
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
для расчета текущего, предыдущего и следующего месяца:
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)Если вы просто хотите в первый день следующего месяца:
next = (x.replace(day=1) + timedelta(days=31)).replace(day=1)
возможно добавить количество дней в текущем месяце с помощью календаря.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)
эта реализация может иметь некоторое значение для тех, кто работает с биллингом.
Если вы работаете с биллингом, вы, вероятно, хотите получить "ту же дату в следующем месяце (если это возможно)", а не "добавить 1/12 одного года".
что так смущает в этом, вам действительно нужно учитывать два значения, если вы делаете это постоянно. В противном случае для любых дат после 27-го вы будете продолжать терять несколько дней, пока не окажетесь на 27-м после високосного года.
значения, которые необходимо учитывать:
- значение, которое вы хотите добавить в месяц
- день начался с
таким образом, если вы получите удар от 31-го до 30-го, когда вы добавите один месяц, вы получите удар обратно до 31-го в течение следующего месяца, который имеет этот день.
вот как я это сделал:
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
похоже в идеале на решение Дэйва Уэбба, но без всей этой сложной арифметики по модулю:
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)
Как насчет этого? (не требует никаких дополнительных библиотек)
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)
Просто Используйте Это:
import datetime today = datetime.datetime.today() nextMonthDatetime = today + datetime.timedelta(days=(today.max.day - today.day)+1)
Ну с некоторыми хитростями и использовать timedelta вот так:
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()
Я искал, чтобы решить проблемы, связанные с поиском первого числа следующего месяца, независимо от дня в данной дате. Это не найти позже в тот же день 1 месяц.
Итак, если все, что вы хотите, это поставить в декабре 12, 2014 (или в любой день в декабре) и вернуться 1 января 2015 года, попробуйте это:
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)
самое простое решение-пойти в конце месяца (мы всегда знаем, что месяцы имеют не менее 28 дней) и добавить достаточно дней, чтобы перейти к следующему мотыльку:
>>> 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)также работает с года:
>>> 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)просто имейте в виду, что не гарантируется, что в следующем месяце будет тот же день, например, при переходе с 31 января на 31 февраля он не будет:
>>> 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 "<stdin>", line 1, in <module> ValueError: day is out of range for monthтак что это правильное решение, если вам нужно перейти к первому дню следующего месяца, как вы всегда знаете, что в следующем месяце есть день 1 (
.replace(day=1)). В противном случае, чтобы перейти к последнему доступному дню, вы можете использовать:>>> 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)
решение без использования календарь:
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))
вот что я придумал
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)
пример использования объекта:
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]))
мое очень простое решение, которое не требует никаких дополнительных модулей:
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
Comments