Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
lmj01 committed Nov 11, 2023
1 parent b82c8da commit 0c32a98
Show file tree
Hide file tree
Showing 7 changed files with 345 additions and 5 deletions.
23 changes: 23 additions & 0 deletions articles/2023/chineseCalendar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 天文历法


## 农历

- [农历的编算和颁行国家标准](https://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=E107EA4DE9725EDF819F33C60A44B296)

农历的特征
- 农历不是阴历,而是阴阳合历
- 农历不是数学历法--纯数学计算的历法,而是天文历法--需要使用天文观测数据进行计算
- 定气,二十四节气,是彻底的阳历,代表了地球上的太阳直射点。直射点在北回归线的时候叫做夏至,直射点在南回归线时叫做冬至。需要使用天文观测仪器来测量出天文数据,再去计算出二十四节气的时刻
- 定朔shuo--new moon,月球和太阳的地心视黄经相等的时刻
- 规定朔日是一个月的第一天,即初一,月份划分就是这样来的

农历的编算和颁行国家标准中4节描述了规则


- [A class framework for Computeational Astronomy](http://www.naughter.com/aa.html)
- [html - The Total Solar Eclipse of 2006 March 29](https://umbra.nascom.nasa.gov/eclipse/20060329/rp.html)
- [pdf - The Total Solar Eclipse of 2006 March 29 ](https://umbra.nascom.nasa.gov/eclipse/20060329/TP2004212762.pdf)
- [github](https://github.com/harrysummer/AA)
- [好奇关于农历算法的实现](https://github.com/harrysummer/AA/blob/master/aaplus/AAChineseCalendar.h)

235 changes: 235 additions & 0 deletions html/calendar.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
/**
* 源自https://juejin.cn/post/6941022036919582728
* 可参数python的zhDate库处理的农历数据
* https://github.com/CutePandaSh/zhdate/blob/master/zhdate/constants.py
*/

/* 源数据说明:
* lunarYear数据来自香港天文台提供的源数据反向推导得出,其中201项数据分别对应1900-2100年。
* 示例: 2021年 -- 0x06aa0
* ╭-------┰-------┰-------┰-------┰--------╮
* ┆ 0000 ┆ 0110 ┆ 1010 ┆ 1010 ┆ 0000 ┆
* ┠-------╊-------╊-------╊-------╊--------┨
* ┆ 20-17 ┆ 16-12 ┆ 12-9 ┆ 8-5 ┆ 4-1 ┆
* ╰-------┸-------┸-------┸-------┸--------╯
* 1-4: 表示当年有无闰年,有的话,为闰月的月份,没有的话,为0。 2021年无闰月
* 5-16:为除了闰月外的正常月份是大月还是小月,1为30天,0为29天。从1月到12月对应的是第16位到第5位,2021年各月天数[29,30,30,29,30,29,30,29,30,29,30,29]
* 17-20: 表示闰月是大月还是小月,仅当存在闰月的情况下有意义。(0/1,即闰大/小月)
*/

const lunarYears = [
0x04bd8,
// 1901-2000
0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,0x04ae0,
0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,0x04970,
0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,0x06566,
0x0d4a0,0x0ea50,0x16a95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,0x0d4a0,
0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,0x06ca0,
0x0b550,0x15355,0x04da0,0x0a5b0,0x14573,0x052b0,0x0a9a8,0x0e950,0x06aa0,0x0aea6,
0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,0x096d0,
0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b6a0,0x195a6,0x095b0,
0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,0x04af5,
0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x05ac0,0x0ab60,0x096d5,0x092e0,0x0c960,
// 2001-2100
0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,0x0a950,
0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,0x07954,
0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,0x05aa0,
0x076a3,0x096d0,0x04afb,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,0x0b5a0,
0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0,0x14b63,
0x09370,0x049f8,0x04970,0x064b0,0x168a6,0x0ea50,0x06b20,0x1a6c4,0x0aae0,0x092e0,
0x0d2e3,0x0c960,0x0d557,0x0d4a0,0x0da50,0x05d55,0x056a0,0x0a6d0,0x055d4,0x052d0,
0x0a9b8,0x0a950,0x0b4a0,0x0b6a6,0x0ad50,0x055a0,0x0aba4,0x0a5b0,0x052b0,0x0b273,
0x06930,0x07337,0x06aa0,0x0ad50,0x14b55,0x04b60,0x0a570,0x054e4,0x0d160,0x0e968,
0x0d520,0x0daa0,0x16aa6,0x056d0,0x04ae0,0x0a9d4,0x0a2d0,0x0d150,0x0f252,0x0d520
]

// ['月','正','一','二','三','四','五','六','七','八','九','十','冬','腊'];
const ChinaMonths = ["\u6708","\u6b63","\u4e8c","\u4e09","\u56db","\u4e94","\u516d","\u4e03","\u516b","\u4e5d","\u5341","\u51ac","\u814a"]
// ['日','一','二','三','四','五','六','七','八','九','十']
const ChinaDay = ["\u65e5","\u4e00","\u4e8c","\u4e09","\u56db","\u4e94","\u516d","\u4e03","\u516b","\u4e5d","\u5341"]
// ['初','十','廿','卅','闰']
const ChinaElement = ["\u521d","\u5341","\u5eff","\u5345", "\u95f0"]

// 农历日中文显示,参数日期day
export const toChinaDay = function(day) {
let str = '';
switch(day) {
case 10:
str = '\u521d\u5341';break; // "初十"
case 20:
str = '\u5eff\u5341';break; // "廿十"
case 30:
str = '\u5345\u5341';break; // "卅十"
default:
str = ChinaElement[Math.floor(day/10)] + ChinaDay[day%10];
}
return str
}
// 农历月初一中文月显示(如农历二月初一 -> 二月,农历闰四月初一 ->闰四月)
export const toChinaMonth = function(month, isleap) {
isleap = isleap || false;
return isleap ? (ChinaElement[4] + ChinaMonths[month] + ChinaMonths[0]) : (ChinaMonths[month] + ChinaMonths[0]);
}

const nowInfo = function() {
let now = new Date();
return {
y: now.getFullYear(),
m: now.getMonth()+1,
d: now.getDate()
};
}
// 某年农历闰月月份
export const leapMonth = function(year) {
year = year || nowInfo().y;
return lunarYears[year - 1900] & 0xF;
}
// 某年农历闰月天数
export const leapDays = function(year) {
year = year || nowInfo().y;
if(leapMonth(year)) {
return (lunarYears[year-1900] & 0x10000) ? 30 : 29;
}
return 0;
}

// 某年份农历各月天数
export const lunarMonthDays = function(year) {
year = year || nowInfo().y;
let lunarYear = lunarYears[year - 1900];
let monthDays = [];
for(let i = 4; i< 16; i++) {
let monthDay = (lunarYear >> i & 0x1) ? 30 :29;
monthDays.push(monthDay);
}
monthDays.reverse();
// 添加闰月
let leapM = leapMonth(year);
if(leapM) monthDays.splice(leapM, 0 , leapDays(year));
return monthDays;
}
// 某年农历天数
const lunarYearDays = function(year) {
year = year || nowInfo().y;
let num = 0;
lunarMonthDays(year).forEach(item => {
num += item;
});
return num;
}

export const solarToLunar = function(y,m,d) {
if(y < 1901 || y > 2100) return -1;
let date;
if(!y) {
date = new Date();
} else {
date = new Date(y,m-1,d);
}

// 参照日期 1901-02-19 正月初一
let offset = (Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - Date.UTC(1901,1,19))/86400000;
let temp = 0, i;
for(i = 1901; i < 2101 && offset > 0; i++ ){
temp = lunarYearDays(i);
offset -= temp;
}
if(offset < 0) {
offset += temp;
i--;
}

// 农历年、月、日
let isLeap = false, j;
let monthDays = lunarMonthDays(i);
let leapM = leapMonth(i);

if(offset > 0) {
for(j = 0; j < monthDays.length && offset > 0; j++) {
temp = monthDays[j];
offset -=temp;
}
if(offset == 0) {
j++;
}
if(offset < 0) {
offset += temp;
}
} else {
// 补偿公历1901年2月的农历信息
if(offset == -23) {
return {
lunarY: i,
lunarM: 12,
lunarD: 8,
isLeap: false
}
}
}

// 矫正闰年月
if(leapM) {
if(j == leapM + 1) {
isLeap = true
}
if(j >= leapM + 1) {
j--
}
}

return {
lunarY: i,
lunarM: j,
lunarD: ++offset,
isLeap: isLeap
}
}

// 公历月表推算表中各农历日
const solarToLunarMonthTable = function(firstDay, days) {
let firstMoonDay = solarToLunar(firstDay.years, firstDay.months + 1, firstDay.date);
let curY = firstMoonDay.lunarY,
curM = firstMoonDay.lunarM,
curD = firstMoonDay.lunarD,
leap = firstMoonDay.isLeap;

// 判断当前是否为闰年闰月
let leap_m = leapMonth(curY);
let isleap = false;
if(leap_m === curM) {
isleap = true;
}

// 获取当前年份各农历月天数, 首先获取当前月在当前农历年份中的天数
let moonMonthDays = lunarMonthDays(curY);
let moonMonthTotal;
if(moonMonthDays.length === 12 || (moonMonthDays.length > 12 && curM < leap_m) || (moonMonthDays.length > 12 && curM === leap_m && !leap)) {
moonMonthTotal = moonMonthDays[curM - 1];
} else {
moonMonthTotal = moonMonthDays[curM];
}

for(let i = 0, len = days.length; i < len; i++) {
if(moonMonthTotal < curD) {
if(!isleap || leap) {
curM++;
}
curD = 1;
if(curM > 12) {
curY++;
curM = 1;
curD = 1;
moonMonthTotal = lunarMonthDays(curY)[0];
}
if(isleap) leap = !leap;
}

days[i].lunarY = curY;
days[i].lunarM = curM;
days[i].lunarD = curD === 1 ? toChinaMonth(curM, leap) : toChinaDay(curD);
days[i].isLeap = leap;
curD++;
}
return days;
}

85 changes: 82 additions & 3 deletions html/personal.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,92 @@ <h1>个人信息</h1>
<div>
<h4 id="section1">生日</h4>
<div>
<label>幺儿生日<input id="input20220828" type="text" disabled value="2022-08-28"></label>
<div id="div19960124">
<label>老婆生日<input id="input19960124" type="text" disabled value="1996-01-24"></label>
</div>
<div id="div20220828">
<label>幺儿生日<input id="input20220828" type="text" disabled value="2022-08-28"></label>
</div>
<div id="div19870903">
<label>自己生日<input id="input19870903" type="text" disabled value="1987-10-25"></label>
</div>
<div id="divOtherBirth">
<label>别人生日<input id="inputOtherBirth" type="text" placeholder="请输入年-月-日格式"></label>
<div id="divOtherInfo"></div>
</div>
</div>
</div>
<div></div>
<script type="module">
const birthdayLiduruo = document.getElementById('input20220828').value
console.log('', )
import { timeDay, timeYear, timeMonth } from "https://cdn.skypack.dev/d3-time@3";
import { solarToLunar, toChinaMonth, toChinaDay, lunarMonthDays, leapMonth } from './calendar.mjs';
const div19960124 = document.getElementById('div19960124');
const div20220828 = document.getElementById('div20220828');
const div19870903 = document.getElementById('div19870903');
const birthDarling = new Date(document.getElementById('input19960124').value);
const birthSon = new Date(document.getElementById('input20220828').value);
const birthSelf = new Date(document.getElementById('input19870903').value);
const today = new Date();

function computeTimeDate(el, date, birthDayUseChineseCalendar = true) {
if (['divOtherInfo'].includes(el.id)) {
el.replaceChildren();
}
// 出生农历年
const chineseCalendar = solarToLunar(date.getFullYear(), date.getMonth()+1, date.getDate());
const infoChineseCalendar = `农历${chineseCalendar.lunarY}${toChinaMonth(chineseCalendar.lunarM, chineseCalendar.isLeap)}${toChinaDay(chineseCalendar.lunarD)}`;
let p = document.createElement('p');
p.classList.add('ms-3');
const totalYear = timeYear.count(date, today);
const totalMonth = timeMonth.count(date, today);
p.innerText = `出生于${infoChineseCalendar}、距今已有${totalYear}${totalMonth - 12 * totalYear}月、成长天数为${timeDay.count(date, today)}`;
el.appendChild(p);
p = p.cloneNode(true);
if (birthDayUseChineseCalendar) {
const thisChineseCalendar = solarToLunar(today.getFullYear(), today.getMonth()+1, today.getDate());
const thisYear = today.getFullYear();
const thisMonth = chineseCalendar.lunarM;
const thisDate = chineseCalendar.lunarD;
const thisYearMonths = lunarMonthDays(thisYear);

const dayList = [];
let begin = thisChineseCalendar.lunarM + 1, end = chineseCalendar.lunarM;
// 这个月的天数
dayList.push(thisYearMonths[begin] - thisChineseCalendar.lunarD);
if (thisChineseCalendar.lunarM < chineseCalendar.lunarM) {
// 今年未过生
// 整月的天数
for (let i=begin; i < end; i++) {
dayList.push(thisYearMonths[i]);
}
} else {
// 今年已经过了生日
dayList.push(thisYearMonths[begin] - thisChineseCalendar.lunarD);
// 下个月到年末
thisYearMonths.forEach((days,i)=>{
if (begin < i) dayList.push(days);
})
// 年初至过生那个月
lunarMonthDays(thisYear + 1).forEach((days,i)=>{
if (begin > i) dayList.push(days);
})
}
// 生日当月的天数
dayList.push(chineseCalendar.lunarD);
p.innerText = `下个农历生日还有${dayList.reduce((p,c)=>p+c, 0) - 1}天到来`;
} else {
const nextBirthDay = new Date(today.getFullYear()+1, date.getMonth(), date.getDate());
p.innerText = `下个阳历生日还有${timeDay.count(today, nextBirthDay)}天到来`;
}
el.appendChild(p);
}
computeTimeDate(div20220828, birthSon, false);
computeTimeDate(div19960124, birthDarling);
computeTimeDate(div19870903, birthSelf);
document.getElementById('inputOtherBirth').addEventListener('change', (event)=>{
const otherBirth = event.target.value;
if (otherBirth) computeTimeDate(divOtherInfo, new Date(otherBirth));
})
</script>
</div>
</body>
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<a href="./index/computerScience.md">CS</a>
<a href="./index/stomatological.md">口腔</a>
<a href="./blender/index.md">Blender</a>
<a href="./math/index.html">Mathjax latex Article</a>
<a href="./html/index.html">Mathjax latex Article</a>
</section>
<main class="main-content">
<div id="content"></div>
Expand Down
1 change: 0 additions & 1 deletion index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ function updateContent(text, options = {}) {
const elContent = document.getElementById('content');
if (options.isLink) {
elContent.classList.add('iframe')
console.log('22', elContent.style)
const elIframe = document.createElement('iframe');
elIframe.src = text;
elIframe.width = '100%';
Expand Down
1 change: 1 addition & 0 deletions index/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
- [用户 角色 权限的通用设计](../articles/2023/userRolePermission.md)
- [Markdown 例子](../articles/markdown.md)
- [Mathjax](../articles/mathjax.md)
- [农历历法](../articles/2023/chineseCalendar.md)

## 工作中遇到的
- [mobile-detect.js](https://github.com/hgoebl/mobile-detect.js)
Expand Down
3 changes: 3 additions & 0 deletions index/online.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@

## 工具


### 文档

- [PubScholar公益学术平台](https://pubscholar.cn/)
- [国家标准全文公开系统](https://openstd.samr.gov.cn/bzgk/gb/index)
- [msdn](https://learn.microsoft.com/zh-cn/)
- [个人关于微软的开发文档](https://msdn.itellyou.cn/)
- [MDN Web Docs](https://developer.mozilla.org/en-US/)
Expand Down

0 comments on commit 0c32a98

Please sign in to comment.