Skip to content

Commit

Permalink
🔧 fix late rat hour issue
Browse files Browse the repository at this point in the history
  • Loading branch information
SylarLong committed Oct 31, 2023
1 parent 2af46e9 commit 72a1afe
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 86 deletions.
16 changes: 14 additions & 2 deletions src/__tests__/ganzhi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe("calendar/heavenlyStemAndEarthlyBranch", () => {
{
date: "2023-1-21",
timeIndex: 12,
result: "壬寅 癸丑 庚辰 丙子",
result: "癸卯 癸丑 庚辰 丙子",
},
{
date: "2023-03-09",
Expand All @@ -91,9 +91,21 @@ describe("calendar/heavenlyStemAndEarthlyBranch", () => {
{
date: "2023-2-19",
timeIndex: 12,
isLeap: false,
result: "癸卯 甲寅 己酉 甲子",
},
{
date: '1987-12-6',
timeIndex: 11,
result: "丁卯 辛亥 己丑 乙亥"
}, {
date: '1987-12-6',
timeIndex: 12,
result: "丁卯 壬子 庚寅 丙子"
}, {
date: '1983-4-22',
timeIndex: 0,
result: "癸亥 丙辰 庚辰 丙子"
}
];

data.forEach(({ date, timeIndex, result }) => {
Expand Down
95 changes: 92 additions & 3 deletions src/__tests__/misc.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { getTerm, lunarDayToStr, lunarMonthToStr } from "..";
import { getSign, getTerm, getZodiac, lunarDayToStr, lunarMonthToStr } from "..";
import { EarthlyBranch } from "../types";
import { fixIndex } from "../utils";

describe("calendar/misc", () => {
test("getTerm()", () => {
Expand All @@ -12,7 +14,7 @@ describe("calendar/misc", () => {
getTerm(2101, 0);
} catch (err) {
expect((err as Error).message).toBe(
"Year should be greater or equal then 1900.",
"Year should be greater or equal then 1900."
);
}

Expand All @@ -34,7 +36,7 @@ describe("calendar/misc", () => {
lunarMonthToStr(0);
} catch (err) {
expect((err as Error).message).toBe(
"lunarMonth should be between 1 and 12.",
"lunarMonth should be between 1 and 12."
);
}
});
Expand All @@ -53,4 +55,91 @@ describe("calendar/misc", () => {
expect(lunarDayToStr(item.key)).toBe(item.value);
});
});

test("fixIndex()", () => {
expect(fixIndex(-1, 12)).toEqual(11);
expect(fixIndex(0, 12)).toEqual(0);
expect(fixIndex(-0, 12)).toEqual(0);
expect(fixIndex(10, 12)).toEqual(10);
expect(fixIndex(13, 12)).toEqual(1);
});

test("getSign()", () => {
const data = [
{
date: "2023-3-21",
value: "白羊座",
},
{
date: "2023-4-21",
value: "金牛座",
},
{
date: "2023-5-22",
value: "双子座",
},
{
date: "2023-6-22",
value: "巨蟹座",
},
{
date: "2023-7-23",
value: "狮子座",
},
{
date: "2023-8-23",
value: "处女座",
},
{
date: "2023-9-23",
value: "天秤座",
},
{
date: "2023-10-24",
value: "天蝎座",
},
{
date: "2023-11-23",
value: "射手座",
},
{
date: "2023-12-22",
value: "摩羯座",
},
{
date: "2023-1-20",
value: "水瓶座",
},
{
date: "2023-2-19",
value: "双鱼座",
},
];

data.forEach((item) => {
expect(getSign(item.date)).toEqual(item.value);
});
});

test("getZodiac()", () => {
const data = [
{key: "子", value: "鼠"},
{key: "丑", value: "牛"},
{key: "寅", value: "虎"},
{key: "卯", value: "兔"},
{key: "辰", value: "龙"},
{key: "巳", value: "蛇"},
{key: "午", value: "马"},
{key: "未", value: "羊"},
{key: "申", value: "猴"},
{key: "酉", value: "鸡"},
{key: "戌", value: "狗"},
{key: "亥", value: "猪"},
];

data.forEach((item) => {
expect(getZodiac(item.key as EarthlyBranch)).toEqual(item.value);
});
});

});
81 changes: 39 additions & 42 deletions src/ganzhi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
* @return [干, 支]
*/
const heavenlyStemAndEarthlyBranchFromOffset = (
offset: number,
offset: number
): HeavenlyStemAndEarthlyBranch => {
return [HEAVENLY_STEMS[offset % 10], EARTHLY_BRANCHES[offset % 12]];
};
Expand All @@ -27,7 +27,7 @@ const heavenlyStemAndEarthlyBranchFromOffset = (
* @return [干, 支]
*/
export const heavenlyStemAndEarthlyBranchOfYear = (
year: number,
year: number
): HeavenlyStemAndEarthlyBranch => {
let heavenStemKey = (year - 3) % 10;
let earthlyBranchKey = (year - 3) % 12;
Expand All @@ -48,7 +48,7 @@ export const heavenlyStemAndEarthlyBranchOfYear = (
* @returns [干, 支]
*/
export const heavenlyStemAndEarthlyBranchOfMonth = (
date: Date,
date: Date
): HeavenlyStemAndEarthlyBranch => {
const [year, month, day] = normalizeDateStr(date);

Expand All @@ -72,15 +72,13 @@ export const heavenlyStemAndEarthlyBranchOfMonth = (
* @returns [干, 支]
*/
export const heavenlyStemAndEarthlyBranchOfDay = (
date: Date,
timeIndex: number,
date: Date
): HeavenlyStemAndEarthlyBranch => {
const [year, month, day] = normalizeDateStr(date);
const dayFix = timeIndex === 12 ? 1 : 0; // 若时辰索引为12表示是晚子时,需要加一天
const dayCyclical =
Date.UTC(year, month - 1, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10;

return heavenlyStemAndEarthlyBranchFromOffset(dayCyclical + day + dayFix - 1);
return heavenlyStemAndEarthlyBranchFromOffset(dayCyclical + day - 1);
};

/**
Expand All @@ -92,14 +90,14 @@ export const heavenlyStemAndEarthlyBranchOfDay = (
*/
export const heavenlyStemAndEarthlyBranchOfTime = (
timeIndex: number,
heavenlyStemNameOfDay: HeavenlyStem,
heavenlyStemNameOfDay: HeavenlyStem
): HeavenlyStemAndEarthlyBranch => {
const startHeavenlyStem = RAT_RULE[heavenlyStemNameOfDay];
const heavenlyStem =
HEAVENLY_STEMS[
fixIndex(
HEAVENLY_STEMS.indexOf(startHeavenlyStem) + fixIndex(timeIndex),
10,
10
)
];
const earthlyBranch = EARTHLY_BRANCHES[fixIndex(timeIndex)];
Expand All @@ -118,34 +116,14 @@ export const heavenlyStemAndEarthlyBranchOfTime = (
export const getHeavenlyStemAndEarthlyBranchByLunarDate = (
dateStr: string,
timeIndex: number,
isLeap?: boolean,
isLeap?: boolean
): HeavenlyStemAndEarthlyBranchDate => {
const [lunarYear] = normalizeDateStr(dateStr);
const { solarYear, solarMonth, solarDay } = lunar2solar(dateStr, isLeap);
const solarDate = new Date(solarYear, solarMonth - 1, solarDay);

const yearly = heavenlyStemAndEarthlyBranchOfYear(lunarYear);
const monthly = heavenlyStemAndEarthlyBranchOfMonth(solarDate);
const daily = heavenlyStemAndEarthlyBranchOfDay(solarDate, timeIndex);
const hourly = heavenlyStemAndEarthlyBranchOfTime(timeIndex, daily[0]);
const solarDate = lunar2solar(dateStr, isLeap);

return {
yearly,
monthly,
daily,
hourly,
toString() {
if (yearly[0].length > 1) {
return `${yearly.join(" ")} - ${monthly.join(" ")} - ${daily.join(
" ",
)} - ${hourly.join(" ")}`;
} else {
return `${yearly.join("")} ${monthly.join("")} ${daily.join(
"",
)} ${hourly.join("")}`;
}
},
};
return getHeavenlyStemAndEarthlyBranchBySolarDate(
solarDate.toString(),
timeIndex
);
};

/**
Expand All @@ -157,13 +135,32 @@ export const getHeavenlyStemAndEarthlyBranchByLunarDate = (
*/
export const getHeavenlyStemAndEarthlyBranchBySolarDate = (
dateStr: string | Date,
timeIndex: number,
timeIndex: number
): HeavenlyStemAndEarthlyBranchDate => {
const lunarDate = solar2lunar(dateStr);
const [year, month, date] = normalizeDateStr(dateStr);
const solarDate = new Date(year, month - 1, date);

return getHeavenlyStemAndEarthlyBranchByLunarDate(
lunarDate.toString(),
timeIndex,
lunarDate.isLeap,
);
if (timeIndex == 12) {
// 晚子时,需要加1天
solarDate.setDate(solarDate.getDate() + 1);
}

const { lunarYear } = solar2lunar(solarDate);

const yearly = heavenlyStemAndEarthlyBranchOfYear(lunarYear);
const monthly = heavenlyStemAndEarthlyBranchOfMonth(solarDate);
const daily = heavenlyStemAndEarthlyBranchOfDay(solarDate);
const hourly = heavenlyStemAndEarthlyBranchOfTime(timeIndex, daily[0]);

return {
yearly,
monthly,
daily,
hourly,
toString() {
return `${yearly.join("")} ${monthly.join("")} ${daily.join(
""
)} ${hourly.join("")}`;
},
};
};
39 changes: 0 additions & 39 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,3 @@
import { TERM_INFO } from "./constants";

/**
* 传入公历年获得该年第termNo个节气的公历节气日
*
* @param year 公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
* @param termNo 节气序号【1~24】
* @return 节气日期
* @example
* termDay = getTerm(1987, 3); // termDay=4; 即1987年2月4日立春
*/
export const getTerm = (year: number, termNo: number) => {
if (year < 1900 || year > 2100) {
throw new Error("Year should be greater or equal then 1900.");
}

if (termNo < 1 || termNo > 24) {
throw new Error("termNo should be between 1 and 24.");
}

const _table: string = TERM_INFO[year - 1900];
const _info: string[] = [];

for (let i = 0; i < 30; i += 5) {
_info.push(parseInt("0x" + _table.substring(i, i + 5), 16).toString());
}

const _calday: string[] = [];

_info.forEach((item: string) => {
_calday.push(item.substring(0, 1));
_calday.push(item.substring(1, 3));
_calday.push(item.substring(3, 4));
_calday.push(item.substring(4, 6));
});

return parseInt(_calday[termNo - 1], 10);
};

/**
* 用于处理索引,将索引锁定在 0~max 范围内
*
Expand Down

0 comments on commit 72a1afe

Please sign in to comment.