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

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

はじめに 「年一覧生成」は“長期スパンの集計・分析の土台”

売上の年次推移、年度別の件数集計、ログの年別アーカイブ。
こういう「年単位」で物事を見る処理の裏側には、たいてい「年一覧」がいます。

C# では、DateTime や単なる int(年だけ)を使って、
「開始年から終了年までを順番に列挙する」ユーティリティを作るだけで、
年次処理の多くがぐっと書きやすくなります。

ここでは、
最も基本的な「年のリスト生成」から、DateTime 版・年度対応・直近N年・
そして実務での設計ポイントまで、初心者向けにかみ砕いて説明します。


基本の考え方:年は「int」で扱うか「DateTime」で扱うか

年だけ欲しいなら int、日付も絡むなら DateTime

「2020, 2021, 2022, 2023…」のように、
単純に“年の数字だけ”が欲しいなら int の列で十分です。

一方で、「その年の1月1日」や「その年の開始日・終了日」も一緒に扱いたいなら、
DateTime(あるいは DateOnly)で持っておくと便利です。

まずは一番シンプルな int 版から見ていき、そのあと DateTime 版・年度版へと広げていきます。


年一覧生成の基本形(int 版)

開始年から終了年までを順番に列挙する

最も基本的な「年一覧生成」は、次のように書けます。

using System;
using System.Collections.Generic;

public static class YearListUtil
{
    public static IEnumerable<int> GetYearList(int fromYear, int toYear)
    {
        if (toYear < fromYear)
        {
            throw new ArgumentException("終了年は開始年以上である必要があります。");
        }

        int current = fromYear;

        while (current <= toYear)
        {
            yield return current;
            current++;
        }
    }
}
C#

使い方の例です。

foreach (var year in YearListUtil.GetYearList(2020, 2024))
{
    Console.WriteLine(year);
}

// 出力:
// 2020
// 2021
// 2022
// 2023
// 2024
C#

ここでの重要ポイントは、
「開始年・終了年を含む閉区間(fromYear 以上 toYear 以下)」としていることです。
年次グラフや年別集計では、この形が一番自然なことが多いです。


DateTime 版:その年の代表日(1月1日)を持たせる

「年+日付」をセットで扱いたい場合

年次処理の中で、「その年の開始日」「その年の範囲」をすぐに使いたいことがあります。
その場合、DateTime で「その年の1月1日」を持たせておくと便利です。

using System;
using System.Collections.Generic;

public static class YearDateTimeListUtil
{
    public static IEnumerable<DateTime> GetYearStartDates(int fromYear, int toYear)
    {
        if (toYear < fromYear)
        {
            throw new ArgumentException("終了年は開始年以上である必要があります。");
        }

        int current = fromYear;

        while (current <= toYear)
        {
            yield return new DateTime(current, 1, 1);
            current++;
        }
    }
}
C#

使い方の例です。

foreach (var d in YearDateTimeListUtil.GetYearStartDates(2020, 2023))
{
    Console.WriteLine(d.ToString("yyyy-MM-dd"));
}

// 出力:
// 2020-01-01
// 2021-01-01
// 2022-01-01
// 2023-01-01
C#

この「その年の1月1日」を起点に、
「その年の開始日」「その年の終了日」「その年の全日付一覧」などを
派生させて作ることができます。


年の範囲情報をまとめた小さな型を作る

「年+開始日+終了日」をひとまとめにする

実務では、「その年の開始日と終了日」をセットで扱うことが多いです。
例えば、「2024年のデータだけ抽出したい」といったケースです。

そこで、小さな struct を作って、
「年」「開始日」「終了日」をひとまとめにしてしまうと扱いやすくなります。

public readonly struct YearRange
{
    public int Year { get; }
    public DateTime StartDate { get; }
    public DateTime EndDate { get; }

    public YearRange(int year)
    {
        Year = year;
        StartDate = new DateTime(year, 1, 1);
        EndDate   = new DateTime(year, 12, 31);
    }

    public override string ToString() => Year.ToString();
}
C#

この YearRange を一覧で返すユーティリティです。

public static class YearRangeUtil
{
    public static IEnumerable<YearRange> GetYearRanges(int fromYear, int toYear)
    {
        if (toYear < fromYear)
        {
            throw new ArgumentException("終了年は開始年以上である必要があります。");
        }

        int current = fromYear;

        while (current <= toYear)
        {
            yield return new YearRange(current);
            current++;
        }
    }
}
C#

使い方の例です。

foreach (var yr in YearRangeUtil.GetYearRanges(2022, 2024))
{
    Console.WriteLine($"{yr}: {yr.StartDate:yyyy-MM-dd} ~ {yr.EndDate:yyyy-MM-dd}");
}

// 出力:
// 2022: 2022-01-01 ~ 2022-12-31
// 2023: 2023-01-01 ~ 2023-12-31
// 2024: 2024-01-01 ~ 2024-12-31
C#

ここでの重要ポイントは、
「年の範囲(開始・終了)を YearRange の中に閉じ込めている」ことです。
呼び出し側は「どの年を回すか」だけを考えればよくなり、
開始・終了日の計算ロジックをあちこちに書かずに済みます。


応用1:直近N年の一覧を生成する

「今年を含めた直近5年」などのよくある要件

年次グラフやレポートでよくあるのが、
「今年を含めた直近N年分を出したい」という要件です。

using System;
using System.Collections.Generic;

public static class RecentYearUtil
{
    public static IEnumerable<int> GetRecentYears(int count, int? baseYear = null)
    {
        if (count <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(count));
        }

        int year = baseYear ?? DateTime.Today.Year;

        int start = year - (count - 1);

        for (int y = start; y <= year; y++)
        {
            yield return y;
        }
    }
}
C#

使い方の例です。

foreach (var y in RecentYearUtil.GetRecentYears(5))
{
    Console.WriteLine(y);
}
C#

このようにしておくと、
「直近N年」のロジックを一箇所にまとめられ、
画面やレポートごとにバラバラの計算をしなくて済みます。


応用2:年度一覧(会計年度・学年など)を生成する

「4月始まり」「10月始まり」の世界

日本の業務システムでは、「年度」がよく出てきます。
例えば「2024年度」は、
2024/04/01 ~ 2025/03/31 のような期間を指します。

この場合、「年度の開始月」をパラメータにしたユーティリティを作ると便利です。

public readonly struct FiscalYearRange
{
    public int FiscalYear { get; }
    public DateTime StartDate { get; }
    public DateTime EndDate { get; }

    public FiscalYearRange(int fiscalYear, int startMonth)
    {
        FiscalYear = fiscalYear;

        StartDate = new DateTime(fiscalYear, startMonth, 1);

        DateTime endStart = StartDate.AddYears(1).AddDays(-1);
        EndDate = endStart;
    }

    public override string ToString() => $"{FiscalYear}年度";
}
C#

この FiscalYearRange を一覧で返すユーティリティです。

public static class FiscalYearUtil
{
    public static IEnumerable<FiscalYearRange> GetFiscalYears(
        int fromFiscalYear,
        int toFiscalYear,
        int startMonth)
    {
        if (toFiscalYear < fromFiscalYear)
        {
            throw new ArgumentException("終了年度は開始年度以上である必要があります。");
        }

        int current = fromFiscalYear;

        while (current <= toFiscalYear)
        {
            yield return new FiscalYearRange(current, startMonth);
            current++;
        }
    }
}
C#

使い方の例です(4月始まりの年度)。

foreach (var fy in FiscalYearUtil.GetFiscalYears(2022, 2024, 4))
{
    Console.WriteLine($"{fy}: {fy.StartDate:yyyy-MM-dd} ~ {fy.EndDate:yyyy-MM-dd}");
}

// 出力イメージ:
// 2022年度: 2022-04-01 ~ 2023-03-31
// 2023年度: 2023-04-01 ~ 2024-03-31
// 2024年度: 2024-04-01 ~ 2025-03-31
C#

ここでの重要ポイントは、
「年度の開始月を引数で受け取り、そこから1年引き伸ばして終了日を決めている」ことです。
会計年度・学年・事業年度など、開始月が違うパターンにも柔軟に対応できます。


実務での注意点1:開始・終了の順序チェックを必ず入れる

「終了年が開始年より小さい」入力をどう扱うか

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

これをそのまま使うと、
「一覧が空になる」「ループが無限になる」などの問題が起こり得ます。

そのため、ユーティリティの入り口で必ずチェックを入れ、
おかしければ例外を投げるか、値を入れ替えるか、
方針を決めておくことが大事です。

個人的には、「入力ミスを早く見つけたい」場面では例外にするほうが安全です。


実務での注意点2:年と日付の混在に気をつける

「2024年」と「2024/01/01~2024/12/31」を混同しない

年一覧生成はシンプルですが、
「年だけのつもりが、どこかで日付として扱ってしまう」
「年度と暦年をごちゃ混ぜにする」
といったミスが起こりやすいところでもあります。

設計としては、

  • 暦年(カレンダーの年)は YearRange
  • 年度(会計年度など)は FiscalYearRange

のように型を分けておくと、
「これはどの“年の概念”なのか」がコードから読み取りやすくなります。


まとめ 「年一覧生成ユーティリティ」は“長期スパンの見通しを良くする道具”

年一覧生成は、一見ただの for ループですが、
年次グラフ、年別集計、年度処理など、
長期スパンのビジネスロジックの土台になります。

押さえておきたいポイントをまとめると、次のようになります。

年だけ欲しいなら int の一覧、開始年から終了年までを閉区間で列挙する。
日付も絡めたいなら「その年の1月1日」を DateTime(または DateOnly)で持たせる。
「年+開始日+終了日」をまとめた YearRange や、開始月を持つ FiscalYearRange を用意すると、年次・年度処理が書きやすくなる。
直近N年などのよくある要件は専用ユーティリティにして、ロジックを一箇所に集約する。
開始・終了の順序チェックと、「暦年」と「年度」を型レベルで分ける設計を意識すると、実務でのバグを大きく減らせる。

ここまで押さえておけば、
「その場しのぎで for 文を書いている」状態から一歩進んで、
“年次・年度処理の背骨として安心して使える、実務で使える年一覧生成ユーティリティ”を
自分の C# コードの中に自然に組み込めるようになります。

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