482

これを行うための次のコードがありますが、どうすればもっとうまくできますか? 今のところ、ネストされたループよりも優れていると思いますが、リスト内包表記にジェネレーターがあると、Perl-one-linerish になり始めます。

day_count = (end_date - start_date).days + 1
for single_date in [d for d in (start_date + timedelta(n) for n in range(day_count)) if d <= end_date]:
    print strftime("%Y-%m-%d", single_date.timetuple())

ノート

  • 私は実際にこれを印刷に使用していません。これはデモ用です。
  • タイムスタンプは必要ないため、変数start_dateend_date変数はオブジェクトです。datetime.date(それらはレポートの生成に使用されます)。

サンプル出力

の開始日2009-05-30と終了日2009-06-09:

2009-05-30
2009-05-31
2009-06-01
2009-06-02
2009-06-03
2009-06-04
2009-06-05
2009-06-06
2009-06-07
2009-06-08
2009-06-09
4

24 に答える 24

698

ネストされた反復が2つあるのはなぜですか?私の場合、1回の反復で同じデータリストが生成されます。

for single_date in (start_date + timedelta(n) for n in range(day_count)):
    print ...

また、リストは保存されず、1つのジェネレーターのみが繰り返されます。また、ジェネレーターの「if」は不要のようです。

結局のところ、線形シーケンスには2つではなく、1つのイテレータのみが必要です。

ジョン・マチンと話し合った後の更新:

おそらく最も洗練された解決策は、ジェネレーター関数を使用して、日付の範囲で反復を完全に非表示/抽象化することです。

from datetime import date, timedelta

def daterange(start_date, end_date):
    for n in range(int((end_date - start_date).days)):
        yield start_date + timedelta(n)

start_date = date(2013, 1, 1)
end_date = date(2015, 6, 2)
for single_date in daterange(start_date, end_date):
    print(single_date.strftime("%Y-%m-%d"))

注意:組み込みrange()関数との一貫性を保つために、この反復はに達するend_dateに停止します。したがって、包括的反復の場合は、と同じように翌日を使用しますrange()

于 2009-06-29T20:27:14.573 に答える
298

これはより明確かもしれません:

from datetime import date, timedelta

start_date = date(2019, 1, 1)
end_date = date(2020, 1, 1)
delta = timedelta(days=1)
while start_date <= end_date:
    print(start_date.strftime("%Y-%m-%d"))
    start_date += delta
于 2009-06-29T20:31:43.847 に答える
185

dateutilライブラリを使用します。

from datetime import date
from dateutil.rrule import rrule, DAILY

a = date(2009, 5, 30)
b = date(2009, 6, 9)

for dt in rrule(DAILY, dtstart=a, until=b):
    print dt.strftime("%Y-%m-%d")

この Python ライブラリには、s のような非常に便利な機能も含めて、さらに多くの高度な機能がありrelative delta、プロジェクトに簡単にインクルードできる単一のファイル (モジュール) として実装されています。

于 2009-06-30T04:49:37.303 に答える
108

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

import pandas as pd
daterange = pd.date_range(start_date, end_date)

その後、日付範囲をループして日付を出力できます。

for single_date in daterange:
    print (single_date.strftime("%Y-%m-%d"))

暮らしを豊かにするオプションも充実しています。たとえば、平日のみが必要な場合は、bdate_range でスワップするだけです。http://pandas.pydata.org/pandas-docs/stable/timeseries.html#generating-ranges-of-timestampsを参照してください

Pandas の真のパワーはそのデータフレームにあります。これはベクトル化された操作 (numpy によく似ています) をサポートし、大量のデータに対する操作を非常に高速かつ簡単にします。

編集: for ループを完全にスキップして、直接印刷することもできます。これは、より簡単で効率的です。

print(daterange)
于 2014-05-25T08:44:46.703 に答える
17
import datetime

def daterange(start, stop, step=datetime.timedelta(days=1), inclusive=False):
  # inclusive=False to behave like range by default
  if step.days > 0:
    while start < stop:
      yield start
      start = start + step
      # not +=! don't modify object passed in if it's mutable
      # since this function is not restricted to
      # only types from datetime module
  elif step.days < 0:
    while start > stop:
      yield start
      start = start + step
  if inclusive and start == stop:
    yield start

# ...

for date in daterange(start_date, end_date, inclusive=True):
  print strftime("%Y-%m-%d", date.timetuple())

この関数は、負のステップをサポートするなど、厳密に必要以上のことを行います。範囲ロジックを除外する限り、個別の必要はありません。day_count最も重要なのは、関数を複数から呼び出すときにコードが読みやすくなるということです。場所。

于 2009-06-29T20:35:13.090 に答える
13

これは、私が考えることができる最も人間が読めるソリューションです。

import datetime

def daterange(start, end, step=datetime.timedelta(1)):
    curr = start
    while curr < end:
        yield curr
        curr += step
于 2016-10-13T14:28:08.377 に答える
12

試してみませんか:

import datetime as dt

start_date = dt.datetime(2012, 12,1)
end_date = dt.datetime(2012, 12,5)

total_days = (end_date - start_date).days + 1 #inclusive 5 days

for day_number in range(total_days):
    current_date = (start_date + dt.timedelta(days = day_number)).date()
    print current_date
于 2013-04-12T10:47:11.023 に答える
8

今日から最後の n 日間を表示します。

import datetime
for i in range(0, 100):
    print((datetime.date.today() + datetime.timedelta(i)).isoformat())

出力:

2016-06-29
2016-06-30
2016-07-01
2016-07-02
2016-07-03
2016-07-04
于 2016-04-25T03:34:21.743 に答える
6
import datetime

def daterange(start, stop, step_days=1):
    current = start
    step = datetime.timedelta(step_days)
    if step_days > 0:
        while current < stop:
            yield current
            current += step
    elif step_days < 0:
        while current > stop:
            yield current
            current += step
    else:
        raise ValueError("daterange() step_days argument must not be zero")

if __name__ == "__main__":
    from pprint import pprint as pp
    lo = datetime.date(2008, 12, 27)
    hi = datetime.date(2009, 1, 5)
    pp(list(daterange(lo, hi)))
    pp(list(daterange(hi, lo, -1)))
    pp(list(daterange(lo, hi, 7)))
    pp(list(daterange(hi, lo, -7))) 
    assert not list(daterange(lo, hi, -1))
    assert not list(daterange(hi, lo))
    assert not list(daterange(lo, hi, -7))
    assert not list(daterange(hi, lo, 7)) 
于 2009-06-30T11:49:11.940 に答える
4
for i in range(16):
    print datetime.date.today() + datetime.timedelta(days=i)
于 2010-06-17T06:26:49.293 に答える
1

この関数にはいくつかの追加機能があります。

  • 開始または終了の DATE_FORMAT に一致する文字列を渡すことができ、日付オブジェクトに変換されます
  • 開始または終了の日付オブジェクトを渡すことができます
  • 末尾が先頭より古い場合のエラーチェック

    import datetime
    from datetime import timedelta
    
    
    DATE_FORMAT = '%Y/%m/%d'
    
    def daterange(start, end):
          def convert(date):
                try:
                      date = datetime.datetime.strptime(date, DATE_FORMAT)
                      return date.date()
                except TypeError:
                      return date
    
          def get_date(n):
                return datetime.datetime.strftime(convert(start) + timedelta(days=n), DATE_FORMAT)
    
          days = (convert(end) - convert(start)).days
          if days <= 0:
                raise ValueError('The start date must be before the end date.')
          for n in range(0, days):
                yield get_date(n)
    
    
    start = '2014/12/1'
    end = '2014/12/31'
    print list(daterange(start, end))
    
    start_ = datetime.date.today()
    end = '2015/12/1'
    print list(daterange(start, end))
    
于 2014-07-27T03:55:35.350 に答える
1

日単位でインクリメントされる範囲を実行するための次のことはどうですか:

for d in map( lambda x: startDate+datetime.timedelta(days=x), xrange( (stopDate-startDate).days ) ):
  # Do stuff here
  • startDate と stopDate は datetime.date オブジェクトです

汎用バージョンの場合:

for d in map( lambda x: startTime+x*stepTime, xrange( (stopTime-startTime).total_seconds() / stepTime.total_seconds() ) ):
  # Do stuff here
  • startTime と stopTime は、datetime.date または datetime.datetime オブジェクトです (どちらも同じ型である必要があります)。
  • stepTime は timedelta オブジェクトです

.total_seconds() は python 2.7 以降でのみサポートされることに注意してください。以前のバージョンで行き詰まっている場合は、独自の関数を作成できます。

def total_seconds( td ):
  return float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
于 2011-07-13T02:35:14.483 に答える
1

使用できますArrow

これはドキュメントの例で、何時間にもわたって繰り返します:

from arrow import Arrow

>>> start = datetime(2013, 5, 5, 12, 30)
>>> end = datetime(2013, 5, 5, 17, 15)
>>> for r in Arrow.range('hour', start, end):
...     print repr(r)
...
<Arrow [2013-05-05T12:30:00+00:00]>
<Arrow [2013-05-05T13:30:00+00:00]>
<Arrow [2013-05-05T14:30:00+00:00]>
<Arrow [2013-05-05T15:30:00+00:00]>
<Arrow [2013-05-05T16:30:00+00:00]>

何日も繰り返すには、次のように使用できます。

>>> start = Arrow(2013, 5, 5)
>>> end = Arrow(2013, 5, 5)
>>> for r in Arrow.range('day', start, end):
...     print repr(r)

(オブジェクトを渡すことができるかどうかはチェックしませんでしdatetime.dateたが、とにかくArrowオブジェクトは一般的に簡単です)

于 2021-01-11T05:49:51.397 に答える