日付範囲をループするにはどうすればよいですか?


197

ループ/カウンタータイプの恐ろしいforソリューションを使用せずにこれを行う方法すらわかりません。ここに問題があります:

開始日と終了日の2つの日付が与えられ、指定された間隔で何らかのアクションを実行する必要があります。たとえば、2009年3月10日から2009年3月26日までの3日ごとのすべての日付について、リストにエントリを作成する必要があります。だから私の入力は:

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

私の出力は次の日付のリストになります:

2009年3月13日2009年3月16日2009年3月19日2009年3月22日2009年3月25日

それで、一体どうやって私はこのようなことをしますか?私は次のように別のカウンターで範囲内の毎日を繰り返すforループを使用することを考えました:

int count = 0;

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

}

しかし、もっと良い方法があるかもしれませんか?


1
C#には、使用できる日付のデータ構造があると思います。
アンナ

回答:


470

まあ、あなたはそれらを何らかの方法でループする必要があります。私はこのような方法を定義することを好みます:

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ループ(...私は= 0のint型)のためだけではないことを思い出させる
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 2016

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 2009

3
StartDate.AddDays(DayInterval);が必要だと思います。このループで1回2回ではありません。
Abdul Saboor 2013

15

拡張機能で使用される@mquanderおよび@Yogurt The 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);
}

EachDayToand の意味は何EachMonthToですか?ここで何かを逃したと思います。
Alisson 2017

@AlissonそれらはdateFromオブジェクトで機能する拡張メソッドです:)したがって、作成済みのDateTimeオブジェクトで既にそれらをより流暢に使用できます(インスタンスの後にのみ。を使用)。もっとここに拡張メソッドについて:docs.microsoft.com/en-us/dotnet/csharp/programming-guide/...
ジェイコブのSOBU

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代わりに空の範囲を返すことを好みます[]


うわーこれは本当に包括的です。アフマドありがとう!
onekidney 2016年

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で同様の質問を検索して見つけ、DateTimeを反復可能にするための指針を示しました。


1

DateTime.AddDays()関数を使用して をに追加DayIntervalし、StartDateそれが未満であることを確認することができますEndDate


0

ループ内でより良い解決策が得られる日付を逃さないように、ここで注意する必要があります。

これにより、startdateの最初の日付が得られ、それを増分する前にループで使用すると、enddateの最後の日付を含むすべての日付が処理されるため、<= enddateになります。

上記の答えが正しいです。

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.