和暦 | 元号Y年M月D日 W曜日 |
満年齢 | N歳 |
干支 | 干支(えと) |
星座 | 星座(せいざ) |
閏年 | |
ラッキーナンバー |
アルゴリズムの解説
- 年齢
- 和暦
- 干支
- 星座
- 閏年
- ラッキーナンバー
「○歳○ヶ月と○日」まで求めました。
年月…現在年月から生まれ年月を引きます。まだ現在年の誕生日を迎えていない場合、1歳減らし、11ヶ月足します。
日…現在日から生まれ日を引きます。差がマイナスになった場合、1か月減らし、①現在年の誕生日から当月末までの日数と②現在日付の月初日から当日までの日数を算出し、合計します。さらに、月ごとに日数は異なるため、現在日・生年月日ともに月末日であれば、差は0日として1か月足します。
※うるう日を考慮していないため、うるう日前後の日数カウントが不正確です。
/// <summary>
/// 年齢
/// </summary>
/// <params name="birthday">生年月日</params>
/// <returns>年齢</returns>
function getAge(birthday) {
// 今日
let today = new Date(document.getElementById('today').value);
// 今年の誕生日
let thisBirthday = new Date(today.getFullYear(), birthday.getMonth(), birthday.getDate());
// 年月日の差分
let y = today.getFullYear() - birthday.getFullYear();
let m = today.getMonth() - birthday.getMonth();
let d = today.getDate() - birthday.getDate();
// 今年の誕生日前
if (today < thisBirthday) {
y--;
m += 11;
}
if (d < 0) {
m--;
let endDay = new Date(thisBirthday.getFullYear(), thisBirthday.getMonth() + 1, 0);
d = endDay.getDate() - thisBirthday.getDate();
d += today.getDate();
// 月末日
if (isMonthEndDay(thisBirthday) == true) {
if (isMonthEndDay(today) == true) {
m++;
d = 0;
}
}
}
// 単位
y += '歳';
m += 'ヶ月';
d += '日';
// 今日が誕生日
let happyBirthday = '';
if (today.toDateString() == thisBirthday.toDateString()) {
happyBirthday = '🎂';
}
return y + m + d + happyBirthday;
}
/// <summary>
/// 月末日判定
/// </summary>
/// <params name="date">日付</params>
/// <returns>真偽値</returns>
function isMonthEndDay(date) {
let endDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
if (endDay.getDate() == date.getDate()) {
return true;
}
return false;
}
日付のプロパティに、和暦フォーマット「元号Y年M月D日 W曜日」があります。
和暦 = 日付
.toLocaleDateString('ja-JP-u-ca-japanese',
{dateStyle: 'full'}
);
ちなみに、「yyyy-MM-dd」形式の日付フォーマットは、下記のように取得します。
日付 = new Date()
.toLocaleDateString('sv-SE');
年を12で割った余りを、十二支の配列に当てはめます。
/// <summary>
/// 干支
/// </summary>
const etos = [
'🐵 申(さる)',
'🐔 酉(とり・にわとり)',
'🐶 戌(いぬ)',
'🐗 亥(い・いのしし)',
'🐭 子(ね・ねずみ)',
'🐮 丑(うし)',
'🐯 寅(とら)',
'🐰 卯(う・うさぎ)',
'🐉 辰(たつ・りゅう)',
'🐍 巳(み・へび)',
'🐴 午(うま)',
'🐏 未(ひつじ)'
];
干支 = etos[年 % 12];
アルゴリズムの解説
干支を求める計算方法は何通りかあります。
- 計算式A:①西暦÷12の余りを求める。②9を足す。③解が4以上なら12を引く。
- 計算式B:①西暦÷12の余りを求める。②3を引く。③解が0以下なら12を足す。
まず最初に「西暦÷12の余り」を求めるところはどの計算式でも共通です。無駄が少ないのは計算式Bでしょうか。計算式Aの亜種として、8を足して11を引く、と解説しているサイトもあります(同じことですね)。
順番 | 干支 | 西暦÷12の余 | 計算式A | 計算式B |
---|---|---|---|---|
1 | 子 | 4 | 4 + 9 = 13 13 – 12 = 1 | 4 – 3 = 1 |
2 | 丑 | 5 | 5 + 9 = 14 14 – 12 = 2 | 5 – 3 = 2 |
3 | 寅 | 6 | 6 + 9 = 15 15 – 12 = 3 | 6 – 3 = 3 |
4 | 卯 | 7 | 7 + 9 = 16 16 – 12 = 4 | 7 – 3 = 4 |
5 | 辰 | 8 | 8 + 9 = 17 17 – 12 = 5 | 8 – 3 = 5 |
6 | 巳 | 9 | 9 + 9 = 18 18 – 12 = 6 | 9 – 3 = 6 |
7 | 馬 | 10 | 10 + 9 = 19 19 – 12 = 7 | 10 – 3 = 7 |
8 | 未 | 11 | 11 + 9 = 20 20 – 12 = 8 | 11 – 3 = 8 |
9 | 申 | 0 | 0 + 9 = 9 | 0 – 3 = -3 -3 + 12 = 9 |
10 | 酉 | 1 | 1 + 9 = 10 | 1 – 3 = -2 -2 + 12 = 10 |
11 | 戌 | 2 | 2 + 9 = 11 | 2 – 3 = -1 -1 + 12 = 10 |
12 | 亥 | 3 | 3 + 9 = 12 | 3 – 3 = 0 0 + 12 = 12 |
このように、神様のところに到着した順番通りに十二支を取得しようとすると、「西暦÷12の余り」の数字をシフトするひと手間が生じてしまいます。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 0 | 1 | 2 | 3 |
🐭 | 🐮 | 🐯 | 🐰 | 🐉 | 🐍 | 🐎 | 🐏 | 🐵 | 🐔 | 🐶 | 🐗 |
最初から「西暦÷12の余り」と順番が一致するような形の配列を用意しておけば、無駄な計算を省くことができます。
全体を4つずらし、申(さる)を先頭に持ってきます。インデックスは0始まりになります。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|
🐵 | 🐔 | 🐶 | 🐗 | 🐭 | 🐮 | 🐯 | 🐰 | 🐉 | 🐍 | 🐎 | 🐏 |
曜日のインデックスを取得する関数などと同様の対処法ですね。
生年月日が、どの星座の期間(開始月日、終了月日)に該当するかを判定します。
JavaScriptの日付.getMonth()関数は、月の数字名ではなく、インデックスを返すので、+1する必要がある点に注意が必要です。月名を数字で呼ぶ国は日本だけです。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|
1月 | 2月 | 3月 | 4月 | 5月 | 6月 | 7月 | 8月 | 9月 | 10月 | 11月 | 12月 |
/// <summary>
/// 星座
/// </summary>
/// <params name="birthday">生年月日</params>
/// <returns>星座</returns>
function getZodiac(birthday) {
const zodiacs = [
['♓ 魚座(うおざ)', 2, 19, 3, 20],
['♈ 牡羊座(おひつじざ)', 3, 21, 4, 19],
['♉ 牡牛座(おうしざ)', 4, 20, 5, 20],
['♊ 双子座(ふたござ)', 5, 21, 6, 21],
['♋ 蟹座(かにざ)', 6, 22, 7, 22],
['♌ 獅子座(ししざ)', 7, 23, 8, 22],
['♍ 乙女座(おとめざ)', 8, 23, 9, 22],
['♎ 天秤座(てんびんざ)', 9, 23, 10, 23],
['♏ 蠍座(さそりざ)', 10, 24, 11, 22],
['♐ 射手座(いてざ)', 11, 23, 12, 21],
['♑ 山羊座(やぎざ)', 12, 22, 1, 19],
['♒ 水瓶座(みずがめざ)', 1, 20, 2, 18],
];
let zodiac = '';
for (let i = 0; i < 12; i++) {
var m = birthday.getMonth() + 1;
var d = birthday.getDate();
if (m == zodiacs[i][1]) {
if (d >= zodiacs[i][2]) {
zodiac = zodiacs[i][0];
}
}
if (m == zodiacs[i][3]) {
if (d <= zodiacs[i][4]) {
zodiac = zodiacs[i][0];
}
}
}
return zodiac;
}
論理演算子が文字化けするため、if文を入れ子にしています。※詳細は「閏年の判定アルゴリズム」を参照
/// <summary>
/// 閏年
/// </summary>
/// <params name="year">西暦</params>
/// <returns>真偽値</returns>
function isLeapYear(year) {
if (year % 400 == 0) {
return true;
}
if (year % 100 != 0) {
if (year % 4 == 0) {
return true;
}
}
return false;
}
ラッキーナンバーとは、数秘術による誕生日占いです。生年月日を数字に分解し、1桁になるまで足し算を繰り返します。(例:「2019年1月31日」→「20190131」→「2+0+1+9+0+1+3+1」→「17」→「1+7」→「8」)
2桁の数字がぞろ目になった場合は、ぞろ目がラッキーナンバーになります。
/// <summary>
/// 1桁になるまで、各桁の数字の足し算を繰り返す
/// </summary>
/// <params name="num">数値文字列</params>
/// <returns>1桁の数字</returns>
function getLuckyNumber(num) {
var str = String(num).replace(/[^0-9]/g, '');
do {
var arr = str.split('');
var sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += Number(arr[i]);
}
str = String(sum);
// ぞろ目判定
if (str.length == 2) {
if (str[0] == str[1]) {
break;
}
}
} while(str.length > 1);
return str;
}
「数字を分解し、1桁になるまで、各位の数字を足し算する」というロジックは、チェックデジットのアルゴリズムなどにも応用できます。
コメント