如何在不使用库的情况下在python中按自定义月份增加日期时间

How to increment datetime by custom months in python without using library

本问题已经有最佳答案,请猛点这里访问。

我需要增加日期时间值的月份

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

当月份为12时,它变为13并引发错误"月份必须在1到12之间"。(我预计这一年会增加)

我想使用TimeDelta,但它不需要月参数。有relativedelta python包,但我不想只为这个安装它。还有一个使用strtotime的解决方案。

1
2
time = strtotime(str(mydate));
next_month = date("Y-m-d", strtotime("+1 month", time));

我不想从datetime转换为str,然后转换为time,再转换为datetime;因此,它仍然是一个库

有没有人能像使用TimeDelta那样有任何好的简单的解决方案?


使用dateutil的relativedelta将一个月添加到一个日期,这是一种简短而甜蜜的方法。

1
2
3
4
5
6
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')

输出:

Today: 01/03/2013

After Month: 01/04/2013

警告一句:relativedelta(months=1)relativedelta(month=1)有不同的含义。通过month=1将取代原日期至1月的月份,而通过months=1将增加原日期一个月。

注:这需要python-dateutil。要安装它,您需要在Linux终端上运行。

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

说明:在python中添加月份值


编辑-根据您对需要向下取整的日期的评论,如果下个月的天数较少,下面是一个解决方案:

1
2
3
4
5
6
7
8
9
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)

使用中:

1
2
3
4
5
6
7
8
9
10
>>> 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,并将小时、分钟和秒从源复制到结果。


这是我的盐:

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

快速简单:)


既然没有人提出任何解决方案,下面是到目前为止我是如何解决的

1
2
3
4
5
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类似,但适用于日历月份而不是天/小时等。

下面是一个例子:

1
2
3
4
5
from monthdelta import MonthDelta

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

将其与DIY方法进行比较:

1
2
3
4
5
6
7
8
9
10
11
12
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


要计算当前、上个月和下个月:

1
2
3
4
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


1
2
3
4
5
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)

如果您只想要下个月的第一天:

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

也许可以使用calendar.monthrange()添加当前月份的天数?

1
2
3
4
5
6
7
8
9
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个月减到第30个月。

我就是这样做的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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


类似于戴夫·韦伯的解决方案,但没有所有复杂的模运算:

1
2
3
4
5
6
7
8
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)


这个怎么样?(不需要任何额外的库)

1
2
3
4
5
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)

有了一些调整和使用TimeDelta,我们开始:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
def add_month(d,n=1): return type(d)(d.year+(d.month+n-1)/12, (d.month+n-1)%12+1, 1)

我想解决的相关问题是找到下个月的第一个日期,而不管给定日期中的哪一天。这在1个月后的同一天找不到。

所以,如果你只想在2014年12月12日(或12月的任何一天)回到2015年1月1日,试试这个:

1
2
3
4
5
6
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天),并添加足够的天数以移动到下一个月:

1
2
3
4
5
6
>>> 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)

也适用于不同年份:

1
2
3
4
5
>>> 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)

请记住,不能保证下个月将有同一天,例如,从1月31日移到2月31日,它将失败:

1
2
3
4
5
6
>>> 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))。否则,要移动到最后一个可用日,您可能需要使用:

1
2
3
4
5
6
7
>>> 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)

只要用这个:

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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)

不使用日历的解决方案:

1
2
3
4
5
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))

这就是我想到的

1
2
3
4
5
6
7
8
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))


使用时间对象的示例:

1
2
3
4
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]))


我的解决方案非常简单,不需要任何附加模块:

1
2
3
4
5
6
7
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