Kohei Blog

夫・父親・医療系エンジニア

Reactで和暦と西暦の表示切り替えをする関数を書いた

すでに令和も4年。平成まではギリ西暦⇔和暦の変換ができていたけれど、令和になってからは覚えるのもめんどくさくなり、ググらないと今は令和何年なのかもわからないという人もいるのでは?

前職は病院の事務員だったので、様々な行政の書類や日々の業務の中で和暦にふれる機会が多かったのですが、、IT業界へ転職し、書類を処理したり患者様の対応をすることもないので、わざわざ和暦で年を数えることもなくなりました。

ただし、役所や医療機関など行政書類を扱ったり、保険情報などを扱う場合は和暦が標準になっているケースが多く、そういった業務アプリの開発には和暦対応も要求されると思っています。

今回は、和暦⇔西暦で相互変換する関数を実装してみました。

やりたいこと

やりたいことをざっと書き出してみたのが以下

  • 和暦⇔西暦の切り替えボタンにより、表示形式の切り替えができる

  • ページ内に存在する日付データの形式がまとめて切り替わる

  • あくまで表示を切り替えるだけで元データには影響を与えない

実装イメージ

  • コンポーネント(Page)でboolean型の表示形式の状態を持つ

  • コンポーネント(Page)でstring型の日付データを持つ。

  • 日付データは必須項目である

  • 関数は日付情報と表示形式の状態を引数として受け取る

  • 表示形式の状態によって、和暦と西暦の表示切り替えをする

結論

まずは結論として、Codesandboxを御覧ください。

https://codesandbox.io/embed/date-he-li-xi-li-og86ng?fontsize=14&hidenavigation=1&theme=dark

表示切り替えのボタンをクリックすると、BirthDayの一覧すべての項目に対し、表示形式の切り替えができます。

メインとなるのは utils.ts に定義している関数 conversionBetweenJpAndAdです。

dummy.ts は単なるダミーデータなので割愛。

実装方法

utils.ts

import { parse } from "date-fns";
import ja from "date-fns/locale/ja";

export const conversionBetweenJpAndAd = (date: string, jpFormat: boolean) => {
  if (jpFormat) {
    const jp = new Intl.DateTimeFormat("ja-JP-u-ca-japanese", {
      era: "long",
      year: "numeric",
      month: "long",
      day: "numeric"
    }).format(
      new Date(parse(date, "yyyy年M月d日", new Date(), { locale: ja }))
    );

    return jp;
  }

  return date;
};

日付ライブラリは date-fnsを使いました。

date-fnsは日付データのパースに使用している程度で、本命は Intl.DateTimeFormatです。

Intlは国際化API名前空間で、数値フォーマットや表示名の翻訳など国ごとの表記に変換するAPIが用意されています。

その中の一つが今回使用したIntl.DateTimeFormat()で、言語に依存した日時のフォーマットができるAPIです。

Intl - JavaScript | MDN

Intl オブジェクトは、 ECMAScript の国際化 API名前空間で、言語に依存した文字列の比較、数値の書式化と、日付の書式化を提供します。 Intl オブジェクトは、いくつかのコンストラクターに加え、国際化コンストラクターや他の言語に関する関数に共通する機能へのアクセスを提供します。

  • 第一引数 ... locale(日本であればja-JP-u-ca-japanese)

  • 第二引数 ... options(年、月、日の表記形式やタイムゾーンの表記形式など)

第二引数にeraを指定すると、元号を付与して表示させることができます。

今回はstring形式の日付データを扱うため、フォーマットする際は、string形式の日付データをdate-fnsDate型にパースして渡してあげる必要があります。

あとは、表示形式の状態を定義したjpFormatを受け取って条件分岐させ、jpFormatでない場合は日付データをそのままreturnするようにしました。

コンポーネントApp.tsx

コンポーネント側では、jpFormatとして表示形式の状態をboolean型で定義し、Buttonをクリックした際にstateを更新するようにします。これによって、和暦⇔西暦の切り替えを実現させます。

usersデータを表示させる際、conversionBetweenJpAndAdを呼び出してuser.birthDatejpFormatを引数として渡してあげれば完成です。

App.tsx

import { useState, useCallback } from "react";
import { conversionBetweenJpAndAd } from "./utils";
import { users } from "./dummy";
import "./styles.css";

export default function App() {

  const [jpFormat, setJpFormat] = useState<boolean>(false);
  const onChangeDateViewType = useCallback(() => {
    setJpFormat((prevState) => !prevState);
  }, []);

  return (
    <div className="App">
      <div className="button">
        <button onClick={onChangeDateViewType} type="button">
          {jpFormat ? "西暦表示" : "和暦表示"}
        </button>
      </div>
      <ul className="list">
        <li className="listHead">
          <span>ID</span>
          <span>UserName</span>
          <span>BirthDay</span>
        </li>
        {users.map((user) => (
          <li key={user.id}>
            <span>{user.id}</span>
            <span>{user.name}</span>
            <span>{conversionBetweenJpAndAd(user.birthDate, jpFormat)}</span>
          </li>
        ))}
      </ul>
    </div>
  );
}

所感

和暦って、正規表現で処理マッチさせて処理を書いていくイメージだったのですが、Intl.DateTimeFormatdate-fnsを使うことで簡単に実装できました。

ググっても和暦⇔西暦の切り替え機能を作っている人はあまりいなく、こういった実装方法で問題がないのかは不安ではありますが、イメージどおりの動きをしてくれていると思います。

「平成6年って、西暦何年だっけ?」みたいなケースにサクッと切り替えられるのは個人的には嬉しい。使える機会があれば業務アプリの開発で使ってみようと思います。

参考リンク