39 lines
2.4 KiB
JavaScript
39 lines
2.4 KiB
JavaScript
/* Chinese calendar conversion supplied by the browser's ICU calendar, offline. */
|
|
(function(root){
|
|
'use strict';
|
|
const fmt=new Intl.DateTimeFormat('en-u-ca-chinese',{year:'numeric',month:'numeric',day:'numeric',timeZone:'Asia/Shanghai'});
|
|
const cache=new Map();
|
|
function solarDate(value){
|
|
if(!/^\d{4}-\d{2}-\d{2}$/.test(value))throw Error('日期请填写 YYYY-MM-DD');
|
|
const d=new Date(value+'T12:00:00Z');
|
|
if(!Number.isFinite(+d)||d.toISOString().slice(0,10)!==value)throw Error('日期不存在');
|
|
return d;
|
|
}
|
|
function lunar(value){
|
|
const d=solarDate(value),year=d.getUTCFullYear();
|
|
if(year<1901||year>2100)throw Error('自动换算支持 1901—2100 年;更早日期可填写公历并在备注保留原记载');
|
|
if(fmt.resolvedOptions().calendar!=='chinese')throw Error('当前浏览器不支持农历换算');
|
|
const parts=Object.fromEntries(fmt.formatToParts(d).map(p=>[p.type,p.value]));
|
|
return {year:Number(parts.relatedYear),month:parseInt(parts.month,10),day:Number(parts.day),leap:parts.month.includes('bis')};
|
|
}
|
|
function solar(value,leap=false){
|
|
if(!/^\d{4}-\d{2}-\d{2}$/.test(value))throw Error('农历请填写 YYYY-MM-DD,例如 2023-02-01');
|
|
const [year,month,day]=value.split('-').map(Number);
|
|
if(year<1901||year>2099)throw Error('农历输入支持 1901—2099 年');
|
|
if(month<1||month>12||day<1||day>30)throw Error('农历日期不存在');
|
|
if(!cache.has(year)){
|
|
const days=new Map(),start=Date.UTC(year,0,1,12),end=Date.UTC(year+1,2,1,12);
|
|
for(let t=start;t<end;t+=86400000){const iso=new Date(t).toISOString().slice(0,10),l=lunar(iso);if(l.year===year)days.set(`${l.month}-${l.day}-${l.leap}`,iso);}
|
|
if(cache.size>8)cache.clear();cache.set(year,days);
|
|
}
|
|
const result=cache.get(year).get(`${month}-${day}-${!!leap}`);
|
|
if(!result)throw Error('该农历日期或闰月不存在');
|
|
return result;
|
|
}
|
|
const pad=n=>String(n).padStart(2,'0');
|
|
function iso(l){return `${l.year}-${pad(l.month)}-${pad(l.day)}`;}
|
|
function describe(value){if(!value)return '';try{const l=lunar(value);return `${value} · 农历 ${l.year}年${l.leap?'闰':''}${l.month}月${l.day}日`;}catch{return value+'(公历)';}}
|
|
root.ZhaoCalendar={solarDate,lunar,solar,iso,describe};
|
|
if(typeof module!=='undefined')module.exports=root.ZhaoCalendar;
|
|
})(typeof window==='undefined'?globalThis:window);
|