datetime Pythonモジュールを使用して、現在の日付から6か月の日付を計算するにはどうすればよいですか?


391

datetime Pythonモジュールを使用しています。現在の日付から6か月後の日付を計算しようとしています。誰かがこれを行うのに少し助けてくれますか?

現在の日付から6か月後に日付を生成したいのは、レビュー日付を作成するためです。ユーザーがシステムにデータを入力した場合、データを入力した日から6か月のレビュー日があります。


2
より具体的にする必要があります。3月31日から6か月はいつですか。そして8月30日から?
kmkaplan 2009

3
はい、編集は役立ちます:それはあなたが悪影響なしでおよそ6か月から183日を過ごすことができることを意味します。したがって、今日に183日を追加すると、うまくいきます。
kmkaplan 2009

15
上記のコメントは私をばかげているように思います。「6か月を追加する」という概念は非常に明確です。12月を過ぎる6と、1か月のローリング(および月をに戻す1)のサポートにより、月コンポーネントを追加します。これは、まさにrelativedeltaこのような概念をサポートするすべてのプログラミング言語が実際に行っていることであり、実際にそうなっています。
カークウォル

5
@KirkWoll:はっきりしていると思います。しかし、話す人にとってはまだ違います。Python:date(2015, 3, 31) + relativedelta(months = 6)を与えdatetime.date(2015, 9, 30)ます。Perl:DateTime->new(year=>2000, month=>3, day=>31)->add(months=>6)を与え2000-10-01T00:00:00ます。Php:date_create('2000-03-31', new DateTimeZone('UTC'))->add(new DateInterval('P6M'))2000-10-01を返します。毒を選びなさい。
kmkaplan 2015

2
... 182を追加することは、レビュー日付を生成するためにより実用的であるように見えます。それは、曜日をそのままに保ちます
Wolfが

回答:


1047

この解決策は良いと思いました。(これは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)

2
+6は-6になる可能性があることを示すもので、同じことが日と年にも
当てはまり

5
@sliders_alpha python-dateutilパッケージをインストールする必要があります(pip install python-dateutil)
poiuytrez

18
これが正しい解決策です。OPが6か月ではなく6年を要求した場合、承認された回答は無残に失敗します。そのため、一般化された回答ほど価値が高くなることに留意してください。
ダニエルF

3
このrelativedelta関数monthは引数としても受け取ることに注意してください。これは基本的に、渡された日付の月を置換/設定/修正します。これは、月を追加することとは大きく異なります。彼らは余分に忘れてしまったので、機能が壊れている場合には不思議な人々のためだけの事前警告ヶ月
shad0w_wa1k3r

1
私は興味があります:これがデフォルトで含まれていない理由を誰かが知っていますか?Timedeltaはdatetimeデフォルトでパッケージ化されているようです。私は実際に「月」をtimedeltaに渡すことができると思いました。
dTanMan

51

まあ、それはあなたが現在の日付から6か月までに何を意味するかによって異なります。

  1. 自然な月を使用する:

    (day, month, year) = (day, (month + 5) % 12 + 1, year + (month + 5)/12)
  2. 銀行家の定義を使用して、6 * 30:

    date += datetime.timedelta(6 * 30)

3
半年の定義(183日)と26週間の定義も一緒に投入できますか?それらすべてを1か所にまとめることができます。
S.Lott、2009

11
簡単なコメント:月の場合、式は(月+ 5)%12 + 1 b / c(6月の場合)になると思います。式は0ですが、期待される結果は12です...この小さなエラーにもかかわらず、私の心、あなたの答えは質問に最もよく答えるものです
PierrOz

3
年も同じ:年+(月+ 5)/ 12
PierrOz

7
日付が31で、6か月後の月に31日を含めることができない場合はどうなりますか(31日のほとんどの月に当てはまります)。
akv 2011

4
->(day, month, year) = (day, (month+6)%12, year+(month+6)/12)(31, 8, 2015)(31, 2, 2016)
ohw

37

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

賛成票pip install ...
ネイサン

お勧めしfrom dateutil.relativedelta import relativedeltaます。使用import *は明示的ではありません。
サムモーガン

19

月初めの計算の場合:

from datetime import timedelta
from dateutil.relativedelta import relativedelta

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

18
これは、コメントで前述したrelativedeltaソリューションではありません。600以上の賛成票でソリューションをスクロールし続けます。
Nostalg.io 2018

15

「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に関する詳細情報


14

だから、ここに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か月後」までに実際の意味を理解する必要があります。「6年後の月の今日の日」を意味する場合は、次のようになります。

datetime.datetime.now() + relativedelta(months=6)

14

このソリューションは12月に正しく機能しますが、このページのほとんどの回答では機能しません。モジュラス(%)または整数除算(//)を使用する前に、最初に月をベース1(つまりJan = 1)からベース0(つまりJan = 0)にシフトする必要があります。 、残り(12%12)を見つけると0になります。

(「(月%12)+ 1」または10月+ 1 = 12月を推奨しないでください!)

def AddMonths(d,x):
    newmonth = ((( d.month - 1) + x ) % 12 ) + 1
    newyear  = int(d.year + ((( d.month - 1) + x ) / 12 ))
    return datetime.date( newyear, newmonth, d.day)

ただし... 1月31日+ 1か月などの問題は考慮されていません。それでは、OPに戻ります。月を追加するとはどういう意味ですか?1つの解決策は、有効な日になるまでバックトラックすることです。ほとんどの人は、janの最終日と推定され、1か月は2月の最終日と同じです。これは、負の月数でも機能します。証明:

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

3
「Jan 31 + 1か月」の問題を修正します。days_in_month= calendar.monthrange(newyear、newmonth)[1]; newday = min(d.day、days_in_month); (2月31日から2月28日、29日までなど、大きすぎる場合は1日を下げます)
Curtis Yallop

これは、newyearを整数データ型def AddMonths(d、x)に変換することによってのみ機能しました:newmonth =((((d.month-1)+ x)%12)+ 1 newyear = d.year + int(( (d.month-1)+ x)/ 12)return datetime.date(newyear、newmonth、d.day)
Manmeet Singh

12

私はこれが6か月だったことを知っていますが、1か月を追加している場合、答えはGoogleで「Pythonで月を追加する」と表示されます。

import calendar

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

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

これは現在の月の日数を数え、それらを現在の日付に追加します。365/ 12を使用すると、1年の1/12が日付を反復する場合、短い月または長い月に問題を引き起こす可能性があります。



10

ただ、使用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) or 12, day)

APIは少し不格好ですが、例として機能します。また、2008-01-31 + 1か月などのコーナーケースでは機能しません。:)


3
コードのエラー:であるnew_month % 12必要があります(new_month % 12) or 12。それ以外の場合、11月にこれを実行すると、エラーが発生します。:)
ジョーダンライター

これは実際には、受け入れられているソリューションよりもはるかにクリーンです。これは、新しいインポートを必要とせず、基本的な計算のみを必要とします
Simon PA

return datetime.date(year +(new_month / / 12)、(new_month%12)or 12、day)
paytam

9

Dateutilパッケージには、このような機能が実装されています。ただし、他の人がすでに指摘しているように、これは単純なものになることに注意してください。


dateutilは素晴らしいです。easy_installでもインストールできます。
ソビエト連邦2009

優秀な。提案してくれてありがとう。それは神から送られたようです。
ayaz

9

Python標準ライブラリを使用して、つまりdateutil、他のものなしで、「2月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))

これにはバグがあります。対象月が12月の場合、必要な日付より1年遅れて日付が返されます。例:add_months(datetime.date(2018, 11, 30), 1)戻り値datetime.date(2019, 12, 30)(年は2019ではなく2018でなければなりません)。したがって、これには専用の十分にテストされたライブラリを使用することをお勧めします 標準ライブラリモジュールのみを使用する必要がある場合は、同様の質問に対する私の回答を参照しください。
taleinat

5

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

(月を引くために)負の数でも機能すると思いますが、これはあまりテストしていません。


1
この回答には、組み込みのPythonライブラリのみを使用して問題を正しく解決できるというメリットがあります。stackoverflow.com/a/4131114/302264をチェックして、同等であるが少し簡潔な答えを探します。
Eduardo Dobay

3

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)

3

これはどう?別のライブラリを使用していない(dateutil)またはtimedeltavartecの答えに基づいて構築し、私はこれを実行しました。

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、Not 2015-09-08)。

これがお役に立てば幸いです。


1
day + datetime.timedelta(6*365/12)一部の年は365日、他の年は366日なので、常に機能するとは限りません。
2018年

3

これは特定の質問には答えません(使用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

2

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)

これは、うるう年(2月29日)を考慮していないようです。
ハンドル

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

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

1

1new_month = 121の場合の修正されたJohannes Weiの回答。これは私にとって完全に機能します。月は、正または負になる可能性があります。

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)

2
開始日の日が対象月の日数よりも大きい場合は、「完全に機能」しません。例:2001-01-31プラス1か月は、日付2001-02-31を作成しようとします。
John Machin、2010年

1

さらに別の解決策-誰かがそれを好きになることを願っています:

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

1

この回答から、parsedatetimeを参照してください。次にコード例を示します。詳細:多くの自然言語によるユニットテスト-> YYYY-MM-DD変換の例、および明らかな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
$ 

1

これは、ユーザーが日が月の日数よりも大きい日付を返す方法を決定できるようにする例です。

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)

1

あなたの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)

1

xか月後/前の次の日付を取得する一般的な関数。

日時インポート日から

def after_month(given_date、month):
    yyyy = int(((given_date.year * 12 + given_date.month)+ month)/ 12)
    mm = int(((given_date.year * 12 + given_date.month)+ month)%12)

    mm == 0の場合:
        yyyy-= 1
        mm = 12
    given_date.replace(年= yyyy、月= mm)を返します


__name__ == "__main__"の場合:
    今日= date.today()
    プリント(今日)

    mmの場合[-12、-1、0、1、2、12、20]:
        next_date = after_month(today、mm)
        print(next_date)

これが明らかに最良の答えです。丸めの問題がなく、シンプルで効果的です。
jprobichaud 2018


0

Pythonのdatetimeモジュールを使用して、6か月のtimedeltaをdatetime.today()に追加します。

http://docs.python.org/library/datetime.html

もちろん、ヨハネスヴァイスによって提起された問題を解決する必要あります。6か月までにどういう意味ですか?


1
timedeltaは月をサポートしていないため、「6か月で何日ですか?」という質問に対する可能な回答を回避します。Eefのコードはレビュー日を設定するので、日数(6 * 30)を使用してtimedeltaを設定することを検討することをお勧めします。期間が製品/サービスへのクライアントのアクセスを表す場合、ビジネス定義が必要/推奨される場合があります。
カール

0

これが私が思いついたものです。正しい数の月と年を移動しますが、日を無視します(これは私の状況で必要でした)。

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)

0

この関数を使用して年と月を変更しますが、日は保持します。

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)

0

手動で日数を追加するよりも、このようなことをする方が安全だと思います。

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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.