【C言語】
西暦和暦変換プログラム
~明治/大正/昭和/平成/令和対応~

■この記事の概要

この記事では、西暦と和暦を相互に変換するプログラムの例を示しています。

具体的なコードを用いて、各元号の期間を定義し、ユーザーが入力した日付に基づいて変換を行う方法を説明しています。


■西暦を干支に変換(if文もswitch文も使わない)

#include <stdio.h>
char *西暦干支変換(int 西暦){
    static char *干支[] ={
        [0]="申(さる)"    ,   
        [1]="酉(とり)"    ,   
        [2]="戌(いぬ)"    ,   
        [3]="亥(い)"      ,     
        [4]="子(ね)"      , 
        [5]="丑(うし)"    , 
        [6]="寅(とら)"    ,
        [7]="卯(う)"      ,         
        [8]="辰(たつ)"    , 
        [9]="巳(み)"      ,   
        [10]="午(うま)"   ,  
        [11]="未(ひつじ)" 
    };
    return  干支[西暦 % 12] ;
}
int main(void){
    const int 今年=2025;
	for(int 西暦 = 今年; 西暦 <= 今年+12; 西暦++){
        printf("西暦%4d年の干支は%s\n",
            西暦,
            西暦干支変換(西暦)
        );
    }
}
./a.out
西暦2025年の干支は巳(み)
西暦2026年の干支は午(うま)
西暦2027年の干支は未(ひつじ)
西暦2028年の干支は申(さる)
西暦2029年の干支は酉(とり)
西暦2030年の干支は戌(いぬ)
西暦2031年の干支は亥(い)
西暦2032年の干支は子(ね)
西暦2033年の干支は丑(うし)
西暦2034年の干支は寅(とら)
西暦2035年の干支は卯(う)
西暦2036年の干支は辰(たつ)
西暦2037年の干支は巳(み)

干支の配列を子年から始めないで
西暦を十二支で割った余りが0になる
さる年から始めるのがミソです


■西暦を和暦に変換(年月日をまとめてint型にする)

#include <stdio.h>
#include <string.h>
#include <limits.h>
/*
    元号期間
明治	1868-01-25  1912-07-29
大正	1912-07-30  1926-12-24
昭和	1926-12-25  1989-01-07
平成	1989-01-08  2019-04-30
令和	2019-05-01
*/
char *西暦和暦変換(int 年,int 月,int 日){
    int y = 年;
    int m = 月;
    int d = 日;
    int ymd = y*10000 + m*100 +d;
    char *G;
    switch(ymd){
    case    18680125 ... 19120729:  G="明治";y -= 1868;  break; 
    case    19120730 ... 19261224:  G="大正";y -= 1912;  break;        
    case    19261225 ... 19890107:  G="昭和";y -= 1926;  break; 
    case    19890108 ... 20190430:  G="平成";y -= 1989;  break; 
    case    20190501 ... INT_MAX:   G="令和";y -= 2019;  break;
    default:                        G="未対応"; y -= 1;  break;
    }
    y += 1;//0年元年補正
    static char 和暦[1024];
    sprintf(和暦,"西暦=%d -> %s/%d年/%02d/%02d",ymd,G,y,m,d);
    return  strdup(和暦) ;
}
int main(void){
    printf("明治以前:%s\n",
        西暦和暦変換(1868,1,24));
    
    printf("明治:%s\t%s\n",
        西暦和暦変換(1868,1,25),
        西暦和暦変換(1912,7,29));
    
    printf("大正:%s\t%s\n",
        西暦和暦変換(1912,7,30),
        西暦和暦変換(1926,12,24));
    
    printf("昭和:%s\t%s\n",
        西暦和暦変換(1926,12,25),
        西暦和暦変換(1989,1,7));

    printf("平成:%s\t%s\n",
        西暦和暦変換(1989,1,8),
        西暦和暦変換(2019,4,30));

    printf("令和:%s\t%s\n",
        西暦和暦変換(2019,5,1),
        西暦和暦変換(9999,12,31));
}
./a.out
明治以前:西暦=18680124 -> 未対応/1868年/01/24
明治:西暦=18680125 -> 明治/1年/01/25    西暦=19120729 -> 明治/45年/07/29
大正:西暦=19120730 -> 大正/1年/07/30    西暦=19261224 -> 大正/15年/12/24
昭和:西暦=19261225 -> 昭和/1年/12/25    西暦=19890107 -> 昭和/64年/01/07
平成:西暦=19890108 -> 平成/1年/01/08    西暦=20190430 -> 平成/31年/04/30
令和:西暦=20190501 -> 令和/1年/05/01    西暦=99991231 -> 令和/7981年/12/31

gccの拡張switch-caseを使用しているので
gccとclangではコンパイル出来ますが
Visual Studio ではコンパイルエラーになります。


■和暦を西暦に変換(sscanfで文字列解析する)

#include <stdio.h>
#include <string.h>
//例: 令和/5年/06/03->2023/06/03
char *和暦西暦変換(char *和暦){
    char 元号[32];
    int y,m,d ;    
    int ret = sscanf(和暦,"%[^/]/%d年/%d/%d",//正規表現
        元号,&y,&m,&d);
    if(ret != 4){
        printf("ret=%d,%s:%d:%d:%d\n",ret,元号,y,m,d);
        fflush(NULL);
        return "未対応";
    }
    #define CMP(X,Y)  (strcmp(X,Y)==0)
    if(     CMP(元号,"令和")) {  y += 2019-1; }
    else if(CMP(元号,"平成")) {  y += 1989-1; }
    else if(CMP(元号,"昭和")) {  y += 1926-1; }
    else if(CMP(元号,"大正")) {  y += 1912-1; }
    else if(CMP(元号,"明治")) {  y += 1868-1; }
    else {  return "未対応";}
    
    static char    西暦[255];
    sprintf(西暦,"%s->%04d/%02d/%02d",和暦,y,m,d);
    return 西暦 ;
}
//元号期間
//https://www.jacar.archives.go.jp/apps/help/chronological_table.html
int main(void){
    printf("%s\n",和暦西暦変換("明治/01年/01/25"));
    printf("%s\n",和暦西暦変換("明治/45年/07/30"));
    
    printf("%s\n",和暦西暦変換("大正/01年/07/30"));
    printf("%s\n",和暦西暦変換("大正/15年/12/25"));

    printf("%s\n",和暦西暦変換("昭和/01年/12/25"));
    printf("%s\n",和暦西暦変換("昭和/64年/01/07"));
    
    printf("%s\n",和暦西暦変換("平成/01年/01/08"));
    printf("%s\n",和暦西暦変換("平成/31年/04/30"));
    
    printf("%s\n",和暦西暦変換("令和/01年/05/01"));
    printf("%s\n",和暦西暦変換("令和/07年/02/17"));

    printf("%s\n",和暦西暦変換("平和/99年/01"));
    printf("%s\n",和暦西暦変換("平和/99年/01/01"));
}
./a.out
明治/01年/01/25->1868/01/25
明治/45年/07/30->1912/07/30
大正/01年/07/30->1912/07/30
大正/15年/12/25->1926/12/25
昭和/01年/12/25->1926/12/25
昭和/64年/01/07->1989/01/07
平成/01年/01/08->1989/01/08
平成/31年/04/30->2019/04/30
令和/01年/05/01->2019/05/01
令和/07年/02/17->2025/02/17
ret=3,平和:99:1:-2021400662
未対応
未対応

和暦の文字列から元号を切り出すために
sscanfの正規表現で”%[^/]”を使っています。
これは、”/でない物が続く物”の意味です。