日付の情報を表示する
※ 年月日の区切り文字は「/」「空白」を使用できます。
入力例
- 2023/1/25 … 2023年1月25日
- 0/1/25 …… BC 1年1月25日
- -1/1/25 …… BC 2年1月25日
- 1/25 ……… 現在の年の1月25日
- 20230125 … 2023年の1月25日
- 230125 …… 2023年1月25日(最初の2桁が 0~69 -> 2000~2069年)
- 900125 …… 1990年1月25日(最初の2桁が 70~99 -> 1970~1999年)
- 0125 ……… 現在の年の1月25日
- 25 ………… 現在の年月の25日
注意点
- 西暦4年は閏年として扱います。よって、ユリウス暦1年1月1日は土曜日となります。
ソース
・html<div id="p1822">
<div class="v-flex">
<div class="h-flex">
<div>
<select class="combo js-type">
<option value="g" selected>グレゴリオ暦</option>
<option value="j">ユリウス暦</option>
<option value="jd">ユリウス通日</option>
</select>
</div>
<div>
<input type="tel" class="input js-in" spellcheck="false" placeholder="">
</div>
<div><button class="btn js-exec">実行</button></div>
</div>
<div><small>※ 年月日の区切り文字は「/」「空白」を使用できます。</small></div>
<div>
<table>
<tbody class="js-out">
</tbody>
</table>
</div></div>
</div>
・css
.v-flex { display: flex; flex-direction: column; }
.h-flex { display: flex; flex-direction: row; }
.js-out th, .js-out td {
border-color: transparent;
padding: 0.25rem 0.5rem;
}
.js-out th {
background-color: transparent;
text-align: right;
vertical-align: top;
}
.combo {
padding: 1em 0.5em;
margin-right: 0.5em;
}
.input {
padding: 0 1em;
width: 8em;
font-size: 24px;
}
.btn {
margin-left: 0.5em;
padding: 0.5em 2em;
}
.red {
color: #F00;
}
・javascript
jQuery(($) => {
let ok = true;
main();
function main() {
$('.js-in').on('keydown', onKeyDown);
$('.js-in').on('keyup', check); // キー入力用チェック
$('.js-in').on('change', check); // ペースト用チェック
$('.js-type').on('change', check);
$('.js-exec').click(onClick);
$('.js-out').html(htmlResults(null));
}
function onKeyDown(ev) {
if (ev.keyCode == 13 && ok) {
onClick();
}
}
function check(ev) {
const src = $('.js-in').val();
if (parse(src) === null) {
$('.js-in').addClass('red');
$('.js-exec').prop('disabled', true);
ok = false;
} else {
$('.js-in').removeClass('red');
$('.js-exec').prop('disabled', false);
ok = true;
}
}
function onClick() {
const src = $('.js-in').val();
const out = [];
let data;
const j = parse(src);
if (j === null) {
data = null;
} else {
data = [];
data.push(j.toLocaleString());
let date = jd2gdate(j);
let s = gdate2str(date);
let youbi = jdGetDay(j);
let sLeap = gLeap(date[0]) ? '閏年' : '平年';
data.push(`${s}(${youbi})${sLeap} `);
date = jd2jdate(j);
s = jdate2str(date);
youbi = jdGetDay(j);
sLeap = jLeap(date[0]) ? '閏年' : '平年';
data.push(`${s}(${youbi})${sLeap}`);
const era = modernEraName(j);
if (era.length == 0) {
data.push('----');
} else {
let s = era[0];
for (let i = 1; i < era.length; i++) {
s += `\n(${era[i]})`;
}
data.push(s);
}
}
$('.js-out').html(htmlResults(data));
$('.js-in')[0].select();
}
function htmlResults(data) {
const keys = [
'ユリウス通日',
'西暦(グレゴリオ暦)',
'西暦(ユリウス暦)',
'和暦',
];
const out = [];
for (let i = 0; i < keys.length; i++) {
let value = data === null ? '' : data[i];
value = value.replace(/(\r\n|[\r\n])/g, '<br>');
out.push(`<tr><th>${keys[i]}</th><td>${value}</td></tr>`);
}
return out.join('\n');
}
function parse(s) {
// 文字列の掃除
const t = zen2han(s).toLowerCase().trim();
const valueType = $('.js-type').val();
// ユリウス通日?
if (valueType == 'jd') {
let jd = parseValue(t);
return jd;
}
// 年月日部分の解析
const ymd = parseDate(t);
if (ymd === null) return null;
let [yy, mm, dd] = ymd;
const now = new Date();
if (yy === null) yy = now.getFullYear();
if (mm === null) mm = now.getMonth() + 1;
if (dd === null) dd = now.getDate();
return valueType == 'j' ? jdate2jd([yy, mm, dd]) : gdate2jd([yy, mm, dd]);
}
// 文字列を全角から半角に変換(0x20-0x7E 限定)
function zen2han(s) {
return s.replace(/[\u3000]/g, ' ').replace(/[\uFF01-\uFF5E]/g, (s) => {
return String.fromCharCode(s.charCodeAt(0) - 0xFF01 + 0x21);
});
}
function parseDate(s) {
let yy = null;
let mm = null;
let dd = null;
let m;
s = s.replace(/[ ]/g, '/');
if (m = s.match(/^(-?[0-9]+)\/([0-9]+)\/([0-9]+)$/)) {
// y/m/d
yy = m[1] | 0;
mm = m[2] | 0;
dd = m[3] | 0;
return [yy, mm, dd];
}
if (m = s.match(/^([0-9]+)\/([0-9]+)$/)) {
// m/d
mm = m[1] | 0;
dd = m[2] | 0;
return [yy, mm, dd];
}
if (s.match(/^[0-9]*$/)) {
if (m = s.match(/^([0-9]{4})([0-9]{2})([0-9]{2})$/)) {
// yyyymmdd
yy = m[1] | 0;
mm = m[2] | 0;
dd = m[3] | 0;
}
if (m = s.match(/^([0-9]{2})([0-9]{2})([0-9]{2})$/)) {
// yymmdd
yy = m[1] | 0;
yy += yy >= 70 ? 1900 : 2000;
mm = m[2] | 0;
dd = m[3] | 0;
}
if (m = s.match(/^([0-9]{2})([0-9]{2})$/)) {
// mmdd
mm = m[1] | 0;
dd = m[2] | 0;
}
if (m = s.match(/^[0-9]{1,2}$/)) {
// d
dd = m[0] | 0;
}
return [yy, mm, dd];
}
return null;
}
function parseValue(s) {
let m = s.match(/^[0-9,]*$/);
if (!m) return null;
let t = m[0].replace(/[,]/g, '');
return t == '' ? 0 : t | 0;
}
function modernEraName(jd) {
const ret = [];
const a = [
[2458605, '令和'], // 2019-5-1
[2447535, '平成'], // 1989-1-8
[2424875, '昭和'], // 1926-12-25
[2419614, '大正'], // 1912-7-30
[2403357, '明治'], // 1868-1-25
];
const yy = jd2gdate(jd)[0];
for (let j = 0; j < a.length; j++) {
if (jd >= a[j][0]) {
for (let i = j; i < a.length; i++) {
const [jd0, eraName] = a[i];
const y0 = jd2gdate(jd0)[0];
const y = yy - y0 + 1;
const s = y == 1 ? '元' : (''+y);
ret.push(`${eraName}${s}年`);
}
break;
}
}
return ret
}
// ------------------------------------------------------- 日付関連の関数
// 参考>https://en.wikipedia.org/wiki/Julian_day
// グレゴリオ暦 -> ユリウス通日
function gdate2jd(ymd) {
const [yy, mm, dd] = ymd;
const t = _idiv(mm - 14, 12)
return _idiv(1461 * (yy + 4800 + t), 4)
+ _idiv(367 * (mm - 2 -12 * t), 12)
- _idiv(3 * _idiv(yy + 4900 + t, 100), 4)
+ dd
- 32075;
}
// ユリウス通日 -> グレゴリオ暦
function jd2gdate(jd) {
const j = 1401,
B = 274277,
C = -38,
t = _idiv(4 * jd + B, 146097),
t2 = _idiv(t * 3, 4),
f = jd + j + t2 + C;
return _f2date(f);
}
// グレゴリオ暦 -> 文字列
function gdate2str(gdate) {
let [yy, mm, dd] = gdate;
let bc = '';
if (yy <= 0) {
bc = 'BC';
yy = -yy + 1;
}
return `${bc}${yy}年 ${mm}月 ${dd}日`;
}
// ユリウス暦 -> ユリウス通日
function jdate2jd(ymd) {
const [yy, mm, dd] = ymd,
v1 = 367 * yy,
t = _idiv(mm - 9, 7),
v2 = _idiv(7 * (yy + 5001 + t), 4),
v3 = _idiv(275 * mm, 9);
return v1 - v2 + v3 + dd + 1729777;
}
// ユリウス通日 -> ユリウス暦
function jd2jdate(jd) {
return _f2date(1401 + jd);
}
// ユリウス暦 -> 文字列
function jdate2str(gdate) {
let [yy, mm, dd] = gdate;
let bc = '';
if (yy <= 0) {
bc = 'BC';
yy = -yy + 1;
}
return `${bc}${yy}年 ${mm}月 ${dd}日`;
}
// ユリウス通日 -> 曜日(日曜=0)
function jdGetDay(j) {
return ['日', '月', '火', '水', '木', '金', '土'][(j+1) % 7];
}
// 閏年のチェック(ユリウス暦)
function jLeap(y) {
return (y % 4) == 0;
}
// 閏年のチェック(グレゴリオ暦)
function gLeap(y) {
if (y % 4) return false;
if (y % 100) return true;
return (y % 400) == 0;
}
// 整数除算(小数点以下切り捨て)
// 3.1 / 3 = 3
// 3.0 / 3 = 3
// 2.9 / 3 = 2
// -2.9 / 3 = -2
// -3.0 / 3 = -3
// -3.1 / 3 = -3
function _idiv(a, b) {
return a*b >= 0 ? Math.floor(a / b) : -Math.floor(-a / b);
}
// 補助関数
function _f2date(f) {
const y = 4716,
m = 2,
n = 12,
r = 4,
p = 1461,
v = 3,
u = 5,
s = 153,
w = 2,
e = r * f + v,
g = _idiv(e % p, r),
h = u * g + w,
dd = 1 + _idiv(h % s, u),
mm = 1 + ((_idiv(h, s) + m) % n),
yy = _idiv(e, p) - y + _idiv(n + m - mm, n);
return [yy, mm, dd];
}
});