「年初取得」は“その年の1月1日を意味で取り出す”こと
業務システムだと、「今年の年初」「会計年度の開始日」「前年の年初」みたいな話がよく出てきます。
ここでやってはいけないのは、month = 1; day = 1; のように、自分でフィールドを書き換えることです。
Java には、「その年の1月1日」を“名前付き”で安全に取り出すための API が用意されています。
それを素直に使うと、年次処理・年間集計・年度管理のコードが一気に読みやすくなります。
LocalDate から年初を取得する基本パターン
withMonth(1).withDayOfMonth(1) で「その年の1月1日」
一番ストレートな書き方はこれです。
import java.time.LocalDate;
public class YearStartBasic {
public static void main(String[] args) {
LocalDate anyDay = LocalDate.of(2025, 3, 26);
LocalDate yearStart = anyDay.withMonth(1)
.withDayOfMonth(1);
System.out.println("任意の日付 : " + anyDay); // 2025-03-26
System.out.println("その年の年初: " + yearStart); // 2025-01-01
}
}
Javaここで押さえてほしいポイントは二つあります。
一つ目は、withXxx は「そのフィールドだけを差し替えた新しい LocalDate を返す」ということです。withMonth(1) で「同じ年・同じ日だが月だけ1月」、
さらに withDayOfMonth(1) で「その年の1月1日」になります。
元の anyDay は変わりません(不変オブジェクト)。
二つ目は、「1月1日は必ず存在する」ので、withMonth(1).withDayOfMonth(1) は常に安全に使える、ということです。
TemporalAdjusters を使った「年初」の書き方
firstDayOfYear() を使うと“意図が名前になる”
TemporalAdjusters には、「年初」「年末」などを
“意味のある名前”で表現するためのメソッドが用意されています。
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
public class YearStartAdjuster {
public static void main(String[] args) {
LocalDate anyDay = LocalDate.of(2025, 3, 26);
LocalDate yearStart =
anyDay.with(TemporalAdjusters.firstDayOfYear());
System.out.println("任意の日付 : " + anyDay); // 2025-03-26
System.out.println("その年の年初: " + yearStart); // 2025-01-01
}
}
Javawith(TemporalAdjusters.firstDayOfYear()) と書いてあるだけで、
「このコードは“年初を取っている”んだな」と一瞬で分かります。
withMonth(1).withDayOfMonth(1) よりも、
「意図がコードにそのまま出ている」という意味で、実務ではこちらを強くおすすめします。
「今年の年初」を取得する
LocalDate.now() と firstDayOfYear の組み合わせ
「今日が属する年の年初」を取りたい場合です。
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
public class ThisYearStart {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate yearStart =
today.with(TemporalAdjusters.firstDayOfYear());
System.out.println("今日 : " + today);
System.out.println("今年の年初: " + yearStart);
}
}
Java業務的には、
「今年の売上集計」「今年のログ抽出」「今年のバッチ対象期間」などで、
この「今年の年初」が起点になることが多いです。
「任意の年の年初」を直接作る
LocalDate.of(年, 1, 1) で素直に表現する
「2025 年の年初」のように、年がはっきりしている場合は、
最初から 1 月 1 日を指定してしまうのも自然です。
import java.time.LocalDate;
public class SpecificYearStart {
public static void main(String[] args) {
LocalDate yearStart = LocalDate.of(2025, 1, 1);
System.out.println("2025年の年初: " + yearStart); // 2025-01-01
}
}
Java「ある日付から年初を求める」のではなく、
「そもそも年初を直接作る」方が分かりやすい場面も多いです。
例えば「前年の年初」を求めたいなら、
LocalDate thisYearStart = LocalDate.of(2025, 1, 1);
LocalDate lastYearStart = thisYearStart.minusYears(1); // 2024-01-01
Javaのように、「年初を基準に minusYears(1)」とするのもきれいです。
LocalDateTime / ZonedDateTime での年初取得
LocalDateTime の年初(時刻をどうするかを決める)
LocalDateTime でも firstDayOfYear が使えます。
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
public class LocalDateTimeYearStart {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2025, 3, 26, 15, 30);
LocalDateTime yearStartSameTime =
dt.with(TemporalAdjusters.firstDayOfYear());
LocalDateTime yearStartAtMidnight =
dt.with(TemporalAdjusters.firstDayOfYear())
.withHour(0).withMinute(0).withSecond(0).withNano(0);
System.out.println("元日時 : " + dt); // 2025-03-26T15:30
System.out.println("年初 同じ時刻 : " + yearStartSameTime); // 2025-01-01T15:30
System.out.println("年初 0時ちょうど : " + yearStartAtMidnight);// 2025-01-01T00:00
}
}
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 ZonedDateTimeYearStart {
public static void main(String[] args) {
ZonedDateTime zdt = ZonedDateTime.of(
2025, 3, 26,
15, 30, 0, 0,
ZoneId.of("Asia/Tokyo")
);
ZonedDateTime yearStart =
zdt.with(TemporalAdjusters.firstDayOfYear())
.withHour(0).withMinute(0).withSecond(0).withNano(0);
System.out.println("元日時 : " + zdt);
System.out.println("年初 0時 : " + yearStart);
}
}
Java「日本時間の年初」「UTC の年初」を区別したい場合や、
海外システムと連携する場合は、ZonedDateTime で年初を扱う方が安全です。
実務での「年初取得」あるあるパターン
今年の対象期間(年初〜年末)を求める
「今年のデータだけを集計したい」という典型パターンです。
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ここでのポイントは、
「年初取得」と「年末取得」をセットで使うと、“今年の範囲”をきれいに表現できる
ということです。
まとめ:年初取得で身につけてほしい感覚
年初取得は、「その年の1月1日」を安全かつ意図が伝わる形で取り出すことです。
LocalDate なら with(TemporalAdjusters.firstDayOfYear())、
あるいは withMonth(1).withDayOfMonth(1)。
「今年の年初」なら LocalDate.now().with(firstDayOfYear())。
LocalDateTime / ZonedDateTime では、日付に加えて「時刻をどこに合わせるか」を決める。
年が分かっているなら LocalDate.of(年, 1, 1) で素直に作る。
あなたのコードのどこかに、month = 1; day = 1; のように自前で年初を作っている箇所があれば、
そこを一度 firstDayOfYear() や LocalDate.of(年, 1, 1) に置き換えられないか眺めてみてください。
その小さな置き換えが、
「カレンダー計算を API に任せられるエンジニア」への、確かな一歩になります。
