
■西暦を和暦(元号)に変換
static void 西暦和暦変換(char *西暦書式,char *和暦書式){
uint32_t year;
uint32_t mon;
uint32_t day;
int ret = sscanf(西暦書式,"%04d/%02d/%02d",
&year,
&mon,
&day
);
if(ret != 3)
assert(0);
/*
元号期間
明治 1868/09/08 〜 1912/07/29
大正 1912/07/30 〜 1926/12/24
昭和 1926/12/25 〜 1989/01/07
平成 1989/01/08 〜 2019/04/30
令和 2019/05/01 〜
*/
// このマクロは FORM+"/%d年/%02d/%02d"で文字列連結します。
#define G(FORM,START) \
sprintf(和暦書式,FORM "/%d年/%02d/%02d",year-(START)+1,mon,day)
uint32_t ymd = year*10000 + mon*100 +day;
switch(ymd){
default: G("明治以前",1); break;
case 18680908 ... 19120729: G("明治",1868); break;
case 19120730 ... 19261224: G("大正",1912); break;
case 19261225 ... 19890107: G("昭和",1926); break;
case 19890108 ... 20190430: G("平成",1989); break;
case 20190501 ... INT_MAX: G("令和",2019); break;
}
}
例: 2023/06/03 ->令和/5年/06/03
GNUの拡張機能を使用すると
case 18680908 … 19120729:
のように、case 文の範囲指定が出来ます。
gccとclangで使用できますが、
Visual Studio ではコンパイルエラーになります。
■和暦(元号)を西暦に変換
static void 和暦西暦変換(char *和暦書式,char *西暦書式){
char 元号[32];
uint32_t year;
uint32_t mon;
uint32_t day;
int ret = sscanf(和暦書式,"%[^/]/%d年/%d/%d",
元号,
&year,
&mon,
&day
);
if(ret != 4){
fprintf(stderr,"ret=%d,%s:%d:%d:%d\n",ret,元号,year,mon,day);
fflush(NULL);
assert(0);
}
#define CMP(X,Y) (strcmp(X,Y)==0)
if( CMP(元号,"令和")) { year += 2019-1; }
else if(CMP(元号,"平成")) { year += 1989-1; }
else if(CMP(元号,"昭和")) { year += 1926-1; }
else if(CMP(元号,"大正")) { year += 1912-1; }
else if(CMP(元号,"明治")) { year += 1868-1; }
else { year += 0; }
sprintf(西暦書式,"%04d/%02d/%02d",year,mon,day);
}
例: 令和/5年/06/03->2023/06/03
■まとめ(コンパイル可能)
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
//例: 2023/06/03 ->令和/5年/06/03
static void 西暦和暦変換(char *西暦書式,char *和暦書式){
uint32_t year;
uint32_t mon;
uint32_t day;
int ret = sscanf(西暦書式,"%04d/%02d/%02d",
&year,
&mon,
&day
);
if(ret != 3)
assert(0);
/*
元号期間
明治 1868/09/08 〜 1912/07/29
大正 1912/07/30 〜 1926/12/24
昭和 1926/12/25 〜 1989/01/07
平成 1989/01/08 〜 2019/04/30
令和 2019/05/01 〜
*/
// このマクロは FORM+"/%d年/%02d/%02d"で文字列連結します。
#define G(FORM,START) \
sprintf(和暦書式,FORM "/%d年/%02d/%02d",year-(START)+1,mon,day)
uint32_t ymd = year*10000 + mon*100 +day;
switch(ymd){
default: G("明治以前",1); break;
case 18680908 ... 19120729: G("明治",1868); break;
case 19120730 ... 19261224: G("大正",1912); break;
case 19261225 ... 19890107: G("昭和",1926); break;
case 19890108 ... 20190430: G("平成",1989); break;
case 20190501 ... INT_MAX: G("令和",2019); break;
}
}
//例: 令和/5年/06/03->2023/06/03
static void 和暦西暦変換(char *和暦書式,char *西暦書式){
char 元号[32];
uint32_t year;
uint32_t mon;
uint32_t day;
int ret = sscanf(和暦書式,"%[^/]/%d年/%d/%d",
元号,
&year,
&mon,
&day
);
if(ret != 4){
fprintf(stderr,"ret=%d,%s:%d:%d:%d\n",ret,元号,year,mon,day);
fflush(NULL);
assert(0);
}
#define CMP(X,Y) (strcmp(X,Y)==0)
if( CMP(元号,"令和")) { year += 2019-1; }
else if(CMP(元号,"平成")) { year += 1989-1; }
else if(CMP(元号,"昭和")) { year += 1926-1; }
else if(CMP(元号,"大正")) { year += 1912-1; }
else if(CMP(元号,"明治")) { year += 1868-1; }
else { year += 0; }
sprintf(西暦書式,"%04d/%02d/%02d",year,mon,day);
}
int main(void){
uint32_t mdays[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
for(uint32_t ymd = 18670908 ; ymd < 21001231;ymd++){
uint32_t year = (ymd/10000) ;
uint32_t mon = (ymd/100)%100;
uint32_t day = (ymd)%100;
if(mon < 1 || 12 < mon)
continue ;
if(day < 1 || mdays[mon] < day)//閏年無視
continue ;
//西暦1⇒和暦2⇒西暦3の順番で変換する
char 西暦1[256];
char 和暦2[256];
char 西暦3[256];
sprintf(西暦1,"%04d/%02d/%02d",year,mon,day);
printf("%s->",西暦1);
西暦和暦変換(西暦1,和暦2);
printf("%s->",和暦2);
和暦西暦変換(和暦2,西暦3);
printf("%s\n",西暦3);
//元に戻らなければ変換失敗
if(strcmp(西暦1,西暦3) != 0){
fflush(NULL);
assert(0);
}
}
}
