Как увеличить datetime по пользовательским месяцам на python без использования библиотеки
Мне нужно увеличить месяц значения datetime
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?
Ответы
Ответ 1
Изменить - на основе вашего комментария о датах, которые необходимо округлить, если в следующем месяце будет меньше дней, вот решение:
>>> import datetime
>>> import calendar
>>>
>>> def add_months(sourcedate,months):
... month = sourcedate.month - 1 + months
... year = int(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
и копировать часы, минуты и секунды из источника в результат.
Ответ 2
Это короткий и сладкий метод добавления месяца к дате, используя dateutil relativedelta
.
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) имеют различные значения.
Примечание: для этого потребуется python-dateutil. для его установки необходимо запустить в терминале linux.
sudo apt-get update && sudo apt-get install python-dateutil
Объяснение: Добавить значение месяца в python
Ответ 3
Здесь моя соль:
current = datetime.datetime(mydate.year, mydate.month, 1)
next_month = datetime.datetime(mydate.year + (mydate.month / 12), ((mydate.month % 12) + 1), 1)
Быстро и просто:)
Ответ 4
так как никто не предложил никакого решения, вот как я решил до сих пор
year, month= divmod(mydate.month+1, 12)
if month == 0:
month = 12
year = year -1
next_month = datetime.datetime(mydate.year + year, month, 1)
Ответ 5
Используйте пакет 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
Ответ 6
Чтобы вычислить текущий, предыдущий и следующий месяц:
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
Ответ 7
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)
Ответ 8
Возможно, добавьте количество дней в текущем месяце, используя 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)
Ответ 9
Как насчет этого? (не требует дополнительных библиотек)
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)
Ответ 10
Эта реализация может иметь определенную ценность для тех, кто работает с биллингом.
Если вы работаете с биллингом, вы, вероятно, захотите получить "ту же дату в следующем месяце (если возможно)", а не "добавить 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
Ответ 11
Хорошо с некоторыми настройками и использованием 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()
Ответ 12
Аналогично в идеале для решения Dave Webb, но без всей этой сложной арифметики по модулю:
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)
Ответ 13
Я искал решение связанной проблемы поиска даты первого из следующего месяца независимо от дня в заданную дату. Это не находит тот же день через месяц.
Итак, если вы хотите только 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)
Ответ 14
Самое простое решение - пойти в конце месяца (мы всегда знаем, что у месяцев есть как минимум 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)
Ответ 15
Просто используйте это:
import datetime
today = datetime.datetime.today()
nextMonthDatetime = today + datetime.timedelta(days=(today.max.day - today.day)+1)
Ответ 16
Решение без использования календаря:
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))
Ответ 17
def add_month(d,n=1): return type(d)(d.year+(d.month+n-1)/12, (d.month+n-1)%12+1, 1)
Ответ 18
Вот что я придумал
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))
Ответ 19
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)
Ответ 20
пример использования объекта времени:
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]))
Ответ 21
Мое очень простое решение, которое не требует дополнительных модулей:
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