Java Tips | 日付・時間:Calendar変換

Java Java
スポンサーリンク

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 を持っています。
そして DateInstant に変換できます。

つまり、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());
    }
}
Java

Calendar は 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);
    }
}
Java

Calendar → 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 をハブにして整理できないか?」という目で眺めてみると、
日付・時間の扱いが一気にスッキリします。

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