[C#] 날짜 범위를 어떻게 반복합니까?

끔찍한 for 루프 / 카운터 유형 솔루션을 사용하지 않고이 작업을 수행하는 방법조차 확실하지 않습니다. 문제는 다음과 같습니다.

시작 날짜와 종료 날짜 두 가지가 주어지며 지정된 간격으로 조치를 취해야합니다. 예를 들어 : 2009 년 3 월 26 일까지 3 일마다 3/10/2009 사이의 모든 날짜에 대해 목록에 항목을 작성해야합니다. 내 입력은 다음과 같습니다.

DateTime StartDate = "3/10/2009";
DateTime EndDate = "3/26/2009";
int DayInterval = 3;

내 출력은 다음 날짜가있는 목록이됩니다.

2009 년 3 월 13 일 3/16/2009 3/19/2009 3/22/2009 3/25/2009

도대체 내가 어떻게 이런 짓을 할까? 나는 별도의 카운터를 사용하여 범위 내에서 매일 반복되는 for 루프를 사용하는 것에 대해 생각했습니다.

int count = 0;

for(int i = 0; i < n; i++)
{
     count++;
     if(count >= DayInterval)
     {
          //take action
          count = 0;
     }

}

그러나 더 좋은 방법이있을 것 같습니다?



답변

글쎄, 당신은 그것들을 어떤 식 으로든 반복해야합니다. 다음과 같은 방법을 정의하는 것을 선호합니다.

public IEnumerable<DateTime> EachDay(DateTime from, DateTime thru)
{
    for(var day = from.Date; day.Date <= thru.Date; day = day.AddDays(1))
        yield return day;
}

그런 다음 다음과 같이 사용할 수 있습니다.

foreach (DateTime day in EachDay(StartDate, EndDate))
    // print it or whatever

이 방법으로 격일로, 매 3 일마다, 주중에만 등을 맞출 수 있습니다. 예를 들어 “시작”날짜로 시작하는 3 일마다 돌아가 AddDays(3)려면 대신 루프를 호출 하면됩니다 AddDays(1).


답변

나는이 Range클래스 MiscUtil 당신이 유용 할 수있다. 다양한 확장 방법과 결합하여 다음을 수행 할 수 있습니다.

foreach (DateTime date in StartDate.To(EndDate).ExcludeEnd()
                                   .Step(DayInterval.Days())
{
    // Do something with the date
}

(당신은 끝을 제외하고 싶거나 원하지 않을 수 있습니다. 나는 단지 그것을 예제로 제공한다고 생각했습니다.)

이것은 기본적으로 mquander 솔루션의 기성품 및보다 일반적인 형태입니다.


답변

당신의 예를 들어 당신은 시도 할 수 있습니다

DateTime StartDate = new DateTime(2009, 3, 10);
DateTime EndDate = new DateTime(2009, 3, 26);
int DayInterval = 3;

List<DateTime> dateList = new List<DateTime>();
while (StartDate.AddDays(DayInterval) <= EndDate)
{
   StartDate = StartDate.AddDays(DayInterval);
   dateList.Add(StartDate);
}


답변

@mquander 및 @Yogurt의 코드 확장에 사용되는 Wise :

public static IEnumerable<DateTime> EachDay(DateTime from, DateTime thru)
{
    for (var day = from.Date; day.Date <= thru.Date; day = day.AddDays(1))
        yield return day;
}

public static IEnumerable<DateTime> EachMonth(DateTime from, DateTime thru)
{
    for (var month = from.Date; month.Date <= thru.Date || month.Month == thru.Month; month = month.AddMonths(1))
        yield return month;
}

public static IEnumerable<DateTime> EachDayTo(this DateTime dateFrom, DateTime dateTo)
{
    return EachDay(dateFrom, dateTo);
}

public static IEnumerable<DateTime> EachMonthTo(this DateTime dateFrom, DateTime dateTo)
{
    return EachMonth(dateFrom, dateTo);
}


답변

DateTime startDate = new DateTime(2009, 3, 10);
DateTime stopDate = new DateTime(2009, 3, 26);
int interval = 3;

for (DateTime dateTime=startDate;
     dateTime < stopDate;
     dateTime += TimeSpan.FromDays(interval))
{

}


답변

1 년 후 누군가에게 도움이 되겠습니까?

이 버전에는 보다 유연한 술어가 포함 되어 있습니다.

용법

var today = DateTime.UtcNow;
var birthday = new DateTime(2018, 01, 01);

내 생일에 매일

var toBirthday = today.RangeTo(birthday);  

내 생일에 매달 2 단계

var toBirthday = today.RangeTo(birthday, x => x.AddMonths(2));

매년 내 생일에

var toBirthday = today.RangeTo(birthday, x => x.AddYears(1));

사용 RangeFrom하는 대신

// same result
var fromToday = birthday.RangeFrom(today);
var toBirthday = today.RangeTo(birthday);

이행

public static class DateTimeExtensions
{

    public static IEnumerable<DateTime> RangeTo(this DateTime from, DateTime to, Func<DateTime, DateTime> step = null)
    {
        if (step == null)
        {
            step = x => x.AddDays(1);
        }

        while (from < to)
        {
            yield return from;
            from = step(from);
        }
    }

    public static IEnumerable<DateTime> RangeFrom(this DateTime to, DateTime from, Func<DateTime, DateTime> step = null)
    {
        return from.RangeTo(to, step);
    }
}

엑스트라

의 경우 예외를 던질 수 fromDate > toDate있지만 대신 빈 범위를 반환하는 것을 선호합니다.[]


답변

DateTime startDate = new DateTime(2009, 3, 10);
DateTime stopDate = new DateTime(2009, 3, 26);
int interval = 3;

while ((startDate = startDate.AddDays(interval)) <= stopDate)
{
    // do your thing
}