import mx.DateTime as dt
#6 Months
dt.now()+dt.RelativeDateTime(months=6)
#result is '2009-08-13 16:28:00.84'
#6*30 days
dt.now()+dt.RelativeDateTime(days=30*6)
#result is '2009-08-12 16:30:03.35'
from datetime import datetime, timedelta
from dateutil.relativedelta import *
date = datetime.now()
print(date)
# 2018-09-24 13:24:04.007620
date = date + relativedelta(months=+6)
print(date)
# 2019-03-24 13:24:04.007620
但是你需要安装 python-dateutil 模块:
pip install python-dateutil
2
我有更好的方法来解决'2月31日'的问题:
def add_months(start_date, months):
import calendar
year = start_date.year + (months / 12)
month = start_date.month + (months % 12)
day = start_date.day
if month > 12:
month = month % 12
year = year + 1
days_next = calendar.monthrange(year, month)[1]
if day > days_next:
day = days_next
return start_date.replace(year, month, day)
import calendar
from datetime import datetime
moths2add = 6
now = datetime.now()
current_year = now.year
current_month = now.month
#count days in months you want to add using calendar module
days = sum(
[calendar.monthrange(current_year, elem)[1] for elem in range(current_month, current_month + moths)]
)
print now + days
def add_months(d, months):
for i in range(4):
day = d.day - i
try:
return d.replace(day=day).replace(year=d.year+int(months)//12).replace(month=(d.month+int(months))%12)
except:
pass
raise Exception("should not happen")
def add_months(date, months, endOfMonthBehaviour='RoundUp'):
assert endOfMonthBehaviour in ['RoundDown', 'RoundIn', 'RoundOut', 'RoundUp'], \
'Unknown end of month behaviour'
year = date.year + (date.month + months - 1) / 12
month = (date.month + months - 1) % 12 + 1
day = date.day
last = monthrange(year, month)[1]
if day > last:
if endOfMonthBehaviour == 'RoundDown' or \
endOfMonthBehaviour == 'RoundOut' and months < 0 or \
endOfMonthBehaviour == 'RoundIn' and months > 0:
day = last
elif endOfMonthBehaviour == 'RoundUp' or \
endOfMonthBehaviour == 'RoundOut' and months > 0 or \
endOfMonthBehaviour == 'RoundIn' and months < 0:
# we don't need to worry about incrementing the year
# because there will never be a day in December > 31
month += 1
day = 1
return datetime.date(year, month, day)
>>> from calendar import monthrange
>>> import datetime
>>> add_months(datetime.datetime(2016, 1, 31), 1)
datetime.date(2016, 3, 1)
>>> add_months(datetime.datetime(2016, 1, 31), -2)
datetime.date(2015, 12, 1)
>>> add_months(datetime.datetime(2016, 1, 31), -2, 'RoundDown')
datetime.date(2015, 11, 30)
import datetime
'''
Created on 2011-03-09
@author: tonydiep
'''
def add_business_months(start_date, months_to_add):
"""
Add months in the way business people think of months.
Jan 31, 2011 + 1 month = Feb 28, 2011 to business people
Method: Add the number of months, roll back the date until it becomes a valid date
"""
# determine year
years_change = months_to_add / 12
# determine if there is carryover from adding months
if (start_date.month + (months_to_add % 12) > 12 ):
years_change = years_change + 1
new_year = start_date.year + years_change
# determine month
work = months_to_add % 12
if 0 == work:
new_month = start_date.month
else:
new_month = (start_date.month + (work % 12)) % 12
if 0 == new_month:
new_month = 12
# determine day of the month
new_day = start_date.day
if(new_day in [31, 30, 29, 28]):
#user means end of the month
new_day = 31
new_date = None
while (None == new_date and 27 < new_day):
try:
new_date = start_date.replace(year=new_year, month=new_month, day=new_day)
except:
new_day = new_day - 1 #wind down until we get to a valid date
return new_date
if __name__ == '__main__':
#tests
dates = [datetime.date(2011, 1, 31),
datetime.date(2011, 2, 28),
datetime.date(2011, 3, 28),
datetime.date(2011, 4, 28),
datetime.date(2011, 5, 28),
datetime.date(2011, 6, 28),
datetime.date(2011, 7, 28),
datetime.date(2011, 8, 28),
datetime.date(2011, 9, 28),
datetime.date(2011, 10, 28),
datetime.date(2011, 11, 28),
datetime.date(2011, 12, 28),
]
months = range(1, 24)
for start_date in dates:
for m in months:
end_date = add_business_months(start_date, m)
print("%s\t%s\t%s" %(start_date, end_date, m))
30 回答
我发现这个解决方案很好 . (这使用python-dateutil extension)
这种方法的优点是它可以处理28,30,31天等问题 . 这在处理业务规则和方案(比如发票生成等)时非常有用 .
那么,这取决于您从当前日期起6个月的含义 .
对于月初计算的开始:
你是什么意思'6个月' . 是2009-02-13 6个月== 2009-08-13还是2009-02-13 6 * 30天?
有关更多信息mx.DateTime
此解决方案适用于12月,此页面上的大多数答案都没有 . 在使用模数(%)或整数除法(//)之前,您需要首先将月份从基数1(即Jan = 1)转移到基数0(即Jan = 0),否则11月(11)加1个月给出12 ,当找到余数(12%12)给出0 .
(并且不建议“(月%12)1”或10月1日= 12月!)
但是......这并不像1月31日那样解决问题 . 所以我们回到OP - 添加一个月是什么意思?一个解决方案是回溯直到你到达有效的一天,因为大多数人会认为jan的最后一天,加上一个月,等于2月的最后一天 . 这也将在负数月份工作 . 证明:
我知道这已经有6个月了,但是如果你要添加一个月,谷歌的答案显示“在python中增加几个月”:
这将计算当前月份的天数,并将它们添加到当前日期,使用365/12将一年中的1/12可能会导致短期/长期的问题,如果您的迭代日期 .
使用Python的日期时间没有直接的方法 .
查看python-dateutil处的relativedelta类型 . 它允许您指定以月为单位的时间增量 .
所以,这里有一个
dateutil.relativedelta
的例子,我发现它可以用于迭代过去的一年,每次跳过一个月到现在的日期:和其他答案一样,你必须在“6个月后”找出你的真正含义 . 如果你的意思是“未来六个月的今天这个月”,那么这样做:
Dateutil package已实现此类功能 . 但请注意,这将是天真的,正如其他人已经指出的那样 .
只需使用timetuple方法提取月份,添加月份并构建新的日期对象 . 如果有一个已经存在的方法,我不知道 .
API有点笨拙,但作为一个例子 . 显然也不会像2008-01-31 1月那样在角落案件上工作 . :)
使用Python标准库,即没有
dateutil
或其他,并解决'February 31st'问题:测试:
使用Python 3.x,您可以这样做:
但是你需要安装 python-dateutil 模块:
我有更好的方法来解决'2月31日'的问题:
我认为它也适用于负数(减去几个月),但我没有对此进行过多次测试 .
PyQt4的QDate类具有addmonths函数 .
修改AddMonths()以在Zope中使用并处理无效的日期数:
这个怎么样?不使用其他库(
dateutil
)或timedelta
? Build 在vartec的答案上,我这样做了,我相信它有效:我尝试使用
timedelta
,但因为它计算的是日期,365/2
或6*356/12
并不总是转换为6个月,而是182天 . 例如我相信我们通常会假设从某一天开始的6个月将在该月的同一天降落但是在6个月之后(即
2015-03-10
- >2015-09-10
,不是2015-09-08
)我希望你觉得这有帮助 .
我这样解决了这个问题:
在1new_month = 121的案例中修改了Johannes Wei的答案 . 这对我来说非常有效 . 这几个月可能是积极的或消极的 .
还有另一种解决方案 - 希望有人会喜欢它:
对于所有情况,此解决方案在第29,30,31天都不起作用,因此需要更强大的解决方案(这不再那么好了:)):
从this answer,请参阅parsedatetime . 代码示例如下 . 更多细节:unit test with many natural-language -> YYYY-MM-DD conversion examples,明显parsedatetime conversion challenges/bugs .
该上面的代码从MacOSX机器生成以下内容:
这是一个示例,允许用户决定如何返回日期大于该月份天数的日期 .
假设您的datetime变量名为date:
在x个月之后/之前获得下一个日期的一般功能 .
使用python datetime模块向datetime.today()添加六个月的timedelta .
http://docs.python.org/library/datetime.html
你当然要解决JohannesWeiß提出的问题 - 你的意思是6个月?
这就是我提出的 . 它移动了正确的月数和年数,但忽略了几天(这是我在我的情况下所需要的) .
我用这个函数来改变年份和月份但是保持一天:
你应该写:
我认为做这样的事情而不是手动添加天数会更安全: