programing

Python에서 다양한 날짜로 반복

luckcodes 2023. 1. 1. 12:17

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 deltas—프로젝트에 쉽게 포함할 수 있는 단일 파일(프로세서)로 구현됩니다.

판다는 일반적으로 시계열에 적합하며 날짜 범위를 직접 지원합니다.

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