Pythonで日付の範囲を作成する


374

今日から始めて、任意の日数(たとえば、例では100日)遡って日付のリストを作成したいと思います。これよりも良い方法はありますか?

import datetime

a = datetime.datetime.today()
numdays = 100
dateList = []
for x in range (0, numdays):
    dateList.append(a - datetime.timedelta(days = x))
print dateList

回答:


459

やや良い...

base = datetime.datetime.today()
date_list = [base - datetime.timedelta(days=x) for x in range(numdays)]

6
タイムゾーン対応の日時を使用していて、夏時間のシフトがある場合、これは機能しません!!!
つまり

range(0, numdays)この場合、@ s-lottを使用できませんでしたか?
Lukas Juhrich、2015年

3
このメソッドを少し異なる方法で使用して、10、5分の間隔、+ /-の値(私の場合は30秒)を生成しました。私はちょうど私が共有したいと考え出し:datetimes = [start + timedelta(seconds=x*60+randint(-30, 30)) for x in range (0, range_end*5, 5)]どこ変数range_end = 10
MikeyE

247

Pandas 一般的に時系列に最適で、日付範囲を直接サポートしています。

たとえば、pd.date_range()次のとおりです。

import pandas as pd
from datetime import datetime

datelist = pd.date_range(datetime.today(), periods=100).tolist()

また、生活を楽にするオプションもたくさんあります。たとえば、平日だけが必要な場合は、に入れ替えるだけbdate_rangeです。

日付範囲のドキュメントを参照してください

さらに、pytzタイムゾーンを完全にサポートし、春/秋のDSTシフトをスムーズにスパンできます。

OPによる編集:

Pandasタイムスタンプではなく、実際のP​​ython日時が必要な場合:

import pandas as pd
from datetime import datetime

pd.date_range(end = datetime.today(), periods = 100).to_pydatetime().tolist()

#OR

pd.date_range(start="2018-09-09",end="2020-02-02")

これは、「end」パラメーターを使用して元の質問と一致しますが、降順の日付が必要な場合:

pd.date_range(datetime.today(), periods=100).to_pydatetime().tolist()

22
パンダが既に使用されている場合は、最良の回答をDefoしてください。唯一追加するのは、元の投稿のように日付が逆方向に進んでいる場合は、end =パラメータを使用することです。pd.date_range(end = pd.datetime.today()、periods = 100).tolist()
Thomas Browne

5
このメソッドの1つの問題は、Pythonの日時型が必要な場合です... Pandasまたはnumpyの日付範囲メソッドを使用すると、Timestamp型とDatetime64型が作成されます... list(map(pd.Timestamp.to_pydatetime, datelist))日時型を戻す必要があります...
MalikKonéDec

このpandas.datetimeクラスは非推奨であり、将来のバージョンではパンダから削除される予定です。datetime代わりにモジュールからインポートします。
トレントンマッキーニー

82

指定された開始日と終了日の間の日付範囲を取得します(時間とスペースの複雑さに対して最適化されています):

import datetime

start = datetime.datetime.strptime("21-06-2014", "%d-%m-%Y")
end = datetime.datetime.strptime("07-07-2014", "%d-%m-%Y")
date_generated = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]

for date in date_generated:
    print date.strftime("%d-%m-%Y")

6
最初の提案は、date_generatorを取得するために[]ではなく()を使用することです。ある意味で効率的です。日付の配列全体を格納し、必要な場合にのみ日付を生成する必要はありません。
Sandeep 14

2
end_dateは生成されないことに注意してください。
するThorbjörnRavnアンデルセン

8
(end-start + 1)を使用して終了日を取得します。
Sandeep、2015

6
OPの質問には答えませんが、それが私が求めていたものです:)
ティエリーJ.

2
(end-start+1)動作しません。timedeltaとintを追加することはできません。でも使用できます(end-start).days + 1
スティーブンポールガー

44

今日から始まる日付オブジェクトを返すジェネレータ関数を作成できます。

import datetime

def date_generator():
  from_date = datetime.datetime.today()
  while True:
    yield from_date
    from_date = from_date - datetime.timedelta(days=1)

このジェネレータは、今日から始まり、1日ずつ遡って日付を返します。最初の3つの日付を取得する方法は次のとおりです。

>>> import itertools
>>> dates = itertools.islice(date_generator(), 3)
>>> list(dates)
[datetime.datetime(2009, 6, 14, 19, 12, 21, 703890), datetime.datetime(2009, 6, 13, 19, 12, 21, 703890), datetime.datetime(2009, 6, 12, 19, 12, 21, 703890)]

ループまたはリストの理解に対するこのアプローチの利点は、何度でも戻ることができることです。

編集する

関数の代わりにジェネレータ式を使用したよりコンパクトなバージョン:

date_generator = (datetime.datetime.today() - datetime.timedelta(days=i) for i in itertools.count())

使用法:

>>> dates = itertools.islice(date_generator, 3)
>>> list(dates)
[datetime.datetime(2009, 6, 15, 1, 32, 37, 286765), datetime.datetime(2009, 6, 14, 1, 32, 37, 286836), datetime.datetime(2009, 6, 13, 1, 32, 37, 286859)]

1
日数が任意である場合、ジェネレーターはこれを行う理想的な方法です。
xssChauhan 2017年

32

ええ、ホイールを再発明してください...フォーラムを検索するだけで、次のようなものが得られます。

from dateutil import rrule
from datetime import datetime

list(rrule.rrule(rrule.DAILY,count=100,dtstart=datetime.now()))

22
labix.org/python-dateutilが必要です。見栄えは良いですが、1行を節約するだけでは外部依存関係の価値はほとんどありません。
Beni Cherniavsky-Paskin

1
他の答えが非常にpythonicであると誰も信じることができません。rruleはひどい名前ですが、これは少なくとも目には簡単です。
ボートコーダー2015

7
@ BeniCherniavsky-Paskin:ピリオド(カレンダー)演算を実装しているときに、微妙なバグを導入するのは非常に簡単です。iCalendar RFCをdateutil.rrule実装します -わずかに異なるほとんど同じ機能の複数の実装の代わりに、明確に定義された動作を持つ関数を使用する方が簡単です。dateutil.rruleバグ修正を1か所に制限できます。
jfs 2015

3
@ Mark0978:rrule名前は任意ではありません。それは対応するrfc
jfs '28

1
いや、残念ながら名前の選択にdateutilを非難していなかった:-)
ボートコーダー

32

日の序数を使用して簡単にすることもできます。

def date_range(start_date, end_date):
    for ordinal in range(start_date.toordinal(), end_date.toordinal()):
        yield datetime.date.fromordinal(ordinal)

または、コメントで提案されているように、次のようなリストを作成できます。

date_range = [
    datetime.date.fromordinal(ordinal) 
    for ordinal in range(
        start_date.toordinal(),
        end_date.toordinal(),
    )
]

18

この質問のタイトルから、のようなものが見つかると予想していました。これにより、range()2つの日付を指定し、その間にすべての日付を含むリストを作成できます。そうすれば、2つの日付の間の日数を事前に知らなくても、計算する必要はありません。

したがって、少し話題から外れるリスクがあるため、このワンライナーがその役割を果たします。

import datetime
start_date = datetime.date(2011, 01, 01)
end_date   = datetime.date(2014, 01, 01)

dates_2011_2013 = [ start_date + datetime.timedelta(n) for n in range(int ((end_date - start_date).days))]

この答えのすべてのクレジット!


1
これは、質問に対する他の多くの回答と同じように、1つのライナーではありません。
トーマスブラウン

4
私はこれが他の回答よりもワンライナーであると偽ったことはありません。これがより良い解決策であったとも言えません。私は、あなたが要求したものとは少し異なる何かをするコードの一部を示しましたが、質問のタイトルを与えられて、ここで見つけてよかったでしょう。
snake_charmer

11

これは、2つの日付startとの間の日付のリストを提供するS.Lottの回答を基にした、わずかに異なる回答ですend。下の例では、2017年の初めから今日までです。

start = datetime.datetime(2017,1,1)
end = datetime.datetime.today()
daterange = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]

7

私が知っている少し遅い回答ですが、同じ問題があり、Pythonの内部範囲関数がこの点で少し欠けていると判断したので、私のutilモジュールでオーバーライドしました。

from __builtin__ import range as _range
from datetime import datetime, timedelta

def range(*args):
    if len(args) != 3:
        return _range(*args)
    start, stop, step = args
    if start < stop:
        cmp = lambda a, b: a < b
        inc = lambda a: a + step
    else:
        cmp = lambda a, b: a > b
        inc = lambda a: a - step
    output = [start]
    while cmp(start, stop):
        start = inc(start)
        output.append(start)

    return output

print range(datetime(2011, 5, 1), datetime(2011, 10, 1), timedelta(days=30))

1
ループのoutput = []行を入れ替えたいと思いますwhile cmp(...)。比較range(0,10,1)_range(0,10,1)
sigfpe 2012年

3
関数に名前を付ければ、この答えの方が良いと思いますdate_range
Brandon Bradley、

7

私が自分のためにこれを書いた答えに基づいて:

import datetime;
print [(datetime.date.today() - datetime.timedelta(days=x)).strftime('%Y-%m-%d') for x in range(-5, 0)]

出力:

['2017-12-11', '2017-12-10', '2017-12-09', '2017-12-08', '2017-12-07']

違いは、「date」オブジェクトではなく「」オブジェクトを取得することdatetime.datetimeです。


7

2つの日付があり、範囲が必要な場合は、

from dateutil import rrule, parser
date1 = '1995-01-01'
date2 = '1995-02-28'
datesx = list(rrule.rrule(rrule.DAILY, dtstart=parser.parse(date1), until=parser.parse(date2)))

5

これが私が作成した要点です。自分のコードから、これは役立つかもしれません。(質問が古すぎることは知っていますが、他の人が使用できます)

https://gist.github.com/2287345

(以下同じ)

import datetime
from time import mktime

def convert_date_to_datetime(date_object):
    date_tuple = date_object.timetuple()
    date_timestamp = mktime(date_tuple)
    return datetime.datetime.fromtimestamp(date_timestamp)

def date_range(how_many=7):
    for x in range(0, how_many):
        some_date = datetime.datetime.today() - datetime.timedelta(days=x)
        some_datetime = convert_date_to_datetime(some_date.date())
        yield some_datetime

def pick_two_dates(how_many=7):
    a = b = convert_date_to_datetime(datetime.datetime.now().date())
    for each_date in date_range(how_many):
        b = a
        a = each_date
        if a == b:
            continue
        yield b, a

4

これが平日のリストを取得するbashスクリプトの1行です。これはpython 3です。簡単に変更できます。最後のintは、必要な過去の日数です。

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.today() - datetime.timedelta(days=x)).strftime(\"%Y/%m/%d\") for x in range(0,int(sys.argv[1])) if (datetime.datetime.today() - datetime.timedelta(days=x)).isoweekday()<6]))" 10

これは、開始(または終了)日付を提供するバリアントです

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.strptime(sys.argv[1],\"%Y/%m/%d\") - datetime.timedelta(days=x)).strftime(\"%Y/%m/%d \") for x in range(0,int(sys.argv[2])) if (datetime.datetime.today() - datetime.timedelta(days=x)).isoweekday()<6]))" 2015/12/30 10

以下は、任意の開始日と終了日のバリエーションです。これはそれほど効率的ではありませんが、bashスクリプトにforループを配置するのに適しています。

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.strptime(sys.argv[1],\"%Y/%m/%d\") + datetime.timedelta(days=x)).strftime(\"%Y/%m/%d\") for x in range(0,int((datetime.datetime.strptime(sys.argv[2], \"%Y/%m/%d\") - datetime.datetime.strptime(sys.argv[1], \"%Y/%m/%d\")).days)) if (datetime.datetime.strptime(sys.argv[1], \"%Y/%m/%d\") + datetime.timedelta(days=x)).isoweekday()<6]))" 2015/12/15 2015/12/30

コメントのコードで回答投稿を更新したい場合があります。Pythonはコメントで壊れてしまい、ちょっとフォーマットが必要です。
ジェイクバスマン2015

3

Matplotlib関連

from matplotlib.dates import drange
import datetime

base = datetime.date.today()
end  = base + datetime.timedelta(days=100)
delta = datetime.timedelta(days=1)
l = drange(base, end, delta)

3

私はこれが答えられたことを知っていますが、私は歴史的な目的のために私の答えを書き留めます。

import numpy as np
import datetime as dt
listOfDates=[date for date in np.arange(firstDate,lastDate,dt.timedelta(days=x))]

もちろん、コードゴルフのようなものは勝てませんが、エレガントだと思います。


arange手順ではかなりいいですが、listOfDatesで構成されて numpyのdatetime64の代わりに、pythonのネイティブ日付時刻。
F.Raab

2
ただし、numpy datetime64の代わりにネイティブPython datetime np.arange(…).astype(dt.datetime)arange返すために使用できます。
F.Raab

2

Sandeepの回答から始めて、前方または後方にカウントする別の例。

from datetime import date, datetime, timedelta
from typing import Sequence
def range_of_dates(start_of_range: date, end_of_range: date) -> Sequence[date]:

    if start_of_range <= end_of_range:
        return [
            start_of_range + timedelta(days=x)
            for x in range(0, (end_of_range - start_of_range).days + 1)
        ]
    return [
        start_of_range - timedelta(days=x)
        for x in range(0, (start_of_range - end_of_range).days + 1)
    ]

start_of_range = datetime.today().date()
end_of_range = start_of_range + timedelta(days=3)
date_range = range_of_dates(start_of_range, end_of_range)
print(date_range)

与える

[datetime.date(2019, 12, 20), datetime.date(2019, 12, 21), datetime.date(2019, 12, 22), datetime.date(2019, 12, 23)]

そして

start_of_range = datetime.today().date()
end_of_range = start_of_range - timedelta(days=3)
date_range = range_of_dates(start_of_range, end_of_range)
print(date_range)

与える

[datetime.date(2019, 12, 20), datetime.date(2019, 12, 19), datetime.date(2019, 12, 18), datetime.date(2019, 12, 17)]

開始日は戻り値に含まれるため、合計4つの日付が必要な場合は、 timedelta(days=3)


1
from datetime import datetime, timedelta
from dateutil import parser
def getDateRange(begin, end):
    """  """
    beginDate = parser.parse(begin)
    endDate =  parser.parse(end)
    delta = endDate-beginDate
    numdays = delta.days + 1
    dayList = [datetime.strftime(beginDate + timedelta(days=x), '%Y%m%d') for x in range(0, numdays)]
    return dayList

1

毎月の日付範囲ジェネレータdatetimedateutil。シンプルで理解しやすい:

import datetime as dt
from dateutil.relativedelta import relativedelta

def month_range(start_date, n_months):
        for m in range(n_months):
            yield start_date + relativedelta(months=+m)

0
import datetime    
def date_generator():
    cur = base = datetime.date.today()
    end  = base + datetime.timedelta(days=100)
    delta = datetime.timedelta(days=1)
    while(end>base):
        base = base+delta
        print base

date_generator()

1
彼は前方に、戻ってみたかった...そうendでなければなりませんbase - datetime.timedelta。さらに...なぜこのソリューションは元のソリューションよりも優れているのですか?
frarugi87 2015

0

上記の回答から、私は日付ジェネレータのこの例を作成しました

import datetime
date = datetime.datetime.now()
time = date.time()
def date_generator(date, delta):
  counter =0
  date = date - datetime.timedelta(days=delta)
  while counter <= delta:
    yield date
    date = date + datetime.timedelta(days=1)
    counter +=1

for date in date_generator(date, 30):
   if date.date() != datetime.datetime.now().date():
     start_date = datetime.datetime.combine(date, datetime.time())
     end_date = datetime.datetime.combine(date, datetime.time.max)
   else:
     start_date = datetime.datetime.combine(date, datetime.time())
     end_date = datetime.datetime.combine(date, time)
   print('start_date---->',start_date,'end_date---->',end_date)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.