小ネタ。
PHPで西暦から十二支を出す必要があったので、ついでに十干十二支(干支=えと)を出す関数を作ってみた。
西暦→干支
getEto.php
function getEto(int $yyyy = NULL, bool $with_jikkan = TRUE) {
// yyyyに西暦を入れるとその年の干支(十干十二支)を返す
// yyyyが空のときは今年の干支
// 第2引数を0にすると十二支のみ返す
$yyyy = $yyyy ?: date("Y");
if ($yyyy > 0) {
$jikkan = [
'庚',
'辛',
'壬',
'癸',
'甲',
'乙',
'丙',
'丁',
'戊',
'己',
];
$juunishi = [
'申',
'酉',
'戌',
'亥',
'子',
'丑',
'寅',
'卯',
'辰',
'巳',
'午',
'未',
];
return ($with_jikkan ? $jikkan[$yyyy % 10] : '') . $juunishi[$yyyy % 12];
}
return NULL;
}
西暦が10で割り切れる年は「庚(かのえ)」、12で割り切れる年は「申(さる)」なので、そこから算出している。配列が「甲(きのえ)」や「子(ね)」から始まってないのはこのため。
第2引数を0(やfalsyな値)にすると十干ナシで十二支だけ返す。
まあこれは処理が簡単。
干支→西暦
getYearFromEto.php
function getYearFromEto(string $eto, int $yyyy = NULL) {
// yyyy年以降でeto(十干十二支)に当てはまる年を出す
// yyyyが空の場合は今年以降で算出
// 存在しない干支を入力した場合はNULLを返す
$yyyy = $yyyy ?: date("Y");
if ($yyyy > 0) {
$jikkan_r = [
'庚' => 0,
'辛' => 1,
'壬' => 2,
'癸' => 3,
'甲' => 4,
'乙' => 5,
'丙' => 6,
'丁' => 7,
'戊' => 8,
'己' => 9,
];
$juunishi_r = [
'申' => 0,
'酉' => 1,
'戌' => 2,
'亥' => 3,
'子' => 4,
'丑' => 5,
'寅' => 6,
'卯' => 7,
'辰' => 8,
'巳' => 9,
'午' => 10,
'未' => 11,
];
$ji = $jikkan_r[mb_substr($eto, 0, 1)] ?? FALSE;
$ju = $juunishi_r[mb_substr($eto, 1, 1)] ?? FALSE;
if (($ji || $ji === 0) && ($ju || $ju === 0) && (($ji + $ju) % 2 === 0)) {
for ($i = 0; 1; $i++) {
$yi = $yyyy + $i;
if (($yi % 10 === $ji) && ($yi % 12 === $ju)) {return $yi;}
}
}
}
return NULL;
}
第1引数は干支(十二支でなく十干十二支)、第2引数には西暦を入れると、その年以降で入れた干支に当てはまる西暦を返す。第2引数を省略すると今年以降から探す。
手順としては西暦→干支より複雑で、
- 干支を十干と十二支に分割
- 十干と十二支に当てはまる剰余を出す
- 西暦に1ずつ足していき、10の剰余と12の剰余の両方が一致する年を出力
というやや力技。もう少しスマートなやり方があるかもしれない。
if
の条件の1つめと2つめは干支にない文字を入れた場合に無視する(NULL
を返す)ためだが「余りゼロ」もTRUE
にしないといけないためちょっと手間がかかっている。3つめは例えば「甲丑」という干支は存在しない(十干の偶数番目は必ず十二支の偶数番目と結合する。奇数番目も同様)ので、それを回避するためのもの。2つの剰余の和が偶数なら偶数&偶数か奇数&奇数しかないので。XOR
を使うより簡単なんじゃあないかなと思った。
これがあると例えば「辛亥革命って何年だっけ?」というときに
echo getYearFromEto('辛亥', 1900); //1911
みたいなことができる。もっとも60年ごとに同じ干支が回ってくるので「だいたいこのあたりの年」がわかってないと使えないが…。