如何使用datetime Python模块计算从当前date起六个月的date?
我正在使用date时间的Python模块。 我正在计算从当前date起6个月的date。 有人可以给我一点帮助吗?
我想从当前date起6个月内生成一个date的原因是产生一个检查date。 如果用户将数据input系统,则从input数据之日起,审核date将为6个月。
import datetime print (datetime.date.today() + datetime.timedelta(6*365/12)).isoformat()
我发现这个解决scheme是好的。 (这使用python-dateutil扩展名 )
from datetime import date from dateutil.relativedelta import relativedelta six_months = date.today() + relativedelta(months=+6)
这种方法的优势在于,它可以在28,30,31天等情况下处理问题。这对于处理业务规则和场景(例如发票生成等)非常有用。
$ date(2010,12,31)+relativedelta(months=+1) datetime.date(2011, 1, 31) $ date(2010,12,31)+relativedelta(months=+2) datetime.date(2011, 2, 28)
那么,这取决于你从现在的date起6个月的意思。
-
使用自然月份:
(day, month, year) = (day, (month+6)%12, year+(month+6)/12)
-
用银行家的定义,6 * 30:
date += datetime.timedelta(6*30)
你是什么意思“六个月”。 是2009-02-13 + 6个月== 2009-08-13还是2009-02-13 + 6 * 30天?
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'
有关mx.DateTime的更多信息
Python的date时间没有直接的方法。
在python-dateutil中查看relativedeltatypes。 它允许你指定一个月份的时间增量。
这个解决scheme在十二月份正常工作,这个页面上的大部分答案都没有。 在使用模数(%)或整数除法(//)之前,您需要先将基数1(即1月= 1)的月份转换为基数0(即1月= 0),否则11月(11)加1个月会给您12 ,当find剩余的时候(12%12)给出0。
(并不build议“(月%12)+ 1”或十月+ 1 =十二月!)
def AddMonths(d,x): newmonth = ((( d.month - 1) + x ) % 12 ) + 1 newyear = d.year + ((( d.month - 1) + x ) / 12 ) return datetime.date( newyear, newmonth, d.day)
但是…这不包括1月31日+一个月的问题。 所以我们回到OP – 你是什么意思添加一个月? 一个解决scheme是回溯到有效的一天,因为大多数人会认为1月的最后一天,加上一个月,等于2月的最后一天。这个月也是负数。 certificate:
>>> import datetime >>> AddMonths(datetime.datetime(2010,8,25),1) datetime.date(2010, 9, 25) >>> AddMonths(datetime.datetime(2010,8,25),4) datetime.date(2010, 12, 25) >>> AddMonths(datetime.datetime(2010,8,25),5) datetime.date(2011, 1, 25) >>> AddMonths(datetime.datetime(2010,8,25),13) datetime.date(2011, 9, 25) >>> AddMonths(datetime.datetime(2010,8,25),24) datetime.date(2012, 8, 25) >>> AddMonths(datetime.datetime(2010,8,25),-1) datetime.date(2010, 7, 25) >>> AddMonths(datetime.datetime(2010,8,25),0) datetime.date(2010, 8, 25) >>> AddMonths(datetime.datetime(2010,8,25),-12) datetime.date(2009, 8, 25) >>> AddMonths(datetime.datetime(2010,8,25),-8) datetime.date(2009, 12, 25) >>> AddMonths(datetime.datetime(2010,8,25),-7) datetime.date(2010, 1, 25)>>>
Dateutil包已经实现了这样的function。 但是要知道,这将是天真的 ,正如其他人指出的那样。
我知道这是6个月,但是答案显示在谷歌的“添加python的月份”,如果你要增加一个月:
import calendar date = datetime.date.today() //Or your date datetime.timedelta(days=calendar.monthrange(date.year,date.month)[1])
这将计算当前月份的date,并将它们添加到当前date,如果您在date上迭代,则使用365/12年度广告的1/12可能会导致短/长月份的问题。
对于月初至月计算:
from datetime import timedelta from dateutil.relativedelta import relativedelta end_date = start_date + relativedelta(months=delta_period) + timedelta(days=-delta_period)
只需使用timetuple方法来提取月份,添加你的月份,并build立一个新的dateobject。 如果有一个已经存在的方法,我不知道它。
import datetime def in_the_future(months=1): year, month, day = datetime.date.today().timetuple()[:3] new_month = month + months return datetime.date(year + (new_month / 12), new_month % 12, day)
该API有点笨拙,但作为一个例子。 显然,2008-01-31 + 1个月的angular落案例也不会奏效。 🙂
所以,下面是dateutil.relativedelta
一个例子,我发现这个例子对于迭代过去的一年非常有用,每次都跳到现在的一个月:
>>> import datetime >>> from dateutil.relativedelta import relativedelta >>> today = datetime.datetime.today() >>> month_count = 0 >>> while month_count < 12: ... day = today - relativedelta(months=month_count) ... print day ... month_count += 1 ... 2010-07-07 10:51:45.187968 2010-06-07 10:51:45.187968 2010-05-07 10:51:45.187968 2010-04-07 10:51:45.187968 2010-03-07 10:51:45.187968 2010-02-07 10:51:45.187968 2010-01-07 10:51:45.187968 2009-12-07 10:51:45.187968 2009-11-07 10:51:45.187968 2009-10-07 10:51:45.187968 2009-09-07 10:51:45.187968 2009-08-07 10:51:45.187968
和其他答案一样,你必须从“现在起6个月”算出你的实际意思。 如果你的意思是“今后六个月的今天这一天”,那么这样做:
datetime.datetime.now() + relativedelta(months=6)
PyQt4的QDate类有一个addmonths函数。
>>>from PyQt4.QtCore import QDate >>>dt = QDate(2009,12,31) >>>required = dt.addMonths(6) >>>required PyQt4.QtCore.QDate(2010, 6, 30) >>>required.toPyDate() datetime.date(2010, 6, 30)
我有更好的办法来解决“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)
我认为它也适用于负数(减去几个月),但是我没有太多的testing。
修改了AddMonths()以在Zope中使用并处理无效日数:
def AddMonths(d,x): days_of_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] newmonth = ((( d.month() - 1) + x ) % 12 ) + 1 newyear = d.year() + ((( d.month() - 1) + x ) // 12 ) if d.day() > days_of_month[newmonth-1]: newday = days_of_month[newmonth-1] else: newday = d.day() return DateTime( newyear, newmonth, newday)
import time def add_month(start_time, months): ret = time.strptime(start_time, '%Y-%m-%d') t = list(ret) t[1] += months if t[1] > 12: t[0] += 1 + int(months / 12) t[1] %= 12 return int(time.mktime(tuple(t)))
这个怎么样? 不使用其他库( dateutil
)或timedelta
? build立在vartec的答案我做到了这一点,我相信它的工作原理:
import datetime today = datetime.date.today() six_months_from_today = datetime.date(today.year + (today.month + 6)/12, (today.month + 6) % 12, today.day)
我尝试使用timedelta
,但因为它正在计算的日子, 365/2
6*356/12
或6*356/12
365/2
并不总是翻译到6个月,而是182天。 例如
day = datetime.date(2015, 3, 10) print day >>> 2015-03-10 print (day + datetime.timedelta(6*365/12)) >>> 2015-09-08
我相信我们通常假设从某一天的6个月起,将会在当月的同一天但6个月后(即2015-03-10
– > 2015-09-10
,不是2015-09-08
)
我希望你觉得这有帮助。
我解决了这样的问题:
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
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))
修改Johannes Wei的答案在1new_month = 121的情况下,这对我来说非常合适。 这几个月可能是积极的或消极的。
def addMonth(d,months=1): year, month, day = d.timetuple()[:3] new_month = month + months return datetime.date(year + ((new_month-1) / 12), (new_month-1) % 12 +1, day)
另一个解决scheme – 希望有人会喜欢它:
def add_months(d, months): return d.replace(year=d.year+months//12).replace(month=(d.month+months)%12)
这个解决scheme在所有情况下都不能工作29,30,31天,所以需要更强大的解决scheme(这已经不是很好了:)):
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")
从这个答案 ,请参阅parsedatetime 。 代码示例如下。 更多细节: 使用许多自然语言的unit testing – > YYYY-MM-DD转换示例 ,以及明显的parsing时间转换挑战/错误 。
#!/usr/bin/env python # -*- coding: utf-8 -*- import time, calendar from datetime import date # from https://github.com/bear/parsedatetime import parsedatetime as pdt def print_todays_date(): todays_day_of_week = calendar.day_name[date.today().weekday()] print "today's date = " + todays_day_of_week + ', ' + \ time.strftime('%Y-%m-%d') def convert_date(natural_language_date): cal = pdt.Calendar() (struct_time_date, success) = cal.parse(natural_language_date) if success: formal_date = time.strftime('%Y-%m-%d', struct_time_date) else: formal_date = '(conversion failed)' print '{0:12s} -> {1:10s}'.format(natural_language_date, formal_date) print_todays_date() convert_date('6 months')
上面的代码从MacOSX机器生成以下代码:
$ ./parsedatetime_simple.py today's date = Wednesday, 2015-05-13 6 months -> 2015-11-13 $
因为你的date时间variables被称为date:
date=datetime.datetime(year=date.year+int((date.month+6)/12), month=(date.month+6)%13 + (1 if (date.month + months>12) else 0), day=date.day)
使用pythondate时间模块为datetime.today()添加六个月的timedelta。
http://docs.python.org/library/datetime.html
您当然必须解决JohannesWeiß提出的问题–您六个月的意思是什么?
这是我想出来的。 它移动正确的月数和年数,但忽略了几天(这是我所需要的情况)。
import datetime month_dt = 4 today = datetime.date.today() y,m = today.year, today.month m += month_dt-1 year_dt = m//12 new_month = m%12 new_date = datetime.date(y+year_dt, new_month+1, 1)
我使用这个function来改变年份和月份,但保持一天:
def replace_month_year(date1, year2, month2): try: date2 = date1.replace(month = month2, year = year2) except: date2 = datetime.date(year2, month2 + 1, 1) - datetime.timedelta(days=1) return date2
你应该写:
new_year = my_date.year + (my_date.month + 6) / 12 new_month = (my_date.month + 6) % 12 new_date = replace_month_year(my_date, new_year, new_month)
我认为这样做会更安全,而不是手动添加date:
import datetime today = datetime.date.today() def addMonths(dt, months = 0): new_month = months + dt.month year_inc = 0 if new_month>12: year_inc +=1 new_month -=12 return dt.replace(month = new_month, year = dt.year+year_inc) newdate = addMonths(today, 6)
我修改托尼diep的答案,可能稍微更优雅:
def add_months(date, months): month = date.month + months - 1 year = date.year + (month / 12) month = (month % 12) + 1 day = date.day while (day > 0): try: new_date = date.replace(year=year, month=month, day=day) break except: day = day - 1 return new_date
根据业务需求解释增加了几个月
返回user417751更早的答案。 也许不是如此pythonic的方式,但需要照顾不同的月份长度和闰年。 在这种情况下2012年1月31日+ 1个月= 2012年2月29日。
import datetime import calendar def add_mths(d, x): newday = d.day newmonth = (((d.month - 1) + x) % 12) + 1 newyear = d.year + (((d.month - 1) + x) // 12) if newday > calendar.mdays[newmonth]: newday = calendar.mdays[newmonth] if newyear % 4 == 0 and newmonth == 2: newday += 1 return datetime.date(newyear, newmonth, newday)
在这个函数中,n可以是正数也可以是负数。
def addmonth(d, n): n += 1 dd = datetime.date(d.year + n/12, d.month + n%12, 1)-datetime.timedelta(1) return datetime.date(dd.year, dd.month, min(d.day, dd.day))
下面是一个例子,它允许用户决定如何返回一天的date大于一个月中的天数。
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)