和暦西暦の相互変換

新元号の公表が改元1ヶ月前ということで、技術者界隈ではなぜか慌てている人もいるようなのです。アクシア社の米村歩さんは、事前準備できるし、システム改修は1ヶ月もあれば余裕だと言っていますが、私もそう思います。変換するだけなら本当に簡単ですし、事前準備も1行追加で済みます。

慌てている可能性として考えられるのは、Web画面系の開発でドロップリストへ表示するための元号をハードコーディングしてしまっているとか、そういう改修に弱く、工数だけ高くつくというロジックを書いてしまったシステムではないでしょうか。

笑えない話ですが、消費税3%導入時にハードコーディングしてしまい、5%に上がった際に苦労した人や、内税・外税の切り替わりで苦労した人もいると聞いています。

2018.5.18 18:20追記

なんと、平成と昭和をそれぞれTrueとFalseで持っているシステムがあるとか。こういう付け焼き刃的な対応で思い出すのは2000年問題です。信じられないかもしれませんが、日本では西暦を2桁しか持っていないシステムが多く、たとえば40年以上は1900を足して20世紀として扱い、40年未満は2000を足して21世紀として扱うという対応をしたシステムがありました。素直にデータ桁を拡張できなかったからです。


和暦西暦相互変換の実装

和暦と西暦の相互変換処理は至って簡単です。元号を切り替える日付をテーブルとして持っていればよく、リニア検索を使えば済みます。データの管理をする場合はデータベースに頼るほうが安心ですが、別にデータベースがなくてもデータ構造の設計含めて30分もあれば余裕で0から実装できます。

頑張ればいまからでも間に合います!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define elemof(a)   (sizeof(a) / sizeof(*(a)))

typedef struct {
   long switching_date;
   char name;
} ERA_TABLE;

ERA_TABLE era_table[] = {
   20190501, '?',
   19890108, 'H',
   19261225, 'S',
   19120730, 'T',
   18680125, 'M',
};

ERA_TABLE *get_era_table_by_date(long date) {
   for(int i = 0; i < elemof(era_table); i++)
       if (date >= era_table[i].switching_date)
           return era_table +i;

   return NULL;
}

ERA_TABLE *get_era_table_by_name(char era_name) {
   for(int i = 0; i < elemof(era_table); i++)
       if (era_name == era_table[i].name)
           return era_table + i;

   return NULL;
}

// translate chiristian date to japanese date
char *c2j(long cdate, char *buf) {
   ERA_TABLE *p = get_era_table_by_date(cdate);
   sprintf(buf, "%c%02d%04d", p->name, (cdate / 10000) - (p->switching_date / 10000) + 1, cdate % 10000);
   return buf;
}

// translate japanese date to chiristian date
long j2c(char *jdate) {
   ERA_TABLE *p = get_era_table_by_name(*jdate);
   char temp[3] = { '\0' };
   strncpy(temp, jdate + 1, 2);
   return (atol(temp) + p->switching_date / 10000 - 1) * 10000 + atol(jdate + 4);
}

int main(void) {
   char buf[256];

   printf("%s\n", c2j(20190430, buf));
   printf("%ld\n", j2c(buf));

   printf("%s\n", c2j(20190501, buf));
   printf("%ld\n", j2c(buf));

   return 0;
}

実行結果

H310430
20190430
?010501
20190501

問題はテスト

修正自体はテーブル(データベースとは限らない)に1行のみを追加すればよいのですが、テストはそうも行きません。変換処理が既存システムにあればサブルーチンは境界テストだけで済みますが、サービスの維持テストが問題となります。

維持テストとは、たとえば、システムで自動化された帳票が出力される場合に「正しく新元号が印刷されるか」ということをテストすることです。枠がギリギリまで小さくなっており、フォントが枠からはみ出す、あるいは枠のパディングが大きくてフォントが欠けるなどが考えられます。

漢字フォントであればフォント幅はそれほどブレませんが、アルファベットの元号を用いている場合は危ないです。たとえば、元号「明治」を表す「M」は、かなりフォント幅が広いです。実際にテスト不足で欠けてしまったということを目の当たりにしたことがあります。明治時代はレアケースになりつつありますが、新元号はそうもいきませんから、しっかりしたテストが必要です。

Web画面系でドロップダウンリストにアルファベット元号を入れているシステムでは、デザインによっては画面が少し崩れます。これも実際に目の当たりにしたことがあります。元号「平成」の「H」を基準にしてギリギリの表示幅でデザインをしているとこういうことになります。

神Excelのように1枠1文字を守っている場合もあるでしょう。「平成」を「平」「成」と分けなければなりませんので、フォント幅のリスクは2倍です。しかし、それは神Excelのような設計をしたほうがどうかしています。

出遅れると大変なのは遡及

システム改修が出遅れてしまうと、新元号に変わってからも元号「平成」を使い続けなければなりません。そのような対応策を採るということで話題が紛糾しています。

新元号公表、改元1カ月前=「平成」残るケースも=政府の連絡会議が初会合(時事通信)

中でも面倒なのが、同記事内の次の調整です。

2)「平成」と新元号のどちらでもやりとりできるよう調整

こうなってしまうと、元号切替日を超えても平成を扱っていた場合のデータを後から新元号に直さなければならないというケースも起こりえます。稼働しているシステムの過去のデータに対して、あとから必要な加工を加えることを「遡及処理」と呼びますが、遡及の設計もあらかじめしておかなければなりません。

新聞記事のような対応が取られている場合は、おおよそ次の対応をします。「特定条件」がある場合がちょっと面倒です。

元号が切り替わる日以降で、かつ旧元号「平成」が使われており、書き換える必要があるもの(特定条件を覗く)。

遡及処理に失敗し、加工が必要ではないある平成日付のデータを書き換えてしまうと、これもまたシステム障害となりえます。ですから、このような場合は利用者が困らないように夜間や給仕津に作業して対処します。失敗してもデータを戻すことができるからです。

日々刻々とデータが蓄積されてしまうシステムもあります。こういったシステムの場合は、失敗してもデータを戻せばいいや、とは行きませんから、データを復元するための処理を作っておき、後日、改めて遡及する必要があります。これを「追遡及」と呼びます。

もちろん、遡及も追遡及も事前に十分にテストすることができます。たとえば、元号切替日を3日後などに設定しておき、架空の新元号「来是」(キタコレ!)が設定されるかどうか、1週間くらい開発マシンでぐるぐる処理をさせておきます。これを「稼働テスト」「日回しテスト」と言います。

みんなでやれば?

大きな改正に伴うテストは、工数も膨らみがちですから、技術者たちが新元号の事前公表を求める理由もわかろうというものです。

それくらい新元号対応は業務インパクトの大きなものですが、設計や改修に必要な処理の洗い出しは、実はいまからでも十分にできますし、平成対応を行ったオッチャンたちもまだ現役ですので、今からオッチャンたちが対応策をどんどんと広めていけばいいのではないかと思います。

元号対応や消費税対応もそうですが、国の改正に伴う改修は、開発ノウハウという範疇を超えて、共有資産にしてしまったほうが国益になると思います。

この記事が気に入ったら、サポートをしてみませんか?気軽にクリエイターを支援できます。

最後まで読んでいただき、ありがとうございました!
5

Hajime Saito

コメントを投稿するには、 ログイン または 会員登録 をする必要があります。