C# Tips | 日付・時間処理:年齢計算

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

はじめに 「年齢計算」は“日付ロジックの入門にして落とし穴だらけのテーマ”

「この人は今何歳か」「○日時点で何歳だったか」。
業務システムでも、顧客管理・会員管理・保険・医療・学校など、年齢計算は本当によく出てきます。

でも、
単純に「今年 − 生まれた年」ではダメです。
誕生日を迎えているかどうかで、年齢は 1 歳変わります。

ここでは、
一番基本的な「満年齢」の計算から始めて、
基準日を指定するパターン、DateOnly の活用、注意すべき落とし穴まで、
初心者向けにかみ砕いて説明していきます。


基本:満年齢の考え方「誕生日を過ぎているかどうか」

「年だけ引く」となぜ間違うのか

まず、よくやってしまう間違いから。

int age = today.Year - birth.Year;
C#

一見それっぽいですが、
例えば「2000/12/31 生まれ」の人を「2026/02/10 時点」で計算するとどうなるか。

today.Year = 2026
birth.Year = 2000
age = 2026 − 2000 = 26

でも、2026/02/10 の時点では、まだ 2026 年の誕生日(12/31)を迎えていません。
正しい満年齢は 25 歳です。

つまり、
「年だけ引く」と、誕生日を迎えていない期間は 1 歳多く出てしまいます。

正しい満年齢のロジック

満年齢の基本ロジックはこうです。

  1. まず「年だけ引いた値」を仮の年齢とする
  2. その年の誕生日を作る
  3. 基準日がその誕生日より前なら、1 歳引く

これを C# で書くと、こうなります。

using System;

public static class AgeUtil
{
    public static int GetAge(DateTime birthDate, DateTime onDate)
    {
        if (onDate < birthDate)
        {
            throw new ArgumentException("基準日が生年月日より前です。");
        }

        int age = onDate.Year - birthDate.Year;

        DateTime birthdayThisYear = new DateTime(onDate.Year, birthDate.Month, birthDate.Day);

        if (onDate < birthdayThisYear)
        {
            age--;
        }

        return age;
    }
}
C#

使い方の例です。

DateTime birth = new DateTime(2000, 12, 31);

DateTime d1 = new DateTime(2026, 2, 10);
DateTime d2 = new DateTime(2026, 12, 31);
DateTime d3 = new DateTime(2027, 1, 1);

Console.WriteLine(AgeUtil.GetAge(birth, d1)); // 25
Console.WriteLine(AgeUtil.GetAge(birth, d2)); // 26
Console.WriteLine(AgeUtil.GetAge(birth, d3)); // 27
C#

ここでの重要ポイントは、
「その年の誕生日を作って、基準日と比較する」というステップを必ず入れることです。
これを入れないと、誕生日を迎える前後で 1 歳ズレ続けます。


「今日時点の年齢」を求めるユーティリティ

DateTime.Today を使ったシンプル版

「今この瞬間の年齢」ではなく、「今日時点の年齢」でよければ、
DateTime.Today を基準日に使うのが分かりやすいです。

public static class AgeUtil
{
    public static int GetAgeToday(DateTime birthDate)
    {
        return GetAge(birthDate, DateTime.Today);
    }
}
C#

使い方はとてもシンプルです。

DateTime birth = new DateTime(1990, 5, 10);

int age = AgeUtil.GetAgeToday(birth);

Console.WriteLine(age); // 今日時点の満年齢
C#

「画面に表示する年齢」「プロフィールの年齢」など、
多くのケースではこの GetAgeToday で足ります。


基準日を変えたいケース:「○日時点で何歳だったか」

過去や未来のある日を基準にする

業務では、「今日」以外を基準にしたいこともよくあります。

例えば、
「契約開始日時点での年齢」
「入社日時点での年齢」
「イベント開催日時点での年齢」
などです。

こういうときは、先ほどの GetAge をそのまま使えば OK です。

DateTime birth      = new DateTime(1990, 5, 10);
DateTime joinedDate = new DateTime(2015, 4, 1);

int ageAtJoin = AgeUtil.GetAge(birth, joinedDate);

Console.WriteLine(ageAtJoin); // 入社日時点の年齢
C#

ここでのポイントは、
「年齢は常に“ある基準日時点での満年齢”として扱う」
という考え方を徹底することです。

「今何歳?」と「入社時何歳だった?」は別物なので、
基準日を引数で渡せるようにしておくと、ロジックがブレません。


DateOnly を使った、日付だけの年齢計算

時刻を無視したいなら DateOnly が素直

.NET 6 以降なら、日付だけを扱う DateOnly が使えます。
年齢計算は「日付」だけ分かればよく、時刻は不要なので、
DateOnly ベースで書くとより意図がはっきりします。

public static class AgeUtilDateOnly
{
    public static int GetAge(DateOnly birthDate, DateOnly onDate)
    {
        if (onDate < birthDate)
        {
            throw new ArgumentException("基準日が生年月日より前です。");
        }

        int age = onDate.Year - birthDate.Year;

        DateOnly birthdayThisYear = new DateOnly(onDate.Year, birthDate.Month, birthDate.Day);

        if (onDate < birthdayThisYear)
        {
            age--;
        }

        return age;
    }
}
C#

使い方の例です。

DateOnly birth = new DateOnly(2000, 12, 31);
DateOnly on    = new DateOnly(2026, 2, 10);

int age = AgeUtilDateOnly.GetAge(birth, on);

Console.WriteLine(age); // 25
C#

DateTime だと「時刻」「タイムゾーン」の話が絡んできますが、
年齢計算ではそこまで要らないことが多いので、
DateOnly を使うとシンプルで安全です。


落とし穴1:うるう年(2/29 生まれ)の扱い

2/29 生まれの人は、うるう年以外どうカウントするか

2/29 生まれの人は、うるう年以外には「その年の誕生日」が存在しません。
現実世界では、「2/28 か 3/1 を誕生日扱いにする」など、
国や制度によって扱いが分かれることがあります。

先ほどの実装だと、
new DateTime(onDate.Year, 2, 29) がうるう年以外で例外になります。

この問題をどう扱うかは、
システムの要件次第です。

例えば、「2/28 を誕生日扱いにする」ルールにするなら、
こんな感じで調整できます。

public static int GetAgeWithLeapSupport(DateTime birthDate, DateTime onDate)
{
    if (onDate < birthDate)
    {
        throw new ArgumentException("基準日が生年月日より前です。");
    }

    int age = onDate.Year - birthDate.Year;

    int month = birthDate.Month;
    int day   = birthDate.Day;

    if (month == 2 && day == 29 && !DateTime.IsLeapYear(onDate.Year))
    {
        day = 28;
    }

    DateTime birthdayThisYear = new DateTime(onDate.Year, month, day);

    if (onDate < birthdayThisYear)
    {
        age--;
    }

    return age;
}
C#

ここは「業務ルール」として決める必要があるので、
仕様書や関係者との合意が必須です。


落とし穴2:タイムゾーンと「いつ年齢が変わるか」

UTC とローカルで日付がズレる問題

サーバー側で UTC を使っている場合、
「日本時間では誕生日を迎えているのに、UTC ではまだ前日」
という状況が普通に起こります。

例えば、
日本時間 2026/05/10 0:30 は、UTC だと 2026/05/09 15:30 です。

「日本のユーザーの年齢」を扱うのに、
UTC の日付で年齢計算をしてしまうと、
誕生日当日に「まだ年齢が変わっていない」ように見えてしまいます。

実務的には、

  1. ユーザーの居住国・タイムゾーンを決める
  2. UTC からそのタイムゾーンに変換してから、日付ベースで年齢計算する

という方針を取るのが安全です。

イメージとしては、こんな感じです。

public static int GetAgeInTimeZone(DateTime birthDateLocal, DateTime utcNow, TimeZoneInfo timeZone)
{
    DateTime nowLocal = TimeZoneInfo.ConvertTimeFromUtc(utcNow, timeZone);

    DateOnly birth = DateOnly.FromDateTime(birthDateLocal);
    DateOnly on    = DateOnly.FromDateTime(nowLocal);

    return AgeUtilDateOnly.GetAge(birth, on);
}
C#

「どのタイムゾーンの“今日”を基準に年齢を決めるか」を
ユーティリティ名やコメントに明示しておくと、
後から読んだ人が迷わずに済みます。


まとめ 「年齢計算ユーティリティ」は“日付の境界をきちんと扱う練習台”

年齢計算は、一見シンプルに見えて、
誕生日の前後、うるう年、タイムゾーンなど、
日付ロジックの典型的な落とし穴が全部詰まっています。

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

  1. 満年齢は「年だけ引く」のではなく、「その年の誕生日を過ぎているかどうか」で 1 歳調整する。
  2. 「今日時点の年齢」と「ある日時点の年齢」は別物なので、基準日を引数で渡せる GetAge(birth, onDate) という形にしておく。
  3. 時刻やタイムゾーンを気にしたくないなら、DateOnly ベースで年齢計算を書くとシンプルで安全になる。
  4. 2/29 生まれの扱いは業務ルール次第なので、「うるう年以外は 2/28 扱い」など、仕様として決めてから実装する。
  5. UTC とローカルのズレを意識し、「どのタイムゾーンの“今日”で年齢を決めるか」を最初に設計しておく。

ここを押さえておけば、
「なんとなく Year を引いている」状態から一歩進んで、
“現実のルールにちゃんと沿った、実務で使える年齢計算ユーティリティ”を
自分の C# コードの中に自信を持って組み込めるようになります。

C#C#
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました