概要

和暦の基本的な変換は JapaneseDate と DateTimeFormatter で対応できますが、実務ではもう少し踏み込んだ要件に直面します。「R6」「H30」のような英字略称から西暦への変換、元号境界をまたぐ日付の正確な判定、帳票向けの「元年」表記、そして元号を型安全に扱うための設計パターンなどです。この記事では、wareki-conversion で扱った基本変換の先にある実務的な要件を掘り下げ、Java 17 の switch 式や Java 21 の sealed interface / pattern matching を活用した堅牢な実装を紹介します。

使いどころ

金融系帳票で「R6」「H30」のような SHR 英字略称を西暦年に変換する

元号の境界日(2019/5/1 など)をまたぐ期間を正確に計算する

和暦を sealed interface で型安全にモデル化し、元号ごとの処理分岐を網羅的に書く

コード例

SHR略称変換と sealed interface による型安全な和暦モデル
import java.time.LocalDate;

public class JapaneseEraDetailed {

    private static final int REIWA_BASE  = 2018;
    private static final int HEISEI_BASE = 1988;
    private static final int SHOWA_BASE  = 1925;
    private static final int TAISHO_BASE = 1911;

    public static String toWareki(LocalDate date) {
        var jDate = JapaneseDate.from(date);
        var eraFmt = DateTimeFormatter.ofPattern(
            "GGGG", Locale.JAPANESE);
        var eraName = eraFmt.format(jDate);
        int year = jDate.get(ChronoField.YEAR_OF_ERA);
        return (year == 1)
            ? eraName + "元年"
            : eraName + year + "年";
    }

    public static int abbreviationToSeireki(String abbrev) {
        if (abbrev == null || abbrev.length() < 2) {
            throw new IllegalArgumentException(
                "不正な略称: " + abbrev);
        }
        char era = Character.toUpperCase(abbrev.charAt(0));
        int japYear = Integer.parseInt(abbrev.substring(1));
        int base = switch (era) {
            case 'R' -> REIWA_BASE;
            case 'H' -> HEISEI_BASE;
            case 'S' -> SHOWA_BASE;
            case 'T' -> TAISHO_BASE;
            default  -> throw new IllegalArgumentException(
                "不明な元号: " + era);
        };
        return base + japYear;
    }

    public static void main(String[] args) {

        System.out.println(toWareki(LocalDate.of(2025, 3, 27)));
        System.out.println(toWareki(LocalDate.of(2019, 5, 1)));
        System.out.println(toWareki(LocalDate.of(2019, 4, 30)));

        System.out.println("R7  -> " + abbreviationToSeireki("R7"));
        System.out.println("H30 -> " + abbreviationToSeireki("H30"));
        System.out.println("S64 -> " + abbreviationToSeireki("S64"));
    }
}

Java 8 / 17 / 21 の完全なサンプルコードは GitHub リポジトリ で確認できます。

Version Coverage

switch 式で SHR略称や元号名の分岐が簡潔に書ける。fall-through がなく、値を直接返せる。

Java 17
// Java 17: switch 式で簡潔に記述
int base = switch (era) {
    case 'R' -> REIWA_BASE;
    case 'H' -> HEISEI_BASE;
    case 'S' -> SHOWA_BASE;
    case 'T' -> TAISHO_BASE;
    default  -> throw new IllegalArgumentException(
        "不明な元号: " + era);
};
return base + japYear;

Library Comparison

Pure Java (JapaneseDate + switch式)和暦変換が主目的なら標準 API で十分。JDK 更新で新元号にも自動対応できる。SHR略称の変換は自前実装が必要。
ICU4J旧字体の元号表記や、より高度な国際化暦体系が必要な場合。依存が大きく、和暦変換だけなら過剰。

注意点

SHR略称の変換は年レベルの簡易方式。月日をまたぐ正確な境界判定が必要な場合は JapaneseDate 方式を使うこと

JapaneseDate は明治6年(1873年)以降のみ対応。それ以前の日付を渡すと DateTimeException が発生する

DateTimeFormatter の和暦パターンで G の数は表示名の長さを制御する。GGGG で「令和」、G で「令」のように変わる

sealed interface で元号を型安全に表現する場合、新しい元号の追加時にはコンパイルエラーで漏れを検出できるが、permits 宣言の更新が必要になる

FAQ

SHR略称の「R」「H」「S」はどこで定義されている規格ですか?

公式規格ではなく慣例です。金融や行政の帳票で広く使われていますが、システムごとに確認が必要です。

sealed interface で元号を表現するメリットは何ですか?

新しい元号が追加されたとき、permits 宣言を更新すれば switch 文の網羅漏れをコンパイルエラーで検出できます。

元年表記を「1年」にしたい場合はどうしますか?

toWareki メソッドの year == 1 判定を外すだけで対応できます。帳票仕様に合わせて切り替えてください。

関連書籍

この記事のテーマをさらに深く学びたい方へ。

※ Amazon アソシエイトリンクを含みます