Calendar は「古い日付 API」だが、変換パターンを覚えれば怖くない
java.util.Calendar は、Date と同じく“古い日付 API”です。
今の Java では LocalDate / LocalTime / LocalDateTime / ZonedDateTime / Instant を使うのが基本ですが、
業務ではまだまだ Calendar を返すライブラリや、Calendar を使っている既存コードが残っています。
だから大事なのは、
「Calendar を主役にしない。必要なときだけ java.time に変換する」
という発想です。
ここでは、Calendar と java.time の変換を、初心者向けに分かりやすく整理します。
Calendar → Instant が“変換の入り口”
Calendar から Instant を取り出す:toInstant()
Calendar は内部的に Date を持っています。
そして Date は Instant に変換できます。
つまり、Calendar → Date → Instant の流れです。
import java.time.Instant;
import java.util.Calendar;
public class CalendarToInstantExample {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance(); // 現在日時
Instant instant = cal.toInstant();
System.out.println(cal.getTime());
System.out.println(instant); // 例: 2025-03-26T13:25:30.123Z
}
}
Javaここでの重要ポイントは、
「Calendar は toInstant() を持っているので、直接 Instant にできる」
ということです。
Instant にしてしまえば、
あとは LocalDateTime や ZonedDateTime へ自由に変換できます。
Calendar → LocalDateTime / ZonedDateTime 変換
Calendar → LocalDateTime(タイムゾーンが必須)
LocalDateTime はタイムゾーンを持たないため、
「Calendar をどのタイムゾーンとして解釈するか」を指定する必要があります。
import java.time.*;
import java.util.Calendar;
public class CalendarToLocalDateTimeExample {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance(); // 例: DB から取得した Calendar
Instant instant = cal.toInstant();
ZoneId zone = ZoneId.of("Asia/Tokyo");
LocalDateTime ldt = LocalDateTime.ofInstant(instant, zone);
System.out.println("Calendar : " + cal.getTime());
System.out.println("LocalDateTime : " + ldt);
}
}
Javaここで深掘りしたいのは、
「Calendar のタイムゾーンと、変換先のタイムゾーンは別物」
という点です。
Calendar 自体もタイムゾーンを持っていますが、
変換時に別の ZoneId を指定すれば、
「Calendar の瞬間を、別の地域のローカル時間として見る」ことができます。
Calendar → ZonedDateTime(Calendar のタイムゾーンをそのまま使う)
Calendar のタイムゾーンをそのまま使いたい場合は、cal.getTimeZone() を使います。
import java.time.*;
import java.util.Calendar;
public class CalendarToZonedDateTimeExample {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance(); // 例: Asia/Tokyo
Instant instant = cal.toInstant();
ZoneId zone = cal.getTimeZone().toZoneId();
ZonedDateTime zdt = instant.atZone(zone);
System.out.println("Calendar : " + cal.getTime());
System.out.println("ZonedDateTime : " + zdt);
}
}
Javaここでのポイントは、
「Calendar のタイムゾーンを尊重したいなら、getTimeZone().toZoneId() を使う」
ということです。
LocalDateTime / ZonedDateTime → Calendar 変換
LocalDateTime → Calendar(ZoneId が必要)
LocalDateTime はタイムゾーンを持たないため、
Calendar に変換するには ZoneId を指定します。
import java.time.*;
import java.util.Calendar;
import java.util.Date;
public class LocalDateTimeToCalendarExample {
public static void main(String[] args) {
LocalDateTime ldt = LocalDateTime.of(2025, 3, 26, 9, 0);
ZoneId zone = ZoneId.of("Asia/Tokyo");
Instant instant = ldt.atZone(zone).toInstant();
Calendar cal = Calendar.getInstance();
cal.setTime(Date.from(instant));
System.out.println("LocalDateTime : " + ldt);
System.out.println("Calendar : " + cal.getTime());
}
}
JavaCalendar は Date を使って時刻を設定するため、
LocalDateTime → ZonedDateTime → Instant → Date → Calendar
という流れになります。
ZonedDateTime → Calendar(タイムゾーンも反映)
ZonedDateTime はタイムゾーンを持っているので、
Calendar にそのまま反映できます。
import java.time.*;
import java.util.Calendar;
import java.util.Date;
public class ZonedDateTimeToCalendarExample {
public static void main(String[] args) {
ZonedDateTime zdt = ZonedDateTime.of(
2025, 3, 26,
9, 0, 0, 0,
ZoneId.of("Asia/Tokyo")
);
Instant instant = zdt.toInstant();
Calendar cal = Calendar.getInstance();
cal.setTimeZone(java.util.TimeZone.getTimeZone(zdt.getZone()));
cal.setTime(Date.from(instant));
System.out.println("ZonedDateTime : " + zdt);
System.out.println("Calendar : " + cal.getTime());
}
}
Javaここでの重要ポイントは、
「Calendar のタイムゾーンも明示的に設定する」
ということです。
Calendar → LocalDate / LocalTime 変換
Calendar → LocalDate(“日付だけ”に落とす)
import java.time.*;
import java.util.Calendar;
public class CalendarToLocalDateExample {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
LocalDate date = cal.toInstant()
.atZone(cal.getTimeZone().toZoneId())
.toLocalDate();
System.out.println(date);
}
}
JavaCalendar → LocalTime(“時刻だけ”に落とす)
import java.time.*;
import java.util.Calendar;
public class CalendarToLocalTimeExample {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
LocalTime time = cal.toInstant()
.atZone(cal.getTimeZone().toZoneId())
.toLocalTime();
System.out.println(time);
}
}
Javaここでのポイントは、
「Calendar のタイムゾーンを使って LocalDate / LocalTime を切り出す」
ということです。
Calendar を使うときの注意点
Calendar は「可変」「複雑」「月が0始まり」
Calendar は以下の特徴があり、バグの温床になりやすいです。
月が 0 始まり(1月=0、12月=11)
内部状態が可変(set すると書き換わる)
タイムゾーンの扱いが分かりにくい
サマータイムの影響を受けやすい
だからこそ、
「内部では java.time を使い、Calendar は境界でだけ使う」
という設計が実務では強く推奨されます。
まとめ:Calendar変換で身につけてほしい感覚
Calendar はレガシー API ですが、
変換パターンを覚えてしまえば怖くありません。
Calendar → Instant(toInstant)で新世界へ連れてくる。
Instant → LocalDateTime / ZonedDateTime でロジックを組む。
LocalDateTime / ZonedDateTime → Calendar は ZoneId を意識して変換する。
内部は java.time、境界だけ Calendar という設計が実務的。
あなたのコードのどこかに、
Calendar と LocalDateTime が混在している箇所があれば、
一度「Instant をハブにして整理できないか?」という目で眺めてみると、
日付・時間の扱いが一気にスッキリします。
