Как рассчитать дату через шесть месяцев от текущей даты, используя модуль Python datetime?

Я использую модуль даты и времени Python. Я рассчитываю рассчитать дату 6 месяцев с текущей даты. Может ли кто-нибудь помочь мне с этим?

Причина, по которой я хочу создать дату через 6 месяцев после текущей даты, заключается в создании даты проверки. Если пользователь вводит данные в систему, у него будет дата проверки 6 месяцев с даты ввода данных.

49 ответов

Решение
import datetime
print (datetime.date.today() + datetime.timedelta(6*365/12)).isoformat()

Я нашел это решение, чтобы быть хорошим. (Это использует расширение 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)

Ну, это зависит от того, что вы подразумеваете под 6 месяцами от текущей даты.

  1. Используя естественные месяцы:

    (day, month, year) = (day, (month+6)%12, year+(month+6)/12)
    
  2. Используя определение банкира, 6*30:

    date += datetime.timedelta(6*30)
    

С Python 3.x вы можете сделать это так:

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

Итак, вот пример 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)

Python может использовать для этого пакет datautil, см. Пример ниже

Это не ограничивается только этим, вы также можете передавать комбинацию дней, месяцев и лет одновременно.

      import datetime
from dateutil.relativedelta import relativedelta

# subtract months
proc_dt = datetime.date(2021,8,31)
proc_dt_minus_3_months = proc_dt + relativedelta(months=-3)
print(proc_dt_minus_3_months)

# add months
proc_dt = datetime.date(2021,8,31)
proc_dt_plus_3_months = proc_dt + relativedelta(months=+3)
print(proc_dt_plus_3_months)

# subtract days:
proc_dt = datetime.date(2021,8,31)
proc_dt_minus_3_days = proc_dt + relativedelta(days=-3)
print(proc_dt_minus_3_days)

# add days days:
proc_dt = datetime.date(2021,8,31)
proc_dt_plus_3_days = proc_dt + relativedelta(days=+3)
print(proc_dt_plus_3_days)

# subtract years:
proc_dt = datetime.date(2021,8,31)
proc_dt_minus_3_years = proc_dt + relativedelta(years=-3)
print(proc_dt_minus_3_years)

# add years:
proc_dt = datetime.date(2021,8,31)
proc_dt_plus_3_years = proc_dt + relativedelta(years=+3)
print(proc_dt_plus_3_years)

Результаты:

2021-05-31

2021-11-30

2021-08-28

2021-09-03

2018-08-31

2024-08-31

Для начала расчета месяца к месяцу:

from datetime import timedelta
from dateutil.relativedelta import relativedelta

end_date = start_date + relativedelta(months=delta_period) + timedelta(days=-delta_period)

Это решение работает правильно для декабря, что большинство ответов на этой странице нет. Прежде чем использовать модуль ( %) или целочисленное деление ( //), необходимо сначала сдвинуть месяцы с основания 1 (т.е. января = 1) на основание 0 (то есть января = 0), в противном случае ноябрь (11) плюс 1 месяц дает вам 12 что при нахождении остатка ( 12 % 12) дает 0.

(И не предлагайте "(месяц% 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)

Однако... Это не объясняет проблему, такую ​​как 31 января + один месяц. Итак, мы возвращаемся к ОП - что вы имеете в виду, добавляя месяц? Единственное, что нужно сделать, это вернуться назад, пока вы не доберетесь до действительного дня, учитывая, что большинство людей предполагает, что последний день января плюс один месяц равен последнему дню февраля. Это будет работать и при отрицательных числах месяцев. Доказательство:

>>> 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)>>> 

Это не отвечает на конкретный вопрос (используя datetime только), но, учитывая, что другие предлагали использовать разные модули, здесь есть решение, использующее pandas.

import datetime as dt
import pandas as pd

date = dt.date.today() - \
       pd.offsets.DateOffset(months=6)

print(date)

2019-05-04 00:00:00

Что работает должным образом в високосные годы

date = dt.datetime(2019,8,29) - \
       pd.offsets.DateOffset(months=6)
print(date)

2019-02-28 00:00:00

Что вы подразумеваете под "6 месяцев". 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.

Проверьте тип относительной дельты в ht tp://labix.org/python-dateutil. Позволяет указать дельту времени в месяцах.

Я знаю, что это было в течение 6 месяцев, однако ответ показывает в Google для "добавления месяцев в Python", если вы добавляете один месяц:

import calendar

date = datetime.date.today()    //Or your date

datetime.timedelta(days=calendar.monthrange(date.year,date.month)[1])

это будет считать дни в текущем месяце и добавлять их к текущей дате, использование 365/12 может привести к тому, что 1/12 года может вызвать проблемы для коротких / длинных месяцев, если вы выполняете итерацию по дате.

Просто используйте метод timetuple, чтобы извлечь месяцы, добавить свои месяцы и построить новый объект date. Если для этого уже существует метод, я не знаю его.

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 месяц.:)

Использование стандартных библиотек Python, т.е. без dateutil или другие, и решение проблемы "31 февраля":

import datetime
import calendar

def add_months(date, months):
    months_count = date.month + months

    # Calculate the year
    year = date.year + int(months_count / 12)

    # Calculate the month
    month = (months_count % 12)
    if month == 0:
        month = 12

    # Calculate the day
    day = date.day
    last_day_of_month = calendar.monthrange(year, month)[1]
    if day > last_day_of_month:
        day = last_day_of_month

    new_date = datetime.date(year, month, day)
    return new_date

Тестирование:

>>>date = datetime.date(2018, 11, 30)

>>>print(date, add_months(date, 3))
(datetime.date(2018, 11, 30), datetime.date(2019, 2, 28))

>>>print(date, add_months(date, 14))
(datetime.date(2018, 12, 31), datetime.date(2020, 2, 29))

В пакете Dateutil реализована такая функциональность. Но знайте, что это будет наивно, как уже указывали другие.

Быстрое предложение - Стрелка

pip install стрелка

>>> import arrow

>>> arrow.now().date()
datetime.date(2019, 6, 28)
>>> arrow.now().shift(months=6).date()
datetime.date(2019, 12, 28)

У меня есть лучший способ решить проблему "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)

Я думаю, что это также работает с отрицательными числами (чтобы вычесть месяцы), но я не очень проверял это.

Как насчет этого? Не использовать другую библиотеку (dateutil) или же timedelta? основываясь на ответе 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 месяцев, а скорее на 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)

Я надеюсь, что вы найдете это полезным.

Класс QDate PyQt4 имеет функцию 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)

Модифицированный ответ Йоханнеса Вея в случае 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)
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)))

Изменен 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)

Пересмотр более раннего ответа пользователя user417751. Может быть, не так питонски, но он заботится о разной длине месяца и високосных годах. В этом случае 31 января 2012 года + 1 месяц = ​​29 февраля 2012 года.

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)

Учитывая, что ваша переменная datetime называется 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)

"Python-dateutil" (внешнее расширение) - хорошее решение, но вы можете сделать это с помощью встроенных модулей Python (datetime и datetime).

Я сделал короткий и простой код, чтобы решить эту проблему (год, месяц и день)

(работает: Python 3.8.2)

from datetime import datetime
from calendar import monthrange

# Time to increase (in months)
inc = 12

# Returns mod of the division for 12 (months)
month = ((datetime.now().month + inc) % 12) or 1

# Increase the division by 12 (months), if necessary (+ 12 months increase)
year = datetime.now().year + int((month + inc) / 12)

# (IF YOU DON'T NEED DAYS,CAN REMOVE THE BELOW CODE)
# Returns the same day in new month, or the maximum day of new month
day = min(datetime.now().day,monthrange(year, month)[1])

print("Year: {}, Month: {}, Day: {}".format(year, month, day))

Мне часто нужно, чтобы последний день месяца оставался последним днем ​​месяца. Чтобы решить эту проблему, я добавляю один день перед расчетом, а затем снова вычитаю его перед возвратом.

from datetime import date, timedelta

# it's a lot faster with a constant day
DAY = timedelta(1)

def add_month(a_date, months):
    "Add months to date and retain last day in month."
    next_day = a_date + DAY
    # calculate new year and month
    m_sum = next_day.month + months - 1
    y = next_day.year + m_sum // 12
    m = m_sum % 12 + 1
    try:
        return date(y, m, next_day.day) - DAY
    except ValueError:
        # on fail return last day in month
        # can't fail on december so I don't bother changing the year
        return date(y, m + 1, 1) - DAY

Я звоню в конце, но

проверить модуль Кена Рейтца Майя,

https://github.com/kennethreitz/maya

что-то вроде этого может помочь вам, просто измените часы =1 на дни =1 или годы =1

>>> from maya import MayaInterval

# Create an event that is one hour long, starting now.
>>> event_start = maya.now()
>>> event_end = event_start.add(hours=1)

>>> event = MayaInterval(start=event_start, end=event_end)
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))

Еще одно решение - надеюсь, кому-то понравится:

def add_months(d, months):
    return d.replace(year=d.year+months//12).replace(month=(d.month+months)%12)

Это решение не работает в течение 29,30,31 дней для всех случаев, поэтому требуется более надежное решение (что уже не так приятно:)):

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. Пример кода приведен ниже. Более подробная информация: модульное тестирование с множеством примеров преобразования на естественном языке -> ГГГГ-ММ-ДД и очевидные проблемы / ошибки преобразования во время анализа.

#!/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
$ 
Другие вопросы по тегам