C# Tips | 日付・時間処理:日付一覧生成

C# C#
スポンサーリンク

はじめに 「日付一覧生成」は“カレンダー系ロジックの土台”

「指定期間の全日付を出したい」「1ヶ月分のカレンダーを作りたい」「営業日一覧を作りたい」
こういうときに必ず必要になるのが「日付一覧生成」です。

C# では、DateTime(または DateOnly)を1日ずつ足していくことで、
シンプルに日付のリストを作れます。
ただ、「開始・終了を含むか」「どの単位で増やすか」「条件付き(平日だけなど)にするか」を
きちんと意識しておくと、実務で使いやすいユーティリティになります。

ここでは、
基本の「日付を1日ずつ増やす」パターンから、
範囲指定・月カレンダー・条件付き生成まで、
初心者向けにかみ砕いて説明していきます。


基本:開始日から終了日までを1日ずつ列挙する

一番シンプルな日付一覧生成

まずは、「開始日から終了日まで、1日ずつ全部ほしい」という一番基本の形です。

using System;
using System.Collections.Generic;

public static class DateListUtil
{
    public static IEnumerable<DateTime> GetDateList(DateTime from, DateTime to)
    {
        if (to < from)
        {
            throw new ArgumentException("終了日は開始日以上である必要があります。");
        }

        DateTime current = from.Date;
        DateTime end     = to.Date;

        while (current <= end)
        {
            yield return current;
            current = current.AddDays(1);
        }
    }
}
C#

使い方の例です。

DateTime from = new DateTime(2026, 2, 10);
DateTime to   = new DateTime(2026, 2, 13);

foreach (var d in DateListUtil.GetDateList(from, to))
{
    Console.WriteLine(d.ToString("yyyy-MM-dd"));
}

// 出力:
// 2026-02-10
// 2026-02-11
// 2026-02-12
// 2026-02-13
C#

ここでの重要ポイントは次の2つです。

  • from.Date / to.Date で「日付だけ」にそろえていること
  • current <= end として「開始・終了を含む」閉区間にしていること

この形を“基本形”として覚えておくと、
ほとんどの「日付一覧生成」はここから派生させて書けます。


.NET 6以降なら DateOnly 版も素直に書ける

日付だけ扱うなら DateOnly のほうが意図が明確

日付だけを扱いたい場合、DateOnly を使うとよりシンプルになります。

using System;
using System.Collections.Generic;

public static class DateOnlyListUtil
{
    public static IEnumerable<DateOnly> GetDateList(DateOnly from, DateOnly to)
    {
        if (to < from)
        {
            throw new ArgumentException("終了日は開始日以上である必要があります。");
        }

        DateOnly current = from;

        while (current <= to)
        {
            yield return current;
            current = current.AddDays(1);
        }
    }
}
C#

使い方の例です。

DateOnly from = new DateOnly(2026, 2, 10);
DateOnly to   = new DateOnly(2026, 2, 13);

foreach (var d in DateOnlyListUtil.GetDateList(from, to))
{
    Console.WriteLine(d);
}

// 出力:
// 2026/02/10
// 2026/02/11
// 2026/02/12
// 2026/02/13
C#

DateOnly を使うと、「時刻をどうするか」を考えなくてよくなるので、
カレンダー系の処理ではかなり扱いやすくなります。


応用1:1ヶ月分のカレンダー日付一覧を作る

「その月の1日〜末日」を一気に出す

「月次レポート」「月カレンダー表示」などでは、
「指定年月の全日付」が欲しくなることが多いです。

public static IEnumerable<DateTime> GetDatesOfMonth(int year, int month)
{
    DateTime first = new DateTime(year, month, 1);
    int daysInMonth = DateTime.DaysInMonth(year, month);

    for (int i = 0; i < daysInMonth; i++)
    {
        yield return first.AddDays(i);
    }
}
C#

使い方の例です。

foreach (var d in GetDatesOfMonth(2026, 2))
{
    Console.WriteLine(d.ToString("yyyy-MM-dd"));
}
C#

DateOnly 版も同じ考え方で書けます。

public static IEnumerable<DateOnly> GetDatesOfMonthDateOnly(int year, int month)
{
    DateOnly first = new DateOnly(year, month, 1);
    int daysInMonth = DateTime.DaysInMonth(year, month);

    for (int i = 0; i < daysInMonth; i++)
    {
        yield return first.AddDays(i);
    }
}
C#

ここでの重要ポイントは、
DateTime.DaysInMonth(year, month) を使って「その月の日数」を正しく取得していることです。
うるう年の2月なども自動で正しく扱ってくれます。


応用2:条件付きの日付一覧(例:平日だけ)

「一覧生成+フィルタ」の組み合わせで考える

実務では、「期間内の全日付」ではなく、
「平日だけ」「営業日だけ」「特定の曜日だけ」
といった条件付きの一覧が欲しくなることが多いです。

基本の考え方はシンプルで、

  1. まず「全日付一覧」を作る
  2. その中から条件に合うものだけを選ぶ

という2ステップで考えます。

例えば、「平日だけ」の一覧はこう書けます。

public static IEnumerable<DateTime> GetWeekdays(DateTime from, DateTime to)
{
    foreach (var d in DateListUtil.GetDateList(from, to))
    {
        if (d.DayOfWeek != DayOfWeek.Saturday &&
            d.DayOfWeek != DayOfWeek.Sunday)
        {
            yield return d;
        }
    }
}
C#

使い方の例です。

DateTime from = new DateTime(2026, 2, 10);
DateTime to   = new DateTime(2026, 2, 16);

foreach (var d in GetWeekdays(from, to))
{
    Console.WriteLine($"{d:yyyy-MM-dd} ({d.DayOfWeek})");
}
C#

「特定の曜日だけ」(例:毎週月曜日)なら、条件を変えるだけです。

public static IEnumerable<DateTime> GetSpecificWeekday(DateTime from, DateTime to, DayOfWeek dayOfWeek)
{
    foreach (var d in DateListUtil.GetDateList(from, to))
    {
        if (d.DayOfWeek == dayOfWeek)
        {
            yield return d;
        }
    }
}
C#

ここでの重要ポイントは、
「一覧生成のロジック」と「条件のロジック」を分けて考えることです。
これを分けておくと、「祝日を除く」「特定日を除外する」などの拡張がしやすくなります。


応用3:LINQ を使った書き方(考え方の整理用)

「日数分のシーケンス」から日付を作る

少し発展的な書き方として、
「0,1,2,… のようなインデックスから日付を作る」パターンもあります。

using System.Linq;

public static IEnumerable<DateTime> GetDateListLinq(DateTime from, DateTime to)
{
    int days = (to.Date - from.Date).Days;

    return Enumerable
        .Range(0, days + 1)
        .Select(i => from.Date.AddDays(i));
}
C#

Enumerable.Range(0, days + 1) で 0〜days の整数列を作り、
それぞれを「開始日+i日」として日付に変換しています。

初心者のうちは whilefor のほうが分かりやすいかもしれませんが、
「日数分のインデックスから日付を作る」という考え方は、
頭の中を整理するのに役立ちます。


実務での注意点1:開始・終了の順序チェック

「終了が開始より前」の不正な入力をどう扱うか

ユーザー入力や外部データから期間を受け取る場合、
「終了日が開始日より前」という不正な範囲が紛れ込むことがあります。

先ほどの GetDateList では、
to < from のときに ArgumentException を投げるようにしました。

if (to < from)
{
    throw new ArgumentException("終了日は開始日以上である必要があります。");
}
C#

ここをどうするかは、システムの方針次第です。

  • 例外にして「入力がおかしい」と早めに気づく
  • 自動的に入れ替えてしまう(from/to を swap)

など、どちらにするかを最初に決めておきましょう。
個人的には、「入力ミスを早く見つけたい」場面では例外にするほうが安全です。


実務での注意点2:タイムゾーンと「どのカレンダーか」

UTC とローカルが混ざると日付がズレる

サーバー内部で UTC を使い、画面では日本時間を表示しているようなシステムでは、
「どのタイムゾーンの“日付一覧”か」を意識しないと、
「日本時間では 2/10〜2/13 のつもりが、UTC では 2/9〜2/12 になっている」
といったズレが起こります。

日付一覧生成は「カレンダーの世界」の話なので、
ユーザーのタイムゾーンに合わせてから .DateDateOnly を使うのが基本です。

イメージとしては、こういう流れです。

public static IEnumerable<DateTime> GetLocalDateListFromUtc(
    DateTime utcFrom,
    DateTime utcTo,
    TimeZoneInfo timeZone)
{
    DateTime localFrom = TimeZoneInfo.ConvertTimeFromUtc(utcFrom, timeZone).Date;
    DateTime localTo   = TimeZoneInfo.ConvertTimeFromUtc(utcTo, timeZone).Date;

    return DateListUtil.GetDateList(localFrom, localTo);
}
C#

「どのタイムゾーンのカレンダーで日付一覧を作っているか」を
ユーティリティ名やコメントに刻んでおくと、後から読んだ人が迷いません。


まとめ 「日付一覧生成ユーティリティ」は“カレンダー処理の共通エンジン”

日付一覧生成は、一見ただのループですが、
期間の扱い方、日付か日時か、条件付きフィルタ、タイムゾーンなど、
カレンダー系ロジックのエッセンスが詰まっています。

押さえておきたいポイントを整理すると、こうなります。

  • 基本形は「開始日から終了日まで、1日ずつ AddDays(1) で進める」
  • 日付だけを扱いたいときは .DateDateOnly を使い、「時刻を無視する」ことをコードで明示する
  • 月単位の一覧は「1日+DaysInMonth」で素直に作れる
  • 条件付き一覧(平日だけ、特定曜日だけ)は「全日付一覧+フィルタ」の組み合わせで考える
  • 開始・終了の順序チェックと、タイムゾーン(どのカレンダーか)を最初に設計しておく

ここを押さえておけば、
「その場しのぎで for 文を書いている」状態から一歩進んで、
“いろいろなカレンダー処理の土台として再利用できる、実務で使える日付一覧生成ユーティリティ”を
自分の C# コードの中に気持ちよく組み込めるようになります。

タイトルとURLをコピーしました