和暦と西暦の変換は「年だけ」で計算すると、改元のあった年に間違えます。 2019年は4月30日までが平成31年、5月1日からが令和元年で、1989年は1月7日までが昭和64年、1月8日からが平成元年です。正しく変換するには、元号ごとの「改元日」と比べる必要があります。

Java には和暦の暦(JapaneseChronology)があり、JavaScript は Intl.DateTimeFormat で和暦を表示できます。Python・SQL・Excel は元号の一覧表を持って計算します。この記事では、どの言語でも同じ結果になるコードを、改元日の前後で動かした結果つきで載せています。

確認環境:OpenJDK 21.0.10、Node.js 22.22.2(ICU 78.2)、Python 3.11.15、PostgreSQL 16.15、MySQL 8.0.46、LibreOffice Calc 24.2(確認日 2026年10月10日。2026年10月10日は令和8年です)。

早見表:西暦と和暦の対応

年の引き算(改元日より後の日付で使う)

元号 改元日(この日から) 西暦から和暦 和暦から西暦 略字
令和 2019年5月1日 西暦 − 2018 令和 + 2018 R
平成 1989年1月8日 西暦 − 1988 平成 + 1988 H
昭和 1926年12月25日 西暦 − 1925 昭和 + 1925 S
大正 1912年7月30日 西暦 − 1911 大正 + 1911 T
明治 1868年10月23日 西暦 − 1867 明治 + 1867 M

改元をまたぐ年(ここだけは日付で判断する)

西暦 改元日の前日まで 改元日から
2019年 平成31年(1月1日〜4月30日) 令和元年(5月1日〜)
1989年 昭和64年(1月1日〜1月7日) 平成元年(1月8日〜)
1926年 大正15年(1月1日〜12月24日) 昭和元年(12月25日〜)
1912年 明治45年(1月1日〜7月29日) 大正元年(7月30日〜)

よく使う年

西暦 和暦 西暦 和暦
2026年 令和8年 2000年 平成12年
2025年 令和7年 1995年 平成7年
2024年 令和6年 1990年 平成2年
2020年 令和2年 1985年 昭和60年
2010年 平成22年 1975年 昭和50年
2005年 平成17年 1965年 昭和40年

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「和暦⇔西暦変換|Java・JS・Python・SQL・Excel、元年と改元日」

よくある間違い:年だけで元号を決める

// 年だけで判定する書き方(2019年1月1日〜4月30日を令和にしてしまう)
const era = year >= 2019 ? '令和' : year >= 1989 ? '平成' : '昭和';

この書き方では、2019年4月30日が「令和元年」、1989年1月7日が「平成元年」になります。どちらも実際には存在しない日付です。元号は年ではなく、改元日と比べて決めます。

もう1つの間違いは、和暦の入力を検証しないことです。「平成32年1月1日」(平成は31年4月30日まで)や「令和元年4月30日」(令和は5月1日から)は存在しない日付ですが、単純な足し算では「2020年1月1日」「2019年4月30日」に変換できてしまいます。以下のコードはどちらもエラーとして扱います。

Java:JapaneseChronology を使う

Java 8 以降の java.time には和暦の暦 JapaneseChronology があり、令和にも対応しています。DateTimeFormatter に暦を指定すると、西暦の LocalDate を和暦で表示でき、和暦の文字列を LocalDate に戻せます。

import java.time.LocalDate;
import java.time.chrono.JapaneseChronology;
import java.time.chrono.JapaneseDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.ResolverStyle;
import java.time.temporal.ChronoField;
import java.util.Locale;
import java.util.Map;

public class Wareki {

    // 「令和7年10月10日」形式(元年は「1年」)
    static final DateTimeFormatter BASIC =
        DateTimeFormatter.ofPattern("GGGGy年M月d日", Locale.JAPAN)
            .withChronology(JapaneseChronology.INSTANCE);

    // 1年を「元年」と表示・解析する形式
    static final DateTimeFormatter GANNEN = new DateTimeFormatterBuilder()
        .appendText(ChronoField.ERA, java.time.format.TextStyle.FULL)
        .appendText(ChronoField.YEAR_OF_ERA, Map.of(1L, "元"))   // 1 → 元
        .appendLiteral('年')
        .appendValue(ChronoField.MONTH_OF_YEAR).appendLiteral('月')
        .appendValue(ChronoField.DAY_OF_MONTH).appendLiteral('日')
        .toFormatter(Locale.JAPAN)
        .withChronology(JapaneseChronology.INSTANCE)
        .withResolverStyle(ResolverStyle.STRICT);

    // 和暦の文字列を解析する形式(存在しない日付はエラーにする)
    static final DateTimeFormatter PARSER =
        DateTimeFormatter.ofPattern("GGGGy年M月d日", Locale.JAPAN)
            .withChronology(JapaneseChronology.INSTANCE)
            .withResolverStyle(ResolverStyle.STRICT);

    static LocalDate parseWareki(String text) {
        String s = text.replace("元年", "1年");                 // 元年を1年として読む
        return LocalDate.from(PARSER.parse(s));
    }

    // 「R8.10.10」形式(元号の略字+年.月.日)
    static final DateTimeFormatter SHORT =
        DateTimeFormatter.ofPattern("GGGGGy.M.d", Locale.JAPAN)
            .withChronology(JapaneseChronology.INSTANCE);

    public static void main(String[] args) {
        String[] days = {"1926-12-24", "1926-12-25", "1989-01-07", "1989-01-08",
                         "2019-04-30", "2019-05-01", "2026-10-10"};
        System.out.println("西暦        | GGGGy年M月d日   | 元年表記           | 略記");
        for (String d : days) {
            LocalDate date = LocalDate.parse(d);
            System.out.printf("%s | %s | %s | %s%n", d,
                BASIC.format(date), GANNEN.format(date), SHORT.format(date));
        }

        // 和暦 → 西暦
        for (String s : new String[]{"令和元年5月1日", "平成31年4月30日", "昭和64年1月7日", "令和8年10月10日"}) {
            System.out.println(s + " → " + parseWareki(s));
        }

        // 存在しない和暦
        for (String s : new String[]{"平成32年1月1日", "令和元年4月30日", "令和8年2月30日"}) {
            try {
                System.out.println(s + " → " + parseWareki(s));
            } catch (Exception e) {
                System.out.println(s + " → 例外: " + e.getMessage());
            }
        }
        System.out.println("JapaneseDate = " + JapaneseDate.from(LocalDate.of(2026, 10, 10)));
    }
}
$ java -Dstdout.encoding=UTF-8 Wareki.java
西暦        | GGGGy年M月d日   | 元年表記           | 略記
1926-12-24 | 大正15年12月24日 | 大正15年12月24日 | T15.12.24
1926-12-25 | 昭和1年12月25日 | 昭和元年12月25日 | S1.12.25
1989-01-07 | 昭和64年1月7日 | 昭和64年1月7日 | S64.1.7
1989-01-08 | 平成1年1月8日 | 平成元年1月8日 | H1.1.8
2019-04-30 | 平成31年4月30日 | 平成31年4月30日 | H31.4.30
2019-05-01 | 令和1年5月1日 | 令和元年5月1日 | R1.5.1
2026-10-10 | 令和8年10月10日 | 令和8年10月10日 | R8.10.10
令和元年5月1日 → 2019-05-01
平成31年4月30日 → 2019-04-30
昭和64年1月7日 → 1989-01-07
令和8年10月10日 → 2026-10-10
平成32年1月1日 → 例外: Text '平成32年1月1日' could not be parsed: year, month, and day not valid for Era
令和元年4月30日 → 例外: Text '令和1年4月30日' could not be parsed: year, month, and day not valid for Era
令和8年2月30日 → 例外: Text '令和8年2月30日' could not be parsed: year, month, and day not valid for Era
JapaneseDate = Japanese Reiwa 8-10-10

パターン文字の意味

パターン 意味 2019-05-01 の結果
GGGG 元号(正式名) 令和
G 元号(短い形) 令和
GGGGG 元号(略字) R
y 元号の中の年(1始まり) 1
M/d 月/日 5/1
  • GGGGy年 だけでは「元年」にならず「1年」と表示されます。 元年にしたい場合は、DateTimeFormatterBuilder.appendText(ChronoField.YEAR_OF_ERA, Map.of(1L, "元")) で1年の表示を「元」に置き換えます
  • 読み取りは「元年」を「1年」に置き換えてから解析すると、どちらの表記でも受け付けられます
  • ResolverStyle.STRICT を付けると、元号の期間外や存在しない日がすべて例外になります。付けない既定(SMART)で試すと、次のように通ってしまう入力がありました
SMART(既定)の結果
平成32年1月1日 → 例外 Text '平成32年1月1日' could not be parsed: Invalid YearOfEra for Era: Heisei 32
令和1年4月30日 → 2019-04-30     ← 令和になる前の日付なのに通る
令和8年2月30日 → 2026-02-28     ← 月末に丸められる
  • 標準出力に日本語を出すときは -Dstdout.encoding=UTF-8 を付けます(付けないと環境によっては ? に化けます)
  • JapaneseChronology が扱えるのは明治6年(1873年)以降です。それより前の日本は旧暦(太陰太陽暦)だったため、西暦との日付の対応が単純な引き算になりません

JavaScript:Intl.DateTimeFormat で表示、読み取りは自作

ブラウザと Node.js では、ロケールに ja-JP-u-ca-japanese(日本の暦)を指定すると和暦で表示できます。

const d = new Date('2019-05-01T00:00:00+09:00');

new Intl.DateTimeFormat('ja-JP-u-ca-japanese', { dateStyle: 'long', timeZone: 'Asia/Tokyo' }).format(d);
// '令和元年5月1日'

d.toLocaleDateString('ja-JP-u-ca-japanese', { era: 'short', timeZone: 'Asia/Tokyo' });
// '令和1/5/1'

new Intl.DateTimeFormat('ja-JP-u-ca-japanese', { era: 'narrow', year: 'numeric', timeZone: 'Asia/Tokyo' }).format(d);
// 'R元年'

Node.js 22(ICU 78.2)では dateStyle: 'long' で「元年」まで表示されました。ただし formatToParts で年の部品を取ると '1' が返るため、部品を組み立てて表示する場合は自分で「元」に置き換えます。表示の細部は ICU(国際化ライブラリ)の版で変わるので、画面に出す形式は自分の実行環境で一度確かめておきます。

timeZone: 'Asia/Tokyo' は必ず付けます。 付けないと、サーバーやブラウザの時差によって日付が1日ずれ、改元日の前後で元号が変わってしまうことがあります。

和暦の文字列を西暦に戻す関数は JavaScript に用意されていないので、元号の一覧表を使って作ります。

// 和暦⇔西暦の変換(改元日まで見る)
const ERAS = [                       // 新しい順。start は改元日
  { name: '令和', short: 'R', start: '2019-05-01' },
  { name: '平成', short: 'H', start: '1989-01-08' },
  { name: '昭和', short: 'S', start: '1926-12-25' },
  { name: '大正', short: 'T', start: '1912-07-30' },
  { name: '明治', short: 'M', start: '1868-10-23' },
];

// 西暦 → 和暦(Intl を使う)
function toWareki(date, { gannen = true } = {}) {
  const fmt = new Intl.DateTimeFormat('ja-JP-u-ca-japanese', {
    era: 'long', year: 'numeric', month: 'numeric', day: 'numeric', timeZone: 'Asia/Tokyo',
  });
  const parts = Object.fromEntries(fmt.formatToParts(date).map((p) => [p.type, p.value]));
  const year = gannen && parts.year === '1' ? '元' : parts.year;
  return `${parts.era}${year}年${parts.month}月${parts.day}日`;
}

// 和暦 → 西暦(「令和元年5月1日」「R1.5.1」「平成31年4月30日」などを受け付ける)
function fromWareki(text) {
  const s = text
    .replace(/[0-9]/g, (c) => String.fromCharCode(c.charCodeAt(0) - 0xfee0))
    .replace(/元/, '1')
    .trim();
  const m = s.match(/^(令和|平成|昭和|大正|明治|[RHSTMrhstm])\s*(\d{1,2})[年.\/-](\d{1,2})[月.\/-](\d{1,2})日?$/);
  if (!m) throw new Error(`和暦として読めません: ${text}`);
  const era = ERAS.find((e) => e.name === m[1] || e.short === m[1].toUpperCase());
  const [y, mo, d] = [Number(m[2]), Number(m[3]), Number(m[4])];
  const startYear = Number(era.start.slice(0, 4));
  const date = new Date(Date.UTC(startYear + y - 1, mo - 1, d));
  const iso = date.toISOString().slice(0, 10);
  // 2月30日のような日付と、元号の期間外(平成32年など)をはじく
  const next = ERAS[ERAS.indexOf(era) - 1];
  if (date.getUTCMonth() !== mo - 1 || date.getUTCDate() !== d
      || iso < era.start || (next && iso >= next.start)) {
    throw new Error(`存在しない日付です: ${text}`);
  }
  return iso;
}

module.exports = { toWareki, fromWareki, ERAS };

if (require.main === module) {
  for (const d of ['1926-12-24', '1926-12-25', '1989-01-07', '1989-01-08', '2019-04-30', '2019-05-01', '2026-10-10']) {
    console.log(d, '→', toWareki(new Date(d + 'T00:00:00+09:00')));
  }
  for (const s of ['令和元年5月1日', 'R1.5.1', '平成31年4月30日', 'S64/1/7', 'h1-1-8', '令和8年10月10日',
                   '平成32年1月1日', '令和元年4月30日', '令和8年2月30日']) {
    try { console.log(s, '→', fromWareki(s)); } catch (e) { console.log(s, '→', e.message); }
  }
}
$ node wareki.js
1926-12-24 → 大正15年12月24日
1926-12-25 → 昭和元年12月25日
1989-01-07 → 昭和64年1月7日
1989-01-08 → 平成元年1月8日
2019-04-30 → 平成31年4月30日
2019-05-01 → 令和元年5月1日
2026-10-10 → 令和8年10月10日
令和元年5月1日 → 2019-05-01
R1.5.1 → 2019-05-01
平成31年4月30日 → 2019-04-30
S64/1/7 → 1989-01-07
h1-1-8 → 1989-01-08
令和8年10月10日 → 2026-10-10
平成32年1月1日 → 存在しない日付です: 平成32年1月1日
令和元年4月30日 → 存在しない日付です: 令和元年4月30日
令和8年2月30日 → 存在しない日付です: 令和8年2月30日

fromWareki は「令和元年5月1日」「R1.5.1」「平成31年4月30日」(全角数字)「S64/1/7」「h1-1-8」を同じように読み取り、元号の期間外と存在しない日付をエラーにします。

Python:元号の一覧表で変換する

Python の標準ライブラリには和暦の暦が無いので、元号の一覧表を持って計算します。

"""和暦⇔西暦の変換(標準ライブラリのみ。改元日まで見る)"""
import re
from datetime import date

ERAS = [  # 新しい順。(元号, 略字, 改元日)
    ('令和', 'R', date(2019, 5, 1)),
    ('平成', 'H', date(1989, 1, 8)),
    ('昭和', 'S', date(1926, 12, 25)),
    ('大正', 'T', date(1912, 7, 30)),
    ('明治', 'M', date(1868, 10, 23)),
]

def to_wareki(d: date, gannen: bool = True) -> str:
    for name, _, start in ERAS:
        if d >= start:
            y = d.year - start.year + 1
            ys = '元' if (gannen and y == 1) else str(y)
            return f'{name}{ys}年{d.month}月{d.day}日'
    raise ValueError(f'明治より前の日付です: {d}')

_PAT = re.compile(r'^(令和|平成|昭和|大正|明治|[RHSTM])\s*(\d{1,2})[年./-](\d{1,2})[月./-](\d{1,2})日?$', re.I)

def from_wareki(text: str) -> date:
    s = text.translate({i: i - 0xFEE0 for i in range(0xFF10, 0xFF1A)}).replace('元', '1').strip()
    m = _PAT.match(s)
    if not m:
        raise ValueError(f'和暦として読めません: {text}')
    i = next(i for i, e in enumerate(ERAS) if m[1] in (e[0], e[1], e[1].lower()))
    name, _, start = ERAS[i]
    d = date(start.year + int(m[2]) - 1, int(m[3]), int(m[4]))   # 2月30日は ValueError
    if d < start or (i > 0 and d >= ERAS[i - 1][2]):
        raise ValueError(f'{name}の期間外です: {text}')
    return d

if __name__ == '__main__':
    for s in ['1926-12-24', '1926-12-25', '1989-01-07', '1989-01-08', '2019-04-30', '2019-05-01', '2026-10-10']:
        print(s, '→', to_wareki(date.fromisoformat(s)))
    for s in ['令和元年5月1日', 'R1.5.1', '平成31年4月30日', 'S64/1/7', '令和8年10月10日',
              '平成32年1月1日', '令和元年4月30日', '令和8年2月30日']:
        try:
            print(s, '→', from_wareki(s))
        except ValueError as e:
            print(s, '→', e)
$ python3 wareki.py
1926-12-24 → 大正15年12月24日
1926-12-25 → 昭和元年12月25日
1989-01-07 → 昭和64年1月7日
1989-01-08 → 平成元年1月8日
2019-04-30 → 平成31年4月30日
2019-05-01 → 令和元年5月1日
2026-10-10 → 令和8年10月10日
令和元年5月1日 → 2019-05-01
R1.5.1 → 2019-05-01
平成31年4月30日 → 2019-04-30
S64/1/7 → 1989-01-07
令和8年10月10日 → 2026-10-10
平成32年1月1日 → 平成の期間外です: 平成32年1月1日
令和元年4月30日 → 令和の期間外です: 令和元年4月30日
令和8年2月30日 → day is out of range for month

存在しない日(2月30日)は date() が ValueError を出すので、元号の期間外と同じく except ValueError で受け止められます。

SQL:元号テーブルを作って結合する

SQL には(Oracle を除いて)和暦の関数が無いので、元号の一覧をテーブルにして、日付が「改元日以上・次の改元日未満」に入る行と結合します。

CREATE TABLE japanese_era (
  name       VARCHAR(4) PRIMARY KEY,
  short_name CHAR(1)    NOT NULL,
  start_date DATE       NOT NULL,
  end_date   DATE                  -- 次の元号の改元日(現在の元号は NULL)
);
INSERT INTO japanese_era VALUES
 ('令和', 'R', '2019-05-01', NULL),
 ('平成', 'H', '1989-01-08', '2019-05-01'),
 ('昭和', 'S', '1926-12-25', '1989-01-08'),
 ('大正', 'T', '1912-07-30', '1926-12-25'),
 ('明治', 'M', '1868-10-23', '1912-07-30');

西暦→和暦(PostgreSQL)

SELECT d.dt,
       e.name || CASE WHEN EXTRACT(YEAR FROM d.dt) - EXTRACT(YEAR FROM e.start_date) + 1 = 1
                      THEN '元' ELSE (EXTRACT(YEAR FROM d.dt) - EXTRACT(YEAR FROM e.start_date) + 1)::text END
       || '年' || EXTRACT(MONTH FROM d.dt) || '月' || EXTRACT(DAY FROM d.dt) || '日' AS wareki
FROM (VALUES (DATE '1989-01-07'), (DATE '1989-01-08'), (DATE '2019-04-30'),
             (DATE '2019-05-01'), (DATE '2026-10-10')) d(dt)
JOIN japanese_era e
  ON d.dt >= e.start_date AND (e.end_date IS NULL OR d.dt < e.end_date)
ORDER BY d.dt;
     dt     |     wareki
------------+-----------------
 1989-01-07 | 昭和64年1月7日
 1989-01-08 | 平成元年1月8日
 2019-04-30 | 平成31年4月30日
 2019-05-01 | 令和元年5月1日
 2026-10-10 | 令和8年10月10日

西暦→和暦(MySQL)

SELECT d.dt,
       CONCAT(e.name,
              IF(YEAR(d.dt) - YEAR(e.start_date) + 1 = 1, '元', YEAR(d.dt) - YEAR(e.start_date) + 1),
              '年', MONTH(d.dt), '月', DAY(d.dt), '日') AS wareki
FROM (SELECT DATE '1989-01-07' AS dt UNION ALL SELECT '1989-01-08' UNION ALL SELECT '2019-04-30'
      UNION ALL SELECT '2019-05-01' UNION ALL SELECT '2026-10-10') d
JOIN japanese_era e
  ON d.dt >= e.start_date AND (e.end_date IS NULL OR d.dt < e.end_date)
ORDER BY d.dt;

MySQL 8.0.46 でも同じ5行が返りました。

和暦→西暦(PostgreSQL)

SELECT w.era, w.y, w.m, w.d,
       make_date(EXTRACT(YEAR FROM e.start_date)::int + w.y - 1, w.m, w.d) AS seireki
FROM (VALUES ('令和', 1, 5, 1), ('平成', 31, 4, 30), ('昭和', 64, 1, 7)) w(era, y, m, d)
JOIN japanese_era e ON e.name = w.era;
 era  | y  | m | d  |  seireki
------+----+---+----+------------
 令和 |  1 | 5 |  1 | 2019-05-01
 平成 | 31 | 4 | 30 | 2019-04-30
 昭和 | 64 | 1 |  7 | 1989-01-07

変換結果が start_date 以上・end_date 未満かを WHERE に足すと、期間外の和暦をはじけます。

Oracle:NLS_CALENDAR を指定する

Oracle は TO_CHAR の第3引数で暦を和暦(Japanese Imperial)にできます。EE が元号、YY が元号の中の年です。

SELECT TO_CHAR(DATE '2019-05-01', 'EEYY"年"MM"月"DD"日"',
               'NLS_CALENDAR=''Japanese Imperial''') AS wareki
FROM dual;

Excel:表示は書式、計算は元号表

和暦で表示する

方法 書き方 2019/5/1 の表示
書式(TEXT 関数) =TEXT(A2,"ggge年m月d日") 令和1年5月1日
略字 =TEXT(A2,"ge.m.d") R1.5.1
元年で表示(セルの書式) Ctrl+1 →[日付]→[カレンダーの種類]を和暦にし、「元年を使用して1年目を表示」にチェック 令和元年5月1日

g が元号、e が元号の中の年です。Microsoft のサポート記事では、元年の表示はセルの書式設定の[日付]で、ロケールを日本語、カレンダーの種類を和暦にして、元年を使う項目にチェックを入れる手順が案内されています。

元号・年・月・日の列から西暦を求める

元号表(G〜J列)を作り、VLOOKUP で開始年を引いて計算します。期間外は「期間外」と表示します。

G 元号 H 開始年 I 改元日 J 次の改元日
2 令和 2019 2019/05/01 9999/12/31
3 平成 1989 1989/01/08 2019/05/01
4 昭和 1926 1926/12/25 1989/01/08
5 大正 1912 1912/07/30 1926/12/25
6 明治 1868 1868/10/23 1912/07/30
=IF(OR(DATE(VLOOKUP(A2,$G$2:$J$6,2,FALSE)+B2-1,C2,D2)<VLOOKUP(A2,$G$2:$J$6,3,FALSE),
       DATE(VLOOKUP(A2,$G$2:$J$6,2,FALSE)+B2-1,C2,D2)>=VLOOKUP(A2,$G$2:$J$6,4,FALSE)),
    "期間外",
    DATE(VLOOKUP(A2,$G$2:$J$6,2,FALSE)+B2-1,C2,D2))

(実際には1行で入力します。A列に元号、B〜D列に年・月・日)

LibreOffice Calc 24.2 で計算した結果です。

元号 年 月 日 西暦
令和 1 5 1 2019/05/01
平成 31 4 30 2019/04/30
昭和 64 1 7 1989/01/07
令和 8 10 10 2026/10/10
平成 32 1 1 期間外

Excel 365 なら LET 関数で DATE(...) を1回だけ書く形にまとめられます。なお Excel の日付は1900年1月1日からなので、明治32年(1899年)以前の日付はセルの日付として扱えません。

入力フォームで和暦を受け付けるときの注意

項目 おすすめ
入力の形 「元号の選択欄+年・月・日の数値欄」にすると、表記ゆれ(R1、令和元、令1)を受けずに済む
自由入力を受ける場合 全角数字・略字(R/H/S)・区切り(年月日、.、/、-)・「元」を正規化してから読む
検証 元号の期間外(平成32年)と存在しない日(2月30日)をはじく
保存 DB には西暦の日付型で保存し、和暦は表示するときに変換する
新しい元号への備え 元号を一覧表やテーブルで持ち、コードに 2018 などの数字を直接書かない

よくある質問

Q. 「令和1年」と「令和元年」、どちらで表示すべきですか。 A. 公的な書類や一般向けの画面では「元年」が使われることが多く、帳票やデータの受け渡しでは数字の「1年」に統一することもあります。読み取り側は両方を受け付け、表示は用途に合わせて選ぶのが扱いやすい形です。

Q. 2019年の書類は平成と令和のどちらですか。 A. 4月30日までは平成31年、5月1日からは令和元年です。年だけでなく月日で判断します。

Q. 新しい元号になったらコードを直す必要がありますか。 A. Java と JavaScript(Intl)は、実行環境(JDK や ICU)の更新で新しい元号に対応します。Python・SQL・Excel の元号表は、自分で1行追加します。どちらの場合も、元号を一覧で管理しておけば修正は1か所で済みます。

Q. 明治5年より前の日付は変換できますか。 A. 明治5年12月2日までの日本は旧暦(太陰太陽暦)で、翌日が明治6年1月1日(グレゴリオ暦)です。それより前の日付は、年の引き算では西暦の日付に正しく対応しません。Java の JapaneseChronology も明治6年以降を扱います。

まとめ

  • 元号は年ではなく改元日で決める:平成31年4月30日の翌日が令和元年5月1日、昭和64年1月7日の翌日が平成元年1月8日
  • 年の引き算:令和=西暦−2018、平成=西暦−1988、昭和=西暦−1925(改元日より後の日付で使う)
  • Java は JapaneseChronology+DateTimeFormatter。元年は appendText で置き換え、読み取りは ResolverStyle.STRICT で期間外をはじく
  • JavaScript は Intl.DateTimeFormat('ja-JP-u-ca-japanese') で表示、timeZone: 'Asia/Tokyo' を必ず付ける。読み取りは元号表で自作
  • Python・SQL・Excel は元号表(元号・略字・改元日・次の改元日)を持って計算する
  • 保存は西暦の日付型、和暦は表示のときだけにすると、新しい元号にも1か所の修正で対応できる

参考・出典

確認日はいずれも 2026年10月10日です。

  • Java SE 21 API「java.time.chrono.JapaneseChronology」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/chrono/JapaneseChronology.html
  • Java SE 21 API「java.time.chrono.JapaneseEra」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/chrono/JapaneseEra.html
  • Java SE 21 API「DateTimeFormatter」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/format/DateTimeFormatter.html
  • MDN「Intl.DateTimeFormat」:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat
  • Microsoft サポート(Excel の元年の表示):https://support.microsoft.com/ja-JP/Excel/japan-era-changes-and-gannen
  • Oracle Database Globalization Support Guide「Calendar Systems」:https://docs.oracle.com/en/database/oracle/oracle-database/19/nlspg/setting-up-globalization-support-environment.html
  • PostgreSQL 16 文書「日付/時刻関数(make_date)」:https://www.postgresql.org/docs/16/functions-datetime.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「和暦⇔西暦変換|Java・JS・Python・SQL・Excel、元年と改元日」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?