Python에서 다양한 날짜로 반복
이를 위해 다음과 같은 코드가 있는데 어떻게 하면 더 잘 할 수 있을까요?지금은 네스트 루프보다 낫다고 생각하지만 목록 이해에 제너레이터가 있으면 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_date
그리고.end_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
네스트된 반복이 2개 있는 이유는 무엇입니까?저는 동일한 데이터 목록을 한 번만 반복하여 생성합니다.
for single_date in (start_date + timedelta(n) for n in range(day_count)):
print ...
리스트는 저장되지 않고 1개의 제너레이터만 반복됩니다.또한 제너레이터의 "if"는 불필요해 보입니다.
결국 선형 시퀀스는 2개가 아니라 1개의 반복기만 필요로 합니다.
John Machin과 상의 후 업데이트:
가장 우아한 솔루션은 생성 함수를 사용하여 날짜 범위에 걸쳐 반복을 완전히 숨기거나 추출하는 것입니다.
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"))
NB: 빌트인과의 일관성 확보range()
이 반복이 정지된 후,end_date
포괄적 반복의 경우 다음 날 사용합니다.range()
.
이것은 보다 명확할 수 있습니다.
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
라이브러리 사용:
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")
이 파이썬 라이브러리는 다음과 같은 많은 고급 기능을 가지고 있으며, 일부는 매우 유용합니다.relative delta
s—프로젝트에 쉽게 포함할 수 있는 단일 파일(프로세서)로 구현됩니다.
판다는 일반적으로 시계열에 적합하며 날짜 범위를 직접 지원합니다.
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 를 참조해 주세요.
Panda의 장점은 데이터 프레임입니다. 데이터 프레임은 대량의 데이터를 매우 빠르고 쉽게 처리할 수 있는 벡터화 작업(numpy와 거의 유사)을 지원합니다.
편집: for 루프를 완전히 건너뛰고 직접 인쇄할 수도 있습니다.이것이 보다 쉽고 효율적입니다.
print(daterange)
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
가장 중요한 것은 함수를 여러 곳에서 호출하면 코드를 읽기 쉬워진다는 것입니다.
이것은 내가 생각할 수 있는 가장 사람이 읽을 수 있는 해결책이다.
import datetime
def daterange(start, end, step=datetime.timedelta(1)):
curr = start
while curr < end:
yield curr
curr += step
Numpy'sarange
을 사용법
import numpy as np
from datetime import datetime, timedelta
d0 = datetime(2009, 1,1)
d1 = datetime(2010, 1,1)
dt = timedelta(days = 1)
dates = np.arange(d0, d1, dt).astype(datetime)
「 」의 astype
입니다.numpy.datetime64
로 늘어선 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」datetime.datetime
★★★★★★★★★★★★★★★★★★.
시도해 보는 것은 어떨까요?
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
오늘부터 마지막 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
완성도를 높이기 위해, 판다들은 또한period_range
「 」 「 」 、 「 」 、 「 」
import pandas as pd
pd.period_range(start='1/1/1626', end='1/08/1627', freq='D')
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))
for i in range(16):
print datetime.date.today() + datetime.timedelta(days=i)
저도 비슷한 문제가 있는데, 매일이 아니라 매달 반복해야 해요.
이것이 나의 해결책이다.
import calendar
from datetime import datetime, timedelta
def days_in_month(dt):
return calendar.monthrange(dt.year, dt.month)[1]
def monthly_range(dt_start, dt_end):
forward = dt_end >= dt_start
finish = False
dt = dt_start
while not finish:
yield dt.date()
if forward:
days = days_in_month(dt)
dt = dt + timedelta(days=days)
finish = dt > dt_end
else:
_tmp_dt = dt.replace(day=1) - timedelta(days=1)
dt = (_tmp_dt.replace(day=dt.day))
finish = dt < dt_end
예 #1
date_start = datetime(2016, 6, 1)
date_end = datetime(2017, 1, 1)
for p in monthly_range(date_start, date_end):
print(p)
산출량
2016-06-01
2016-07-01
2016-08-01
2016-09-01
2016-10-01
2016-11-01
2016-12-01
2017-01-01
예 #2
date_start = datetime(2017, 1, 1)
date_end = datetime(2016, 6, 1)
for p in monthly_range(date_start, date_end):
print(p)
산출량
2017-01-01
2016-12-01
2016-11-01
2016-10-01
2016-09-01
2016-08-01
2016-07-01
2016-06-01
팬더 라이브러리를 사용하면 두 날짜 사이에 일련의 날짜를 쉽고 확실하게 생성할 수 있습니다.
import pandas as pd
print pd.date_range(start='1/1/2010', end='1/08/2018', freq='M')
날짜 생성 빈도를 변경하려면 freq를 D, M, Q, Y(일별, 월별, 분기별, 연도)로 설정합니다.
진자를 사용해서.기간:
import pendulum
start = pendulum.from_format('2020-05-01', 'YYYY-MM-DD', formatter='alternative')
end = pendulum.from_format('2020-05-02', 'YYYY-MM-DD', formatter='alternative')
period = pendulum.period(start, end)
for dt in period:
print(dt.to_date_string())
> pip install DateTimeRange
from datetimerange import DateTimeRange
def dateRange(start, end, step):
rangeList = []
time_range = DateTimeRange(start, end)
for value in time_range.range(datetime.timedelta(days=step)):
rangeList.append(value.strftime('%m/%d/%Y'))
return rangeList
dateRange("2018-09-07", "2018-12-25", 7)
Out[92]:
['09/07/2018',
'09/14/2018',
'09/21/2018',
'09/28/2018',
'10/05/2018',
'10/12/2018',
'10/19/2018',
'10/26/2018',
'11/02/2018',
'11/09/2018',
'11/16/2018',
'11/23/2018',
'11/30/2018',
'12/07/2018',
'12/14/2018',
'12/21/2018']
피토닉의 기능적 방법에 관심이 있는 분:
from datetime import date, timedelta
from itertools import count, takewhile
for d in takewhile(lambda x: x<=date(2009,6,9), map(lambda x:date(2009,5,30)+timedelta(days=x), count())):
print(d)
일 단위로 증가된 범위를 수행하는 경우 다음과 같이 하십시오.
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
- start Time 및 stop시간은 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
이 기능에는 몇 가지 추가 기능이 있습니다.
- 시작 또는 종료에 대해 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))
다음은 일반적인 날짜 범위 함수에 대한 코드입니다. Ber의 답변과 비슷하지만 더 유연합니다.
def count_timedelta(delta, step, seconds_in_interval):
"""Helper function for iterate. Finds the number of intervals in the timedelta."""
return int(delta.total_seconds() / (seconds_in_interval * step))
def range_dt(start, end, step=1, interval='day'):
"""Iterate over datetimes or dates, similar to builtin range."""
intervals = functools.partial(count_timedelta, (end - start), step)
if interval == 'week':
for i in range(intervals(3600 * 24 * 7)):
yield start + datetime.timedelta(weeks=i) * step
elif interval == 'day':
for i in range(intervals(3600 * 24)):
yield start + datetime.timedelta(days=i) * step
elif interval == 'hour':
for i in range(intervals(3600)):
yield start + datetime.timedelta(hours=i) * step
elif interval == 'minute':
for i in range(intervals(60)):
yield start + datetime.timedelta(minutes=i) * step
elif interval == 'second':
for i in range(intervals(1)):
yield start + datetime.timedelta(seconds=i) * step
elif interval == 'millisecond':
for i in range(intervals(1 / 1000)):
yield start + datetime.timedelta(milliseconds=i) * step
elif interval == 'microsecond':
for i in range(intervals(1e-6)):
yield start + datetime.timedelta(microseconds=i) * step
else:
raise AttributeError("Interval must be 'week', 'day', 'hour' 'second', \
'microsecond' or 'millisecond'.")
from datetime import date,timedelta
delta = timedelta(days=1)
start = date(2020,1,1)
end=date(2020,9,1)
loop_date = start
while loop_date<=end:
print(loop_date)
loop_date+=delta
하시면 됩니다.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
일반적으로 오브젝트가 더 쉽다)
에 대한 접근법은 .range
tupletvs in tuple.tvs in tuple.
def date_range(start, stop, step=1, inclusive=False):
day_count = (stop - start).days
if inclusive:
day_count += 1
if step > 0:
range_args = (0, day_count, step)
elif step < 0:
range_args = (day_count - 1, -1, step)
else:
raise ValueError("date_range(): step arg must be non-zero")
for i in range(*range_args):
yield start + timedelta(days=i)
import datetime
from dateutil.rrule import DAILY,rrule
date=datetime.datetime(2019,1,10)
date1=datetime.datetime(2019,2,2)
for i in rrule(DAILY , dtstart=date,until=date1):
print(i.strftime('%Y%b%d'),sep='\n')
출력:
2019Jan10
2019Jan11
2019Jan12
2019Jan13
2019Jan14
2019Jan15
2019Jan16
2019Jan17
2019Jan18
2019Jan19
2019Jan20
2019Jan21
2019Jan22
2019Jan23
2019Jan24
2019Jan25
2019Jan26
2019Jan27
2019Jan28
2019Jan29
2019Jan30
2019Jan31
2019Feb01
2019Feb02
dynamic을 사용하는 경우 timedelta
을 사용하다
1. while loop 포함
def datetime_range(start: datetime, end: datetime, delta: timedelta) -> Generator[datetime, None, None]:
while start <= end:
yield start
start += delta
2. For 루프 포함
from datetime import datetime, timedelta
from typing import Generator
def datetime_range(start: datetime, end: datetime, delta: timedelta) -> Generator[datetime, None, None]:
delta_units = int((end - start) / delta)
for _ in range(delta_units + 1):
yield start
start += delta
3. 비동기/대기 사용 시
async def datetime_range(start: datetime, end: datetime, delta: timedelta) -> AsyncGenerator[datetime, None]:
delta_units = int((end - start) / delta)
for _ in range(delta_units + 1):
yield start
start += delta
4. 리스트의 이해
def datetime_range(start: datetime, end: datetime, delta: timedelta) -> List[datetime]:
delta_units = int((end - start) / delta)
return [start + (delta * index) for index in range(delta_units + 1)]
그러면 1과 2의 솔루션을 이렇게 간단하게 사용할 수 있습니다.
start = datetime(2020, 10, 10, 10, 00)
end = datetime(2022, 10, 10, 18, 00)
delta = timedelta(minutes=30)
result = [time_part for time_part in datetime_range(start, end, delta)]
# or
for time_part in datetime_range(start, end, delta):
print(time_part)
비동기 컨텍스트에서는 3번째 솔루션을 이와 같이 사용할 수 있습니다.비동기 컨텍스트에서만 사용할 수 있는 비동기 생성기 개체를 재실행하기 때문입니다.
start = datetime(2020, 10, 10, 10, 00)
end = datetime(2022, 10, 10, 18, 00)
delta = timedelta(minutes=30)
result = [time_part async for time_part in datetime_range(start, end, delta)]
async for time_part in datetime_range(start, end, delta):
print(time_part)
에 관한 솔루션의 이점은 모든 솔루션이 다이내믹을 사용한다는 것입니다. timedelta
이것은, 어느 시간대의 델타를 갖게 될지 모르는 경우에 매우 편리합니다.
언급URL : https://stackoverflow.com/questions/1060279/iterating-through-a-range-of-dates-in-python
'programing' 카테고리의 다른 글
Java에서 2배에서 정수로 변환 (0) | 2023.01.01 |
---|---|
테이블 형식 없이 SQL 쿼리 결과 가져오기 (0) | 2023.01.01 |
String을 Title Case로 변환하는 방법이 있나요? (0) | 2023.01.01 |
JDBC 유형에 대한 방언 매핑 없음: 1111 (0) | 2023.01.01 |
Windows 10에서는 MariaDB와 MySQL이 매우 느리다 (0) | 2023.01.01 |