dayjskh 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +20 -0
- package/.prettierrc.json +1 -0
- package/README.md +37 -0
- package/index.html +62 -0
- package/package.json +26 -0
- package/src/constant.ts +104 -0
- package/src/dayjskh.ts +522 -0
- package/src/lerngSak.ts +288 -0
- package/src/main.ts +17 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +22 -0
- package/types/index.d.ts +19 -0
package/.editorconfig
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
indent_style = space
|
|
8
|
+
indent_size = 4
|
|
9
|
+
trim_trailing_whitespace = true
|
|
10
|
+
|
|
11
|
+
[*.{json,vue,js,jsx,ts,tsx,css,scss,html}]
|
|
12
|
+
indent_size = 2
|
|
13
|
+
[*.md]
|
|
14
|
+
trim_trailing_whitespace = false
|
|
15
|
+
|
|
16
|
+
[*.{yml,yaml}]
|
|
17
|
+
indent_size = 2
|
|
18
|
+
|
|
19
|
+
[docker-compose.yml]
|
|
20
|
+
indent_size = 4
|
package/.prettierrc.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Khmer Lunar Date plugin for [Day.js](https://day.js.org/)
|
|
2
|
+
|
|
3
|
+
Convert Date to Khmer Lunar Date [see more...](https://web.archive.org/web/20190714153528/http://www.cam-cc.org/calendar/).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install dayjs
|
|
9
|
+
npm install dayjskh
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import dayjs from "dayjs";
|
|
16
|
+
import toKhDate from "dayjskh";
|
|
17
|
+
|
|
18
|
+
dayjs.extend(toKhDate);
|
|
19
|
+
|
|
20
|
+
const date = dayjs();
|
|
21
|
+
console.log(date.toKhDate(format?)); // ថ្ងៃច័ន្ទ ១២កើត ខែស្រាពណ៍ ឆ្នាំថោះ បញ្ចស័ក ពុទ្ធសករាជ ២៥៦៧
|
|
22
|
+
// find khmer new year dateTime
|
|
23
|
+
console.log(date.khNewYear());
|
|
24
|
+
// type
|
|
25
|
+
// {
|
|
26
|
+
// date: Dayjs;
|
|
27
|
+
// days: number;
|
|
28
|
+
// dates: {
|
|
29
|
+
// date: Dayjs;
|
|
30
|
+
// dayName: string;
|
|
31
|
+
// }[]
|
|
32
|
+
// }
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
# Author
|
|
36
|
+
|
|
37
|
+
This library is Ported from [momentkh](https://github.com/ThyrithSor/momentkh) by [Thyrith Sor](https://github.com/ThyrithSor) in to [Day.js Plugin](https://day.js.org/).
|
package/index.html
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>DayjsKh</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app">
|
|
10
|
+
<h1></h1>
|
|
11
|
+
<h2></h2>
|
|
12
|
+
<h3></h3>
|
|
13
|
+
<pre></pre>
|
|
14
|
+
<div
|
|
15
|
+
style="
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: row;
|
|
18
|
+
/* justify-content: space-between; */
|
|
19
|
+
"
|
|
20
|
+
>
|
|
21
|
+
<ul></ul>
|
|
22
|
+
<ul id="ul2"></ul>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<script type="module">
|
|
26
|
+
import dayjs from "dayjs";
|
|
27
|
+
import toKhDate from "./src/main.ts";
|
|
28
|
+
dayjs.extend(toKhDate);
|
|
29
|
+
const date = dayjs();
|
|
30
|
+
console.log(date.khNewYear());
|
|
31
|
+
document.querySelector("h1").innerHTML = date.toKhDate();
|
|
32
|
+
// document.querySelector("h2").innerHTML = date.format("DD/MM/YYYY HH:mm");
|
|
33
|
+
document.querySelector("pre").innerHTML = JSON.stringify(
|
|
34
|
+
date.year(2024).khNewYear(),
|
|
35
|
+
);
|
|
36
|
+
// .format("DD/MM/YYYY HH:mm");
|
|
37
|
+
// console.log(date.khNewYear(2024).format("DD/MM/YYYY HH:mm"));
|
|
38
|
+
// loop 5 days
|
|
39
|
+
const ul = document.querySelector("ul");
|
|
40
|
+
for (let i = 0; i < 30; i++) {
|
|
41
|
+
const li = document.createElement("li");
|
|
42
|
+
li.innerHTML = `${date
|
|
43
|
+
.add(i, "day")
|
|
44
|
+
.toKhDate("ថ្ងៃ W DN ខែ m")} - ${date
|
|
45
|
+
.add(i, "day")
|
|
46
|
+
.format("DD/MM/YYYY")}`;
|
|
47
|
+
ul.appendChild(li);
|
|
48
|
+
}
|
|
49
|
+
const date2 = dayjs("2050-01-01T00:00:00+07:00");
|
|
50
|
+
const ul2 = document.querySelector("#ul2");
|
|
51
|
+
for (let i = 0; i < 30; i++) {
|
|
52
|
+
const li = document.createElement("li");
|
|
53
|
+
li.innerHTML = `${date2
|
|
54
|
+
.add(i, "day")
|
|
55
|
+
.toKhDate("ថ្ងៃ W DN ខែ m")} - ${date2
|
|
56
|
+
.add(i, "day")
|
|
57
|
+
.format("DD/MM/YYYY")}`;
|
|
58
|
+
ul2.appendChild(li);
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
</body>
|
|
62
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dayjskh",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Khmer Lunar date Plugin for Day.js",
|
|
5
|
+
"main": "./src/main.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc && vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/ChanthornAcademy/dayjskh.git"
|
|
14
|
+
},
|
|
15
|
+
"author": "chanthorn",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^20.5.7",
|
|
19
|
+
"prettier": "3.0.2",
|
|
20
|
+
"typescript": "^5.2.2",
|
|
21
|
+
"vite": "^4.4.9"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"dayjs": "^1.11.9"
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/constant.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const lunarMonths = {};
|
|
2
|
+
"មិគសិរ_បុស្ស_មាឃ_ផល្គុន_ចេត្រ_ពិសាខ_ជេស្ឋ_អាសាឍ_ស្រាពណ៍_ភទ្របទ_អស្សុជ_កក្ដិក_បឋមាសាឍ_ទុតិយាសាឍ"
|
|
3
|
+
.split("_")
|
|
4
|
+
.forEach((month, index) => {
|
|
5
|
+
lunarMonths[month] = index;
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const solarMonths: { [key: string]: number } = {};
|
|
9
|
+
"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ"
|
|
10
|
+
.split("_")
|
|
11
|
+
.forEach((month, index) => (solarMonths[month] = index));
|
|
12
|
+
|
|
13
|
+
const animalYears: { [key: string]: number } = {};
|
|
14
|
+
"ជូត_ឆ្លូវ_ខាល_ថោះ_រោង_ម្សាញ់_មមីរ_មមែ_វក_រកា_ច_កុរ"
|
|
15
|
+
.split("_")
|
|
16
|
+
.forEach((year, index) => (animalYears[year] = index));
|
|
17
|
+
|
|
18
|
+
const eraYears: { [key: string]: number } = {};
|
|
19
|
+
"សំរឹទ្ធិស័ក_ឯកស័ក_ទោស័ក_ត្រីស័ក_ចត្វាស័ក_បញ្ចស័ក_ឆស័ក_សប្តស័ក_អដ្ឋស័ក_នព្វស័ក"
|
|
20
|
+
.split("_")
|
|
21
|
+
.forEach((year, index) => (eraYears[year] = index));
|
|
22
|
+
|
|
23
|
+
const moonStatus: { [key: string]: number } = {};
|
|
24
|
+
"កើត_រោច".split("_").forEach((status, index) => (moonStatus[status] = index));
|
|
25
|
+
|
|
26
|
+
const khNewYear: { [key: string]: string } = {
|
|
27
|
+
"1879": "12-04-1879 11:36",
|
|
28
|
+
"1897": "13-04-1897 02:00",
|
|
29
|
+
"2011": "14-04-2011 13:12",
|
|
30
|
+
"2012": "14-04-2012 19:11",
|
|
31
|
+
"2013": "14-04-2013 02:12",
|
|
32
|
+
"2014": "14-04-2014 08:07",
|
|
33
|
+
"2015": "14-04-2015 14:02",
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const kh = () => {
|
|
37
|
+
let symbolMap = {
|
|
38
|
+
1: "១",
|
|
39
|
+
2: "២",
|
|
40
|
+
3: "៣",
|
|
41
|
+
4: "៤",
|
|
42
|
+
5: "៥",
|
|
43
|
+
6: "៦",
|
|
44
|
+
7: "៧",
|
|
45
|
+
8: "៨",
|
|
46
|
+
9: "៩",
|
|
47
|
+
0: "០",
|
|
48
|
+
},
|
|
49
|
+
numberMap = {
|
|
50
|
+
"១": 1,
|
|
51
|
+
"២": 2,
|
|
52
|
+
"៣": 3,
|
|
53
|
+
"៤": 4,
|
|
54
|
+
"៥": 5,
|
|
55
|
+
"៦": 6,
|
|
56
|
+
"៧": 7,
|
|
57
|
+
"៨": 8,
|
|
58
|
+
"៩": 9,
|
|
59
|
+
"០": 0,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
months:
|
|
64
|
+
"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split(
|
|
65
|
+
"_",
|
|
66
|
+
),
|
|
67
|
+
monthsShort:
|
|
68
|
+
"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split(
|
|
69
|
+
"_",
|
|
70
|
+
),
|
|
71
|
+
moonDays:
|
|
72
|
+
"᧡_᧢_᧣_᧤_᧥_᧦_᧧_᧨_᧩_᧪_᧫_᧬_᧭_᧮_᧯_᧱_᧲_᧳_᧴_᧵_᧶_᧷_᧸_᧹_᧺_᧻_᧼_᧽_᧾_᧿".split("_"),
|
|
73
|
+
moonStatus: "កើត_រោច".split("_"),
|
|
74
|
+
moonStatusShort: "ក_រ".split("_"),
|
|
75
|
+
weekdays: "អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"),
|
|
76
|
+
weekdaysShort: "អា_ច_អ_ព_ព្រ_សុ_ស".split("_"),
|
|
77
|
+
weekdaysMin: "អា_ច_អ_ព_ព្រ_សុ_ស".split("_"),
|
|
78
|
+
lunarMonths:
|
|
79
|
+
"មិគសិរ_បុស្ស_មាឃ_ផល្គុន_ចេត្រ_ពិសាខ_ជេស្ឋ_អាសាឍ_ស្រាពណ៍_ភទ្របទ_អស្សុជ_កក្ដិក_បឋមាសាឍ_ទុតិយាសាឍ".split(
|
|
80
|
+
"_",
|
|
81
|
+
),
|
|
82
|
+
animalYear: "ជូត_ឆ្លូវ_ខាល_ថោះ_រោង_ម្សាញ់_មមីរ_មមែ_វក_រកា_ច_កុរ".split("_"),
|
|
83
|
+
eraYear:
|
|
84
|
+
"សំរឹទ្ធិស័ក_ឯកស័ក_ទោស័ក_ត្រីស័ក_ចត្វាស័ក_បញ្ចស័ក_ឆស័ក_សប្តស័ក_អដ្ឋស័ក_នព្វស័ក".split(
|
|
85
|
+
"_",
|
|
86
|
+
),
|
|
87
|
+
preparse: function (number: any) {
|
|
88
|
+
return number.toString().replace(/[០១២៣៤៥៦៧៨៩]/g, (m) => numberMap[m]);
|
|
89
|
+
},
|
|
90
|
+
postformat: function (number: any) {
|
|
91
|
+
return number.toString().replace(/\d/g, (m) => symbolMap[m]);
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const constant = {
|
|
97
|
+
lunarMonths,
|
|
98
|
+
solarMonths,
|
|
99
|
+
animalYears,
|
|
100
|
+
eraYears,
|
|
101
|
+
moonStatus,
|
|
102
|
+
khNewYear,
|
|
103
|
+
kh: kh(),
|
|
104
|
+
};
|
package/src/dayjskh.ts
ADDED
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
// Khmer Chhankitek Calendar
|
|
2
|
+
// Ref.: https://khmer-calendar.tovnah.com/calendar/toc.php
|
|
3
|
+
|
|
4
|
+
import { constant } from "./constant";
|
|
5
|
+
import learnSak from "./lerngSak";
|
|
6
|
+
import dayjs from "dayjs/esm/index.js";
|
|
7
|
+
import duration from "dayjs/esm/plugin/duration";
|
|
8
|
+
import customParseFormat from "dayjs/esm/plugin/customParseFormat";
|
|
9
|
+
import badMutable from "dayjs/esm/plugin/badMutable";
|
|
10
|
+
|
|
11
|
+
dayjs.extend(customParseFormat);
|
|
12
|
+
dayjs.extend(duration);
|
|
13
|
+
|
|
14
|
+
const { lunarMonths } = constant;
|
|
15
|
+
|
|
16
|
+
export default function dayjskh(date?: dayjs.Dayjs | string) {
|
|
17
|
+
// check if date is valid
|
|
18
|
+
const globalDate = dayjs(date); // if date is undefined, it will return current date
|
|
19
|
+
if (!globalDate.isValid()) {
|
|
20
|
+
throw new Error("Invalid Date");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const { floor } = Math;
|
|
24
|
+
// Aharkun: អាហារគុណ ឬ ហារគុណ
|
|
25
|
+
// Aharkun is used for Avoman and Bodithey calculation below. Given adYear as a target year in Buddhist Era
|
|
26
|
+
function getAharkun(beYear: number): number {
|
|
27
|
+
let t = beYear * 292207 + 499;
|
|
28
|
+
return floor(t / 800) + 4;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getAharkunMod(beYear: number): number {
|
|
32
|
+
let t = beYear * 292207 + 499;
|
|
33
|
+
return t % 800;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Bodithey: បូតិថី
|
|
37
|
+
// Bodithey determines if a given beYear is a leap-month year. Given year target year in Buddhist Era
|
|
38
|
+
function getBodithey(beYear: number): number {
|
|
39
|
+
const { avml, aharkun } = {
|
|
40
|
+
avml: floor((11 * getAharkun(beYear) + 25) / 692),
|
|
41
|
+
aharkun: getAharkun(beYear),
|
|
42
|
+
};
|
|
43
|
+
return (avml + aharkun + 29) % 30;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Avoman: អាវមាន
|
|
47
|
+
// Avoman determines if a given year is a leap-day year. Given a year in Buddhist Era as denoted as adYear
|
|
48
|
+
function getAvoman(beYear: number): number {
|
|
49
|
+
const aharkun = getAharkun(beYear);
|
|
50
|
+
return (11 * aharkun + 25) % 692;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Kromathupul
|
|
54
|
+
function khromathupul(beYear: number): number {
|
|
55
|
+
const aharkunMod = getAharkunMod(beYear);
|
|
56
|
+
return 800 - aharkunMod;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// isKhmerSolarLeap
|
|
60
|
+
function isKhmerSolarLeap(beYear: number): boolean {
|
|
61
|
+
return khromathupul(beYear) <= 207;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Regular if year has 30 day
|
|
65
|
+
// leap month if year has 13 months
|
|
66
|
+
// leap day if Jesth month of the year has 1 extra day
|
|
67
|
+
// leap day and month: both of them
|
|
68
|
+
function getBoditheyLeap(beYear: number): number {
|
|
69
|
+
let result = 0;
|
|
70
|
+
const avoman = getAvoman(beYear);
|
|
71
|
+
const bodithey = getBodithey(beYear);
|
|
72
|
+
let boditheyLeap = 0;
|
|
73
|
+
if (bodithey >= 25 || bodithey <= 5) {
|
|
74
|
+
boditheyLeap = 1;
|
|
75
|
+
}
|
|
76
|
+
// check for avoman leap-day based on gregorian leap
|
|
77
|
+
let avomanLeap = 0;
|
|
78
|
+
if (isKhmerSolarLeap(beYear)) {
|
|
79
|
+
if (avoman <= 126) avomanLeap = 1;
|
|
80
|
+
} else {
|
|
81
|
+
if (avoman <= 137) {
|
|
82
|
+
// check for avoman case 137/0, 137 must be normal year (p.26)
|
|
83
|
+
if (getAvoman(beYear + 1) === 0) {
|
|
84
|
+
avomanLeap = 0;
|
|
85
|
+
} else {
|
|
86
|
+
avomanLeap = 1;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// case of 25/5 consecutively
|
|
92
|
+
// only bodithey 5 can be leap-month, so set bodithey 25 to none
|
|
93
|
+
if (bodithey === 25) {
|
|
94
|
+
let nextBodithey = getBodithey(beYear + 1);
|
|
95
|
+
if (nextBodithey === 5) {
|
|
96
|
+
boditheyLeap = 0;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// case of 24/6 consecutively, 24 must be leap-month
|
|
101
|
+
if (bodithey == 24) {
|
|
102
|
+
let nextBodithey = getBodithey(beYear + 1);
|
|
103
|
+
if (nextBodithey == 6) {
|
|
104
|
+
boditheyLeap = 1;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// format leap result (0:regular, 1:month, 2:day, 3:both)
|
|
109
|
+
if (boditheyLeap === 1 && avomanLeap === 1) {
|
|
110
|
+
result = 3;
|
|
111
|
+
} else if (boditheyLeap === 1) {
|
|
112
|
+
result = 1;
|
|
113
|
+
} else if (avomanLeap === 1) {
|
|
114
|
+
result = 2;
|
|
115
|
+
} else {
|
|
116
|
+
result = 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// bodithey leap can be both leap-day and leap-month but following the khmer calendar rule, they can't be together on the same year, so leap day must be delayed to next year
|
|
123
|
+
function getProtetinLeap(beYear: number): number {
|
|
124
|
+
const b = getBoditheyLeap(beYear);
|
|
125
|
+
if (b === 3) {
|
|
126
|
+
return 1;
|
|
127
|
+
}
|
|
128
|
+
if (b === 2 || b === 1) {
|
|
129
|
+
return b;
|
|
130
|
+
}
|
|
131
|
+
// case of previous year is 3
|
|
132
|
+
if (getBoditheyLeap(beYear - 1) === 3) {
|
|
133
|
+
return 2;
|
|
134
|
+
}
|
|
135
|
+
return 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// A year with an extra day is called Chhantrea Thimeas (ចន្ទ្រាធិមាស) or Adhikavereak (អធិកវារៈ). This year has 355 days.
|
|
139
|
+
function isKhmerLunarLeapDay(beYear: number): boolean {
|
|
140
|
+
return getProtetinLeap(beYear) === 2;
|
|
141
|
+
}
|
|
142
|
+
// A year with an extra month is called Adhikameas (អធិកមាស). This year has 384 days.
|
|
143
|
+
function isKhmerLeapMonth(beYear: number): boolean {
|
|
144
|
+
return getProtetinLeap(beYear) === 1;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// is Gregorian Leap Year
|
|
148
|
+
// function isGregorianLeapYear(beYear: number): boolean {
|
|
149
|
+
// return (beYear % 4 === 0 && beYear % 100 !== 0) || beYear % 400 === 0;
|
|
150
|
+
// }
|
|
151
|
+
|
|
152
|
+
// get Max day of Khmer month
|
|
153
|
+
function getMaxDayOfKhmerMonth(beMonth: number, beYear: number): number {
|
|
154
|
+
// 'ជេស្ឋ': 6,
|
|
155
|
+
if (beMonth === 6 && isKhmerLunarLeapDay(beYear)) {
|
|
156
|
+
return 30;
|
|
157
|
+
}
|
|
158
|
+
if (
|
|
159
|
+
// 'បឋមាសាឍ': 12, 'ទុតិយាសាឍ': 13
|
|
160
|
+
beMonth === 12 ||
|
|
161
|
+
beMonth === 13
|
|
162
|
+
) {
|
|
163
|
+
return 30;
|
|
164
|
+
}
|
|
165
|
+
return beMonth % 2 === 0 ? 29 : 30;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Get number of day in Khmer year
|
|
169
|
+
function getNumDayOfKhmerYear(beYear: number): number {
|
|
170
|
+
if (isKhmerLeapMonth(beYear)) {
|
|
171
|
+
return 384;
|
|
172
|
+
} else if (isKhmerLunarLeapDay(beYear)) {
|
|
173
|
+
return 355;
|
|
174
|
+
} else {
|
|
175
|
+
return 354;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Buddhist Era
|
|
180
|
+
// ថ្ងៃឆ្លងឆ្នាំ គឺ ១ រោច ខែពិសាខ
|
|
181
|
+
// @ref http://news.sabay.com.kh/article/1039620
|
|
182
|
+
// @summary: ឯកឧត្តម សេង សុមុនី អ្នកនាំពាក្យក្រសួងធម្មការ និងសាសនាឲ្យSabay ដឹងថានៅប្រទេសកម្ពុជាការឆ្លងចូលពុទ្ធសករាជថ្មីគឺកំណត់យកនៅថ្ងៃព្រះពុទ្ធយាងចូលនិព្វាន ពោលគឺនៅថ្ងៃ១រោច ខែពិសាខ។
|
|
183
|
+
// @param dayjs
|
|
184
|
+
|
|
185
|
+
function getBEYear(date: dayjs.Dayjs): number {
|
|
186
|
+
if (date.diff(getVisakBochea(date.year())) > 0) {
|
|
187
|
+
return date.year() + 544;
|
|
188
|
+
} else {
|
|
189
|
+
return date.year() + 543;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function getMaybeBEYear(date: dayjs.Dayjs): number {
|
|
194
|
+
if (date.month() <= 4) {
|
|
195
|
+
return date.year() + 543;
|
|
196
|
+
} else {
|
|
197
|
+
return date.year() + 544;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Next month of Khmer month
|
|
202
|
+
|
|
203
|
+
function nextMonthOf(khmerMonth: number, beYear: number): number {
|
|
204
|
+
switch (khmerMonth) {
|
|
205
|
+
case lunarMonths["មិគសិរ"]:
|
|
206
|
+
return lunarMonths["បុស្ស"];
|
|
207
|
+
case lunarMonths["បុស្ស"]:
|
|
208
|
+
return lunarMonths["មាឃ"];
|
|
209
|
+
case lunarMonths["មាឃ"]:
|
|
210
|
+
return lunarMonths["ផល្គុន"];
|
|
211
|
+
case lunarMonths["ផល្គុន"]:
|
|
212
|
+
return lunarMonths["ចេត្រ"];
|
|
213
|
+
case lunarMonths["ចេត្រ"]:
|
|
214
|
+
return lunarMonths["ពិសាខ"];
|
|
215
|
+
case lunarMonths["ពិសាខ"]:
|
|
216
|
+
return lunarMonths["ជេស្ឋ"];
|
|
217
|
+
case lunarMonths["ជេស្ឋ"]: {
|
|
218
|
+
if (isKhmerLeapMonth(beYear)) {
|
|
219
|
+
return lunarMonths["បឋមាសាឍ"];
|
|
220
|
+
} else {
|
|
221
|
+
return lunarMonths["អាសាឍ"];
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
case lunarMonths["អាសាឍ"]:
|
|
225
|
+
return lunarMonths["ស្រាពណ៍"];
|
|
226
|
+
case lunarMonths["ស្រាពណ៍"]:
|
|
227
|
+
return lunarMonths["ភទ្របទ"];
|
|
228
|
+
case lunarMonths["ភទ្របទ"]:
|
|
229
|
+
return lunarMonths["អស្សុជ"];
|
|
230
|
+
case lunarMonths["អស្សុជ"]:
|
|
231
|
+
return lunarMonths["កក្ដិក"];
|
|
232
|
+
case lunarMonths["កក្ដិក"]:
|
|
233
|
+
return lunarMonths["មិគសិរ"];
|
|
234
|
+
case lunarMonths["បឋមាសាឍ"]:
|
|
235
|
+
return lunarMonths["ទុតិយាសាឍ"];
|
|
236
|
+
case lunarMonths["ទុតិយាសាឍ"]:
|
|
237
|
+
return lunarMonths["ស្រាពណ៍"];
|
|
238
|
+
default:
|
|
239
|
+
throw Error("Plugin is facing wrong calculation (Invalid month)");
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// calculate date from dayjs to Khmer date
|
|
244
|
+
function getLunarDate(targetDate: dayjs.Dayjs): {
|
|
245
|
+
day: number;
|
|
246
|
+
month: number;
|
|
247
|
+
epochMoved: dayjs.Dayjs;
|
|
248
|
+
} {
|
|
249
|
+
dayjs.extend(badMutable);
|
|
250
|
+
// Epoch Date: January 1, 1900
|
|
251
|
+
let epochDayjs = dayjs("1900-01-01");
|
|
252
|
+
let khmerMonth = 1;
|
|
253
|
+
let khmerDay = 0; // 0 - 29 ១កើត ... ១៥កើត ១រោច ...១៤រោច (១៥រោច)
|
|
254
|
+
// Find nearest year epoch
|
|
255
|
+
if (targetDate.diff(epochDayjs) > 0) {
|
|
256
|
+
while (
|
|
257
|
+
dayjs.duration(targetDate.diff(epochDayjs), "milliseconds").asDays() > // ok
|
|
258
|
+
getNumDayOfKhmerYear(getMaybeBEYear(epochDayjs.clone().add(1, "year")))
|
|
259
|
+
) {
|
|
260
|
+
epochDayjs.add(
|
|
261
|
+
getNumDayOfKhmerYear(
|
|
262
|
+
getMaybeBEYear(epochDayjs.clone().add(1, "year")),
|
|
263
|
+
),
|
|
264
|
+
"day",
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
do {
|
|
269
|
+
epochDayjs.subtract(
|
|
270
|
+
getNumDayOfKhmerYear(getMaybeBEYear(epochDayjs)),
|
|
271
|
+
"day",
|
|
272
|
+
);
|
|
273
|
+
} while (
|
|
274
|
+
dayjs.duration(epochDayjs.diff(targetDate), "milliseconds").asDays() > 0
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
// Move epoch month
|
|
278
|
+
while (
|
|
279
|
+
dayjs.duration(targetDate.diff(epochDayjs), "milliseconds").asDays() >
|
|
280
|
+
getMaxDayOfKhmerMonth(khmerMonth, getMaybeBEYear(epochDayjs))
|
|
281
|
+
) {
|
|
282
|
+
epochDayjs.add(
|
|
283
|
+
getMaxDayOfKhmerMonth(khmerMonth, getMaybeBEYear(epochDayjs)),
|
|
284
|
+
"day",
|
|
285
|
+
);
|
|
286
|
+
khmerMonth = nextMonthOf(khmerMonth, getMaybeBEYear(epochDayjs));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
khmerDay += floor(
|
|
290
|
+
dayjs.duration(targetDate.diff(epochDayjs), "milliseconds").asDays(),
|
|
291
|
+
);
|
|
292
|
+
// fix result display 15 រោច ខែ ជេស្ឋ នៅថ្ងៃ ១ កើតខែបឋមាសាធ
|
|
293
|
+
// ករណី ខែជេស្ឋមានតែ ២៩ ថ្ងៃ តែលទ្ធផលបង្ហាញ ១៥រោច ខែជេស្ឋ
|
|
294
|
+
const totalDaysOfTheMonth = getMaxDayOfKhmerMonth(
|
|
295
|
+
khmerMonth,
|
|
296
|
+
getMaybeBEYear(targetDate),
|
|
297
|
+
);
|
|
298
|
+
if (totalDaysOfTheMonth <= khmerDay) {
|
|
299
|
+
khmerDay = khmerDay % totalDaysOfTheMonth;
|
|
300
|
+
khmerMonth = nextMonthOf(khmerMonth, getMaybeBEYear(epochDayjs));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
epochDayjs.add(
|
|
304
|
+
dayjs.duration(targetDate.diff(epochDayjs), "milliseconds").asDays(),
|
|
305
|
+
"day",
|
|
306
|
+
);
|
|
307
|
+
return {
|
|
308
|
+
day: khmerDay,
|
|
309
|
+
month: khmerMonth,
|
|
310
|
+
epochMoved: epochDayjs,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// រកថ្ងៃវិសាខបូជា
|
|
315
|
+
// ថ្ងៃដាច់ឆ្នាំពុទ្ធសករាជ
|
|
316
|
+
function getVisakBochea(
|
|
317
|
+
gregorianYear: number,
|
|
318
|
+
): string | number | dayjs.Dayjs | Date | null | undefined | any {
|
|
319
|
+
const date = dayjs(`${gregorianYear}-01-01`);
|
|
320
|
+
for (var i = 0; i < 365; i++) {
|
|
321
|
+
const lunarDate = getLunarDate(date);
|
|
322
|
+
if (lunarDate.month === lunarMonths["ពិសាខ"] && lunarDate.day === 14) {
|
|
323
|
+
return date;
|
|
324
|
+
}
|
|
325
|
+
date.add(1, "day");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function datesOfKhmerNewYear(
|
|
330
|
+
startDate: dayjs.Dayjs,
|
|
331
|
+
numberOfNewYearDays: number,
|
|
332
|
+
) {
|
|
333
|
+
let dates = [];
|
|
334
|
+
for (let i = 0; i < numberOfNewYearDays; i++) {
|
|
335
|
+
dates.push(startDate.clone().add(i, "day"));
|
|
336
|
+
}
|
|
337
|
+
return dates.map((date, index) => {
|
|
338
|
+
// find first day
|
|
339
|
+
let dayName = "Moha Sangkranta"; // មហាសង្រ្កាន្ត
|
|
340
|
+
if (index === 0) {
|
|
341
|
+
dayName = "Moha Sangkranta"; // មហាសង្រ្កាន្ត
|
|
342
|
+
} // last day
|
|
343
|
+
else if (index === numberOfNewYearDays - 1) {
|
|
344
|
+
dayName = "Veareak Laeung Sak"; // ថ្ងៃឡើងស័ក
|
|
345
|
+
} else {
|
|
346
|
+
dayName = "Veareak Vanabat"; // វារៈវ័នបត
|
|
347
|
+
}
|
|
348
|
+
return {
|
|
349
|
+
date,
|
|
350
|
+
dayName,
|
|
351
|
+
};
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// get khmer new year day
|
|
356
|
+
function getKhmerNewYear(gregorianYear: number): {
|
|
357
|
+
date: dayjs.Dayjs;
|
|
358
|
+
days: number;
|
|
359
|
+
dates: { date: dayjs.Dayjs; dayName: string }[];
|
|
360
|
+
} {
|
|
361
|
+
// ពីគ្រិស្ដសករាជ ទៅ ចុល្លសករាជ
|
|
362
|
+
let jsYear = gregorianYear + 544 - 1182;
|
|
363
|
+
let info = learnSak(jsYear);
|
|
364
|
+
let numberOfNewYearDay;
|
|
365
|
+
if (info.newYearsDaySotins[0].angsar === 0) {
|
|
366
|
+
numberOfNewYearDay = 4;
|
|
367
|
+
} else {
|
|
368
|
+
numberOfNewYearDay = 3;
|
|
369
|
+
}
|
|
370
|
+
let epochLerngSak = dayjs(
|
|
371
|
+
`${gregorianYear}-04-17 ${info.timeOfNewYear.hour}:${info.timeOfNewYear.minute}`,
|
|
372
|
+
"YYYY-MM-DD H:m",
|
|
373
|
+
);
|
|
374
|
+
let KhEpoch = getLunarDate(epochLerngSak);
|
|
375
|
+
let diffFromEpoch =
|
|
376
|
+
(KhEpoch.month - 4) * 30 +
|
|
377
|
+
KhEpoch.day -
|
|
378
|
+
((info.lunarDateLerngSak.month - 4) * 30 + info.lunarDateLerngSak.day);
|
|
379
|
+
|
|
380
|
+
const result = epochLerngSak.subtract(
|
|
381
|
+
diffFromEpoch + numberOfNewYearDay - 1,
|
|
382
|
+
"day",
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
return {
|
|
386
|
+
date: result,
|
|
387
|
+
days: numberOfNewYearDay,
|
|
388
|
+
dates: datesOfKhmerNewYear(result, numberOfNewYearDay),
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
// find animal year
|
|
392
|
+
function getAnimalYear(date: dayjs.Dayjs): number {
|
|
393
|
+
const year = date.year();
|
|
394
|
+
const KhmerNewYear = getKhmerNewYear(year).date;
|
|
395
|
+
if (date.diff(KhmerNewYear) < 0) {
|
|
396
|
+
return (year + 543 + 4) % 12;
|
|
397
|
+
} else {
|
|
398
|
+
return (year + 544 + 4) % 12;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Jolak Sakaraj
|
|
403
|
+
function getJolakSakarajYear(date: dayjs.Dayjs) {
|
|
404
|
+
const year = date.year();
|
|
405
|
+
const KhmerNewYear = getKhmerNewYear(year).date;
|
|
406
|
+
if (date.diff(KhmerNewYear) < 0) {
|
|
407
|
+
return year + 543 - 1182;
|
|
408
|
+
} else {
|
|
409
|
+
return year + 544 - 1182;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function getKhmerLunarDayName(day: number): {
|
|
414
|
+
count: number;
|
|
415
|
+
moonStatus: number;
|
|
416
|
+
} {
|
|
417
|
+
return {
|
|
418
|
+
count: (day % 15) + 1,
|
|
419
|
+
moonStatus:
|
|
420
|
+
day > 14 ? constant.moonStatus["រោច"] : constant.moonStatus["កើត"],
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Khmer date format handler
|
|
425
|
+
function formatKhmerDate(
|
|
426
|
+
day: number,
|
|
427
|
+
month: number,
|
|
428
|
+
dayjs: dayjs.Dayjs,
|
|
429
|
+
format: string,
|
|
430
|
+
): string {
|
|
431
|
+
if (format === null || format === undefined || format === "") {
|
|
432
|
+
// Default date format
|
|
433
|
+
const dayOfWeek = dayjs.day();
|
|
434
|
+
const moonDay = getKhmerLunarDayName(day);
|
|
435
|
+
const beYear = getBEYear(dayjs);
|
|
436
|
+
const animalYear = getAnimalYear(dayjs);
|
|
437
|
+
const eraYear = getJolakSakarajYear(dayjs) % 10;
|
|
438
|
+
return constant.kh.postformat(
|
|
439
|
+
`ថ្ងៃ${constant.kh.weekdays[dayOfWeek]} ${moonDay.count}${
|
|
440
|
+
constant.kh.moonStatus[moonDay.moonStatus]
|
|
441
|
+
} ខែ${constant.kh.lunarMonths[month]} ឆ្នាំ${
|
|
442
|
+
constant.kh.animalYear[animalYear]
|
|
443
|
+
} ${constant.kh.eraYear[eraYear]} ពុទ្ធសករាជ ${beYear}`,
|
|
444
|
+
);
|
|
445
|
+
} else if (typeof format === "string") {
|
|
446
|
+
const formatRules = {
|
|
447
|
+
W: () => {
|
|
448
|
+
return constant.kh.weekdays[dayjs.day()];
|
|
449
|
+
},
|
|
450
|
+
w: () => {
|
|
451
|
+
return constant.kh.weekdaysShort[dayjs.day()];
|
|
452
|
+
},
|
|
453
|
+
d: () => {
|
|
454
|
+
const moonDay = getKhmerLunarDayName(day);
|
|
455
|
+
return moonDay.count;
|
|
456
|
+
},
|
|
457
|
+
D: () => {
|
|
458
|
+
const moonDay = getKhmerLunarDayName(day);
|
|
459
|
+
return ("" + moonDay.count).length === 1
|
|
460
|
+
? `០${moonDay.count}`
|
|
461
|
+
: moonDay.count;
|
|
462
|
+
},
|
|
463
|
+
N: () => {
|
|
464
|
+
const moonDay = getKhmerLunarDayName(day);
|
|
465
|
+
return constant.kh.moonStatus[moonDay.moonStatus];
|
|
466
|
+
},
|
|
467
|
+
n: () => {
|
|
468
|
+
const moonDay = getKhmerLunarDayName(day);
|
|
469
|
+
return constant.kh.moonStatusShort[moonDay.moonStatus];
|
|
470
|
+
},
|
|
471
|
+
o: () => {
|
|
472
|
+
return constant.kh.moonDays[day];
|
|
473
|
+
},
|
|
474
|
+
m: () => {
|
|
475
|
+
return constant.kh.lunarMonths[month];
|
|
476
|
+
},
|
|
477
|
+
M: () => {
|
|
478
|
+
return constant.kh.months[dayjs.month()];
|
|
479
|
+
},
|
|
480
|
+
a: () => {
|
|
481
|
+
return constant.kh.animalYear[getAnimalYear(dayjs)];
|
|
482
|
+
},
|
|
483
|
+
e: () => {
|
|
484
|
+
return constant.kh.eraYear[getJolakSakarajYear(dayjs) % 10];
|
|
485
|
+
},
|
|
486
|
+
b: () => {
|
|
487
|
+
return getBEYear(dayjs);
|
|
488
|
+
},
|
|
489
|
+
c: () => {
|
|
490
|
+
return dayjs.year();
|
|
491
|
+
},
|
|
492
|
+
j: () => {
|
|
493
|
+
return getJolakSakarajYear(dayjs);
|
|
494
|
+
},
|
|
495
|
+
};
|
|
496
|
+
return constant.kh.postformat(
|
|
497
|
+
format.replace(
|
|
498
|
+
new RegExp(Object.keys(formatRules).join("|"), "g"),
|
|
499
|
+
(m) => formatRules[m](),
|
|
500
|
+
),
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// format date to Khmer date
|
|
506
|
+
function format(format?: string): string {
|
|
507
|
+
const date = globalDate.clone();
|
|
508
|
+
const lunarDate = getLunarDate(date);
|
|
509
|
+
const result = formatKhmerDate(
|
|
510
|
+
lunarDate.day,
|
|
511
|
+
lunarDate.month,
|
|
512
|
+
date,
|
|
513
|
+
format,
|
|
514
|
+
);
|
|
515
|
+
return result;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return {
|
|
519
|
+
format,
|
|
520
|
+
khmerNewYearDate: getKhmerNewYear,
|
|
521
|
+
};
|
|
522
|
+
}
|
package/src/lerngSak.ts
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import dayjs from "dayjs";
|
|
2
|
+
import { constant } from "./constant";
|
|
3
|
+
|
|
4
|
+
// calculate Khmer New Year
|
|
5
|
+
// based on: https://www.dahlina.com/education/khmer_new_year_time.html?fbclid=IwAR0Eq6US-F0LfplMjKzmiRn7rvPgi31i74Wpv4mNhU034mzdyj-3hYrCA8w
|
|
6
|
+
export default function learnSak(jsYear: number = dayjs().year()) {
|
|
7
|
+
if (arguments.length === 0) {
|
|
8
|
+
jsYear = dayjs().year();
|
|
9
|
+
} else {
|
|
10
|
+
jsYear = arguments[0];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const getInfo = (
|
|
14
|
+
jsYear: number,
|
|
15
|
+
): {
|
|
16
|
+
harkun: number;
|
|
17
|
+
kromathopol: number;
|
|
18
|
+
avaman: number;
|
|
19
|
+
bodithey: number;
|
|
20
|
+
} => {
|
|
21
|
+
let h = 292207 * jsYear + 373;
|
|
22
|
+
let harkun = Math.floor(h / 800) + 1;
|
|
23
|
+
let kromathopol = 800 - (h % 800);
|
|
24
|
+
|
|
25
|
+
let a = 11 * harkun + 650;
|
|
26
|
+
let avaman = a % 692;
|
|
27
|
+
let bodithey = (harkun + Math.floor(a / 692)) % 30;
|
|
28
|
+
return {
|
|
29
|
+
harkun,
|
|
30
|
+
kromathopol,
|
|
31
|
+
avaman,
|
|
32
|
+
bodithey,
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const getHas366Days = (jsYear: number): boolean => {
|
|
37
|
+
const { kromathopol } = getInfo(jsYear);
|
|
38
|
+
return kromathopol <= 207;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const getIsAdhikameas = (jsYear: number): boolean => {
|
|
42
|
+
const { bodithey: infoOfYear } = getInfo(jsYear);
|
|
43
|
+
const { bodithey: infoOfNextYear } = getInfo(jsYear + 1);
|
|
44
|
+
return (
|
|
45
|
+
!(infoOfYear === 25 && infoOfNextYear === 5) &&
|
|
46
|
+
(infoOfYear > 24 ||
|
|
47
|
+
infoOfNextYear < 6 ||
|
|
48
|
+
(infoOfYear === 24 && infoOfNextYear === 6))
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const getIsChantreathimeas = (jsYear: number): boolean => {
|
|
53
|
+
const { avaman: infoOfYear } = getInfo(jsYear);
|
|
54
|
+
const { avaman: infoOfNextYear } = getInfo(jsYear + 1);
|
|
55
|
+
const { avaman: infoOfPrevYear } = getInfo(jsYear - 1);
|
|
56
|
+
const has366Days = getHas366Days(jsYear);
|
|
57
|
+
return (
|
|
58
|
+
(has366Days && infoOfYear < 127) ||
|
|
59
|
+
(!(infoOfYear === 137 && infoOfNextYear === 0) &&
|
|
60
|
+
((!has366Days && infoOfYear < 138) ||
|
|
61
|
+
(infoOfPrevYear === 137 && infoOfYear === 0)))
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const has366Days = getHas366Days(jsYear);
|
|
66
|
+
const isAdhikameas = getIsAdhikameas(jsYear);
|
|
67
|
+
const isChantreathimeas = getIsChantreathimeas(jsYear);
|
|
68
|
+
|
|
69
|
+
const jesthHas30 = (): boolean => {
|
|
70
|
+
const isAthikameas = isAdhikameas;
|
|
71
|
+
let tmp = isChantreathimeas;
|
|
72
|
+
if (isAthikameas && isChantreathimeas) {
|
|
73
|
+
tmp = false;
|
|
74
|
+
}
|
|
75
|
+
if (
|
|
76
|
+
!isChantreathimeas &&
|
|
77
|
+
getIsAdhikameas(jsYear - 1) &&
|
|
78
|
+
getIsChantreathimeas(jsYear - 1)
|
|
79
|
+
) {
|
|
80
|
+
tmp = true;
|
|
81
|
+
}
|
|
82
|
+
return tmp;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const dayLerngSak = (getInfo(jsYear).harkun - 2) % 7;
|
|
86
|
+
|
|
87
|
+
const lunarDateLerngSak = (): {
|
|
88
|
+
day: number;
|
|
89
|
+
month: number;
|
|
90
|
+
} => {
|
|
91
|
+
let { bodithey: bodithey } = getInfo(jsYear);
|
|
92
|
+
if (getIsAdhikameas(jsYear - 1) && getIsChantreathimeas(jsYear - 1)) {
|
|
93
|
+
bodithey = (bodithey + 1) % 30;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
day: bodithey >= 6 ? bodithey - 1 : bodithey,
|
|
97
|
+
month:
|
|
98
|
+
bodithey >= 6
|
|
99
|
+
? constant.lunarMonths["ចេត្រ"]
|
|
100
|
+
: constant.lunarMonths["ពិសាខ"],
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const getSunInfo = (sotin: number) => {
|
|
105
|
+
const infoOfPreviousYear = getInfo(jsYear - 1);
|
|
106
|
+
|
|
107
|
+
const sunAverageAsLibda = (): number => {
|
|
108
|
+
let r2 = 800 * sotin + infoOfPreviousYear.kromathopol;
|
|
109
|
+
let reasey = Math.floor(r2 / 24350); // រាសី
|
|
110
|
+
let r3 = r2 % 24350;
|
|
111
|
+
let angsar = Math.floor(r3 / 811); // អង្សា
|
|
112
|
+
let r4 = r3 % 811;
|
|
113
|
+
let l1 = Math.floor(r4 / 14);
|
|
114
|
+
let libda = l1 - 3; // លិប្ដា
|
|
115
|
+
return 30 * 60 * reasey + 60 * angsar + libda;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const leftOver = (): number => {
|
|
119
|
+
let s1 = 30 * 60 * 2 + 60 * 20;
|
|
120
|
+
let leftOver = sunAverageAsLibda() - s1; // មធ្យមព្រះអាទិត្យ - R2.A20.L0
|
|
121
|
+
if (sunAverageAsLibda() < s1) {
|
|
122
|
+
// បើតូចជាង ខ្ចី ១២ រាសី
|
|
123
|
+
leftOver += 30 * 60 * 12;
|
|
124
|
+
}
|
|
125
|
+
return leftOver;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const kaen = (): number => {
|
|
129
|
+
return Math.floor(leftOver() / (30 * 60));
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const lastLeftOver = (): {
|
|
133
|
+
reasey: number;
|
|
134
|
+
angsar: number;
|
|
135
|
+
libda: number;
|
|
136
|
+
} => {
|
|
137
|
+
let rs = -1;
|
|
138
|
+
if ([0, 1, 2].includes(kaen())) {
|
|
139
|
+
rs = kaen();
|
|
140
|
+
} else if ([3, 4, 5].includes(kaen())) {
|
|
141
|
+
rs = 30 * 60 * 6 - leftOver(); // R6.A0.L0 - leftover
|
|
142
|
+
} else if ([6, 7, 8].includes(kaen())) {
|
|
143
|
+
rs = leftOver() - 30 * 60 * 6; // leftover - R6.A0.L0
|
|
144
|
+
} else if ([9, 10, 11].includes(kaen())) {
|
|
145
|
+
rs = 30 * 60 * 11 + 60 * 29 + 60 - leftOver(); // R11.A29.L60 - leftover
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
reasey: Math.floor(rs / (30 * 60)),
|
|
149
|
+
angsar: Math.floor((rs % (30 * 60)) / 60),
|
|
150
|
+
libda: rs % 60,
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const khan = (): number => {
|
|
155
|
+
if (lastLeftOver().angsar >= 15) {
|
|
156
|
+
return 2 * lastLeftOver().reasey + 1;
|
|
157
|
+
} else {
|
|
158
|
+
return 2 * lastLeftOver().reasey;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const pouichalip = (): number => {
|
|
163
|
+
if (lastLeftOver().angsar >= 15) {
|
|
164
|
+
return 60 * (lastLeftOver().angsar - 15) + lastLeftOver().libda;
|
|
165
|
+
} else {
|
|
166
|
+
return 60 * lastLeftOver().angsar + lastLeftOver().libda;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const phol = (): {
|
|
171
|
+
reasey: number;
|
|
172
|
+
angsar: number;
|
|
173
|
+
libda: number;
|
|
174
|
+
} => {
|
|
175
|
+
const chhayaSun = (
|
|
176
|
+
khan: number,
|
|
177
|
+
): {
|
|
178
|
+
multiplicity: number;
|
|
179
|
+
chhaya: number;
|
|
180
|
+
} => {
|
|
181
|
+
let multiplicities = [35, 32, 27, 22, 13, 5];
|
|
182
|
+
let chhayas = [0, 35, 67, 94, 116, 129];
|
|
183
|
+
switch (khan) {
|
|
184
|
+
case 0:
|
|
185
|
+
case 1:
|
|
186
|
+
case 2:
|
|
187
|
+
case 3:
|
|
188
|
+
case 4:
|
|
189
|
+
case 5:
|
|
190
|
+
return {
|
|
191
|
+
multiplicity: multiplicities[khan],
|
|
192
|
+
chhaya: chhayas[khan],
|
|
193
|
+
};
|
|
194
|
+
default:
|
|
195
|
+
return {
|
|
196
|
+
multiplicity: 0,
|
|
197
|
+
chhaya: 134,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
let val = chhayaSun(khan());
|
|
203
|
+
let q = Math.floor((pouichalip() * val.multiplicity) / 900);
|
|
204
|
+
return {
|
|
205
|
+
reasey: 0,
|
|
206
|
+
angsar: Math.floor((q + val.chhaya) / 60),
|
|
207
|
+
libda: (q + val.chhaya) % 60,
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const sunInaugurationAsLibda = (): number => {
|
|
212
|
+
let pholAsLibda =
|
|
213
|
+
30 * 60 * phol().reasey + 60 * phol().angsar + phol().libda;
|
|
214
|
+
if (kaen() <= 5) {
|
|
215
|
+
return sunAverageAsLibda() - pholAsLibda;
|
|
216
|
+
} else {
|
|
217
|
+
return sunAverageAsLibda() + pholAsLibda;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
sunAverageAsLibda,
|
|
223
|
+
khan,
|
|
224
|
+
pouichalip,
|
|
225
|
+
phol,
|
|
226
|
+
sunInaugurationAsLibda,
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const newYearsDaySotins = (): {
|
|
231
|
+
sotin: number;
|
|
232
|
+
reasey: number;
|
|
233
|
+
angsar: number;
|
|
234
|
+
libda: number;
|
|
235
|
+
}[] => {
|
|
236
|
+
let sotins = getHas366Days(jsYear - 1)
|
|
237
|
+
? [363, 364, 365, 366]
|
|
238
|
+
: [362, 363, 364, 365]; // សុទិន
|
|
239
|
+
return sotins.map((sotin) => {
|
|
240
|
+
let sunInfo = getSunInfo(sotin);
|
|
241
|
+
return {
|
|
242
|
+
sotin: sotin,
|
|
243
|
+
reasey: Math.floor(sunInfo.sunInaugurationAsLibda() / (30 * 60)),
|
|
244
|
+
angsar: Math.floor((sunInfo.sunInaugurationAsLibda() % (30 * 60)) / 60), // អង្សាស្មើសូន្យ គីជាថ្ងៃចូលឆ្នាំ, មួយ ឬ ពីរ ថ្ងៃបន្ទាប់ជាថ្ងៃវ័នបត ហើយ ថ្ងៃចុងក្រោយគីឡើងស័ក
|
|
245
|
+
libda: sunInfo.sunInaugurationAsLibda() % 60,
|
|
246
|
+
};
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const timeOfNewYear = (): {
|
|
251
|
+
hour: number;
|
|
252
|
+
minute: number;
|
|
253
|
+
} => {
|
|
254
|
+
let sotinNewYear = newYearsDaySotins().filter(function (sotin) {
|
|
255
|
+
return sotin.angsar === 0;
|
|
256
|
+
});
|
|
257
|
+
if (sotinNewYear.length > 0) {
|
|
258
|
+
let libda = sotinNewYear[0].libda; // ២៤ ម៉ោង មាន ៦០លិប្ដា
|
|
259
|
+
let minutes = 24 * 60 - libda * 24;
|
|
260
|
+
return {
|
|
261
|
+
hour: Math.floor(minutes / 60),
|
|
262
|
+
minute: minutes % 60,
|
|
263
|
+
};
|
|
264
|
+
} else {
|
|
265
|
+
throw Error(
|
|
266
|
+
"Plugin is facing wrong calculation on new years hour. No sotin with angsar = 0",
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const info = getInfo(jsYear);
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
jsYear: jsYear,
|
|
275
|
+
harkun: info.harkun,
|
|
276
|
+
kromathopol: info.kromathopol,
|
|
277
|
+
avaman: info.avaman,
|
|
278
|
+
bodithey: info.bodithey,
|
|
279
|
+
has366Days: has366Days,
|
|
280
|
+
isAdhikameas: isAdhikameas,
|
|
281
|
+
isChantreathimeas: isChantreathimeas,
|
|
282
|
+
jesthHas30: jesthHas30(),
|
|
283
|
+
dayLerngSak: dayLerngSak,
|
|
284
|
+
lunarDateLerngSak: lunarDateLerngSak(),
|
|
285
|
+
newYearsDaySotins: newYearsDaySotins(),
|
|
286
|
+
timeOfNewYear: timeOfNewYear(),
|
|
287
|
+
};
|
|
288
|
+
}
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import dayjskh from "./dayjskh";
|
|
2
|
+
import type { PluginFunc } from "dayjs";
|
|
3
|
+
import type plugin from "../types";
|
|
4
|
+
import { constant } from "./constant";
|
|
5
|
+
|
|
6
|
+
const toKhDate: PluginFunc<plugin.toKhDate> = (o, c, d) => {
|
|
7
|
+
const proto = c.prototype;
|
|
8
|
+
proto.toKhDate = function (format?: string) {
|
|
9
|
+
const date = constant.kh.preparse(this.format());
|
|
10
|
+
return dayjskh(date).format(format);
|
|
11
|
+
};
|
|
12
|
+
proto.khNewYear = function () {
|
|
13
|
+
return dayjskh(this.year()).khmerNewYearDate(this.year());
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default toKhDate;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
|
|
16
|
+
/* Linting */
|
|
17
|
+
"noUnusedLocals": true,
|
|
18
|
+
"noUnusedParameters": false,
|
|
19
|
+
"noFallthroughCasesInSwitch": true
|
|
20
|
+
},
|
|
21
|
+
"include": ["src", "types"]
|
|
22
|
+
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// add type to support dayjs
|
|
2
|
+
import type { Dayjs, PluginFunc } from "dayjs/esm/index";
|
|
3
|
+
|
|
4
|
+
declare const plugin: PluginFunc;
|
|
5
|
+
export = plugin;
|
|
6
|
+
declare namespace plugin {
|
|
7
|
+
export interface toKhDate {
|
|
8
|
+
toKhDate(format?: string): string;
|
|
9
|
+
khNewYear(): {
|
|
10
|
+
date: dayjs.Dayjs;
|
|
11
|
+
days: number;
|
|
12
|
+
dates: { date: dayjs.Dayjs; dayName: string }[];
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
declare module "dayjs" {
|
|
18
|
+
interface Dayjs extends plugin.toKhDate {}
|
|
19
|
+
}
|