Java Tips | 日付・時間:年末取得

Java Java
スポンサーリンク

「年末取得」は“その年の最後の日を意味でつかまえる”こと

業務システムでは、「今年の年末」「会計年度の最終日」「前年の年末」みたいな話がよく出てきます。
ここでやってはいけないのは、「12 月 31 日で固定」と決め打ちしたり、自前で月の長さを計算したりすることです。

Java には、「その年の最後の日」を“名前付き”で安全に取り出すための API が用意されています。
それを素直に使うと、年次処理・年間集計・年度管理のコードが一気に読みやすくなります。


LocalDate から年末を取得する基本パターン

withMonth(12).withDayOfMonth(31) という素朴な書き方

まずは一番ストレートな書き方から。

import java.time.LocalDate;

public class YearEndBasic {

    public static void main(String[] args) {
        LocalDate anyDay = LocalDate.of(2025, 3, 26);

        LocalDate yearEnd = anyDay.withMonth(12)
                                  .withDayOfMonth(31);

        System.out.println("任意の日付 : " + anyDay);    // 2025-03-26
        System.out.println("その年の年末: " + yearEnd);  // 2025-12-31
    }
}
Java

ここで押さえておきたいのは、withXxx の性質です。

withMonth(12) は「同じ年・同じ日だが月だけ 12 月」、
さらに withDayOfMonth(31) で「その年の 12 月 31 日」になります。
元の anyDay は変わりません(不変オブジェクト)。

ただし、この書き方は「12 月 31 日が年末」という前提に乗っています。
暦年ベースなら問題ありませんが、会計年度が「4 月〜翌年 3 月」のようなケースでは、
別ロジックが必要になります(後で触れます)。


TemporalAdjusters を使った「年末」の書き方

lastDayOfYear() を使うと“意図が名前になる”

TemporalAdjusters には、「年初」「年末」などを
“意味のある名前”で表現するためのメソッドが用意されています。

import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

public class YearEndAdjuster {

    public static void main(String[] args) {
        LocalDate anyDay = LocalDate.of(2025, 3, 26);

        LocalDate yearEnd =
                anyDay.with(TemporalAdjusters.lastDayOfYear());

        System.out.println("任意の日付 : " + anyDay);    // 2025-03-26
        System.out.println("その年の年末: " + yearEnd);  // 2025-12-31
    }
}
Java

with(TemporalAdjusters.lastDayOfYear()) と書いてあるだけで、
「このコードは“年末を取っている”んだな」と一瞬で分かります。

withMonth(12).withDayOfMonth(31) よりも、
「意図がコードにそのまま出ている」という意味で、実務ではこちらを強くおすすめします。


「今年の年末」を取得する

LocalDate.now() と lastDayOfYear の組み合わせ

「今日が属する年の年末」を取りたい場合です。

import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

public class ThisYearEnd {

    public static void main(String[] args) {
        LocalDate today = LocalDate.now();

        LocalDate yearEnd =
                today.with(TemporalAdjusters.lastDayOfYear());

        System.out.println("今日     : " + today);
        System.out.println("今年の年末: " + yearEnd);
    }
}
Java

業務的には、
「今年の売上集計の最終日」「今年のログ抽出の終端」「今年のバッチ対象期間の終わり」などで、
この「今年の年末」が終点としてよく使われます。


「任意の年の年末」を求める

いったん年初を作ってから lastDayOfYear

「2025 年の年末」のように、年が決まっている場合です。

import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

public class SpecificYearEnd {

    public static void main(String[] args) {
        LocalDate yearStart = LocalDate.of(2025, 1, 1);

        LocalDate yearEnd =
                yearStart.with(TemporalAdjusters.lastDayOfYear());

        System.out.println("2025年の年初: " + yearStart); // 2025-01-01
        System.out.println("2025年の年末: " + yearEnd);   // 2025-12-31
    }
}
Java

ポイントは、
「年初は LocalDate.of(年, 1, 1) で素直に作り、年末は lastDayOfYear で求める」
というパターンを覚えておくことです。

「年初+年末」のセットで考えると、年間処理の期間計算がとても書きやすくなります。


LocalDateTime / ZonedDateTime での年末取得

LocalDateTime の年末(時刻をどこに合わせるかが重要)

LocalDateTime でも lastDayOfYear が使えます。

import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;

public class LocalDateTimeYearEnd {

    public static void main(String[] args) {
        LocalDateTime dt = LocalDateTime.of(2025, 3, 26, 15, 30);

        LocalDateTime yearEndSameTime =
                dt.with(TemporalAdjusters.lastDayOfYear());

        LocalDateTime yearEndAt235959 =
                dt.with(TemporalAdjusters.lastDayOfYear())
                  .withHour(23).withMinute(59).withSecond(59).withNano(0);

        System.out.println("元日時            : " + dt);                // 2025-03-26T15:30
        System.out.println("年末 同じ時刻     : " + yearEndSameTime);  // 2025-12-31T15:30
        System.out.println("年末 23:59:59まで : " + yearEndAt235959);  // 2025-12-31T23:59:59
    }
}
Java

業務では、
「今年の 1 月 1 日 0:00 から、今年の 12 月 31 日 23:59:59 まで」
といった“年間の対象期間”を扱うことが多いので、
「日付だけでなく、時刻をどこに合わせるか」をきちんと決めることが大事です。

ZonedDateTime の年末(タイムゾーン付き)

タイムゾーン付きの ZonedDateTime でも同様です。

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAdjusters;

public class ZonedDateTimeYearEnd {

    public static void main(String[] args) {
        ZonedDateTime zdt = ZonedDateTime.of(
                2025, 3, 26,
                15, 30, 0, 0,
                ZoneId.of("Asia/Tokyo")
        );

        ZonedDateTime yearEnd =
                zdt.with(TemporalAdjusters.lastDayOfYear())
                   .withHour(23).withMinute(59).withSecond(59).withNano(0);

        System.out.println("元日時      : " + zdt);
        System.out.println("年末 23:59:59: " + yearEnd);
    }
}
Java

「日本時間の年末」「UTC の年末」を区別したい場合や、
海外システムと連携する場合は、ZonedDateTime で年末を扱う方が安全です。


会計年度など「年末=12/31 ではない」ケース

例えば「4 月〜翌年 3 月」が年度の場合

暦年ではなく「会計年度」を扱う場合、
「年度の開始日」「年度の終了日」を自分で定義する必要があります。

例えば「2024 年度は 2024-04-01 〜 2025-03-31」と決まっているなら、
年度末はこう表現できます。

import java.time.LocalDate;

public class FiscalYearEndExample {

    public static void main(String[] args) {
        int fiscalYear = 2024; // 2024年度

        LocalDate fiscalYearEnd = LocalDate.of(fiscalYear + 1, 3, 31);

        System.out.println("2024年度の年度末: " + fiscalYearEnd); // 2025-03-31
    }
}
Java

ここで大事なのは、
「lastDayOfYear は“暦年”の年末であって、“会計年度の年末”ではない」
ということです。

会計年度を扱うときは、
「年度の定義」を一か所にまとめたユーティリティを作り、
そこに「年度初日」「年度末日」を計算させるのが実務的です。


実務での「年初+年末」セット利用

今年の対象期間(年初〜年末)を求める

「今年のデータだけを集計したい」という典型パターンです。

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;

public class YearlyRangeExample {

    public static void main(String[] args) {
        LocalDate today = LocalDate.now();

        LocalDateTime from = today.with(TemporalAdjusters.firstDayOfYear())
                                  .atStartOfDay();

        LocalDateTime to = today.with(TemporalAdjusters.lastDayOfYear())
                                .atTime(23, 59, 59);

        System.out.println("対象開始: " + from);
        System.out.println("対象終了: " + to);
    }
}
Java

ここでのポイントは、
「年初取得」と「年末取得」をセットで使うと、“今年の範囲”をきれいに表現できる
ということです。


まとめ:年末取得で身につけてほしい感覚

年末取得は、「その年の最後の日」を安全かつ意図が伝わる形で取り出すことです。

LocalDate なら with(TemporalAdjusters.lastDayOfYear()) を使う。
「今年の年末」なら LocalDate.now().with(lastDayOfYear())
LocalDateTime / ZonedDateTime では、日付に加えて「時刻をどこに合わせるか」を決める。
暦年ではなく会計年度を扱う場合は、「年度の定義」を自前でユーティリティ化する。

あなたのコードのどこかに、
「12 月 31 日をベタ書きして“年末扱い”している」ような箇所があれば、
そこを一度 lastDayOfYear() や年度ユーティリティに置き換えられないか眺めてみてください。

その小さな置き換えが、
“時間とカレンダーに強いエンジニア”への、また一歩になります。

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