날짜 범위를 어떻게 반복합니까?


198

끔찍한 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;
     }

}

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


1
C #에는 사용할 수있는 날짜의 데이터 구조가 있다고 생각합니다.
Anna

답변:


471

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

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).


18
간격에 다른 매개 변수를 추가 할 수도 있습니다.
Justin Drury

이것은 첫 번째 날짜를 포함합니다. 원하지 않으면 'var day = from.Date'를 'var day = from.Date.AddDays (dayInterval)'로 변경하십시오.
SwDevMan81

3
흥미롭고 실제적인 단어 문제에 대한 정말 좋은 해결책입니다. 나는 이것이 얼마나 유용한 언어 기술을 보여주는 지 좋아한다. 그리고 이것은 for 루프가 (int i = 0; ...)뿐만 아니라 (-.
Audrius

9
이것을 datetime의 확장 방법으로 만들면 더 나아질 수 있습니다.
MatteS

1
며칠, 몇 달 동안 연장에 대한 내 대답을보십시오.) 당신의 즐거움을 위해 : D
Jacob Sobus

31

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

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

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

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


2
당신이 그런 것들을 확장 방법으로 좋아하든 아니든 분명히 맛의 문제 일 것입니다. ExcludeEnd()귀엽다.
mqp 2009

물론 확장 방법을 사용하지 않고도 모든 것을 할 수 있습니다. IMO를 읽는 것이 훨씬 더 추악하고 어려울 것입니다 :)
Jon Skeet

1
와우-MiscUtil이 얼마나 훌륭한 자원인지-귀하의 답변에 감사드립니다!
onekidney 2009

1
다른 사람이 DayInterval을 구조체 / 클래스로 착각 한 경우 실제로이 샘플의 정수입니다. 물론 질문을주의 깊게 읽으면 분명히 알 수 있습니다.
marc.d

23

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

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);
}

1
그것은 내가 생각했던 것과 동일하지만 (위의 mquander의 답변도 좋아하지만) 어떻게 멋진 코드 샘플을 그렇게 빨리 게시하는지 알 수 없습니다!
TLiebe

3
StartDate.AddDays (DayInterval); 이 루프에서 한 번만 두 번.
Abdul Saboor

15

@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);
}

지점 무엇 EachDayToEachMonthTo? 여기에 뭔가 빠진 것 같습니다.
Alisson

@Alisson 그것들은 dateFrom 객체에서 작동하는 확장 메소드입니다 :) 따라서 생성 된 DateTime 객체에서 이미 더 유창하게 사용할 수 있습니다 (예 : .after 인스턴스 사용). 확장 방법에 대한 자세한 내용은 여기를 참조하십시오. docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…
Jacob Sobus

8
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))
{

}

8

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있지만 대신 빈 범위를 반환하는 것을 선호합니다.[]


와우-이것은 매우 포괄적입니다. 고마워요 Ahmad!
onekidney

3
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
}

시작 날짜가 처음으로 while실행 되기 때문에 시작 날짜는 포함되지 않습니다 .
John Washam

2

문제에 따르면 이것을 시도 할 수 있습니다 ...

// looping between date range    
while (startDate <= endDate)
{
    //here will be your code block...

    startDate = startDate.AddDays(1);
}

감사......


2
DateTime begindate = Convert.ToDateTime("01/Jan/2018");
DateTime enddate = Convert.ToDateTime("12 Feb 2018");
 while (begindate < enddate)
 {
    begindate= begindate.AddDays(1);
    Console.WriteLine(begindate + "  " + enddate);
 }

1

대신 '++'와 같은 일반적인 'for'루프 구문을 사용할 수있는 반복자를 작성하는 것이 좋습니다. 내가 검색과 비슷한 질문을 발견 대답 날짜 시간 반복자를 만들기에 대한 포인터를 제공에 StackOverflow 여기를.


1

당신이 사용할 수있는 DateTime.AddDays()사용자를 추가하는 기능을 DayInterval받는 사람 StartDate과는보다 작은 있는지 확인하십시오 EndDate.


0

루프에서 더 나은 솔루션이 될 때 날짜를 놓치지 않도록주의해야합니다.

이것은 시작 날짜의 첫 번째 날짜를 제공하고 증가시키기 전에 루프에서 사용하며 종료 날짜의 마지막 날짜를 포함하여 모든 날짜를 처리하므로 <= 종료 날짜입니다.

위의 답변이 맞습니다.

while (startdate <= enddate)
{
    // do something with the startdate
    startdate = startdate.adddays(interval);
}

0

이것을 사용할 수 있습니다.

 DateTime dt0 = new DateTime(2009, 3, 10);
 DateTime dt1 = new DateTime(2009, 3, 26);

 for (; dt0.Date <= dt1.Date; dt0=dt0.AddDays(3))
 {
    //Console.WriteLine(dt0.Date.ToString("yyyy-MM-dd"));
    //take action
 }

정말 간결합니다. 좋은!
onekidney

0

15 분마다 반복

DateTime startDate = DateTime.Parse("2018-06-24 06:00");
        DateTime endDate = DateTime.Parse("2018-06-24 11:45");

        while (startDate.AddMinutes(15) <= endDate)
        {

            Console.WriteLine(startDate.ToString("yyyy-MM-dd HH:mm"));
            startDate = startDate.AddMinutes(15);
        }

0

@ jacob-sobus와 @mquander와 @Yogurt는 정확히 정확하지 않습니다. 다음 날에 필요한 경우 00:00 시간을 기다립니다.

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

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

    public static IEnumerable<DateTime> EachYear(DateTime from, DateTime thru)
    {
        for (var year = from.Date; year.Date <= thru.Date || year.Year == thru.Year; year = year.NextYear())
            yield return year;
    }

    public static DateTime NextDay(this DateTime date)
    {
        return date.AddTicks(TimeSpan.TicksPerDay - date.TimeOfDay.Ticks);
    }

    public static DateTime NextMonth(this DateTime date)
    {
        return date.AddTicks(TimeSpan.TicksPerDay * DateTime.DaysInMonth(date.Year, date.Month) - (date.TimeOfDay.Ticks + TimeSpan.TicksPerDay * (date.Day - 1)));
    }

    public static DateTime NextYear(this DateTime date)
    {
        var yearTicks = (new DateTime(date.Year + 1, 1, 1) - new DateTime(date.Year, 1, 1)).Ticks;
        var ticks = (date - new DateTime(date.Year, 1, 1)).Ticks;
        return date.AddTicks(yearTicks - ticks);
    }

    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);
    }

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

0

여기 2020 년에 내 2 센트가 있습니다.

Enumerable.Range(0, (endDate - startDate).Days + 1)
.ToList()
.Select(a => startDate.AddDays(a));

대단해. 👍
onekidney
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.