lichta 1.0.0-beta
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/README.md +245 -0
- package/dist/components/Calendar.svelte +437 -0
- package/dist/components/Calendar.svelte.d.ts +33 -0
- package/dist/components/Formatter.svelte +57 -0
- package/dist/components/Formatter.svelte.d.ts +8 -0
- package/dist/constants/earthly-branches.d.ts +31 -0
- package/dist/constants/earthly-branches.js +42 -0
- package/dist/constants/five-elements.d.ts +9 -0
- package/dist/constants/five-elements.js +9 -0
- package/dist/constants/heavenly-stems.d.ts +19 -0
- package/dist/constants/heavenly-stems.js +24 -0
- package/dist/constants/i18n.d.ts +59 -0
- package/dist/constants/i18n.js +65 -0
- package/dist/core/feng-shui.d.ts +55 -0
- package/dist/core/feng-shui.js +116 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.js +4 -0
- package/dist/core/lunar.d.ts +73 -0
- package/dist/core/lunar.js +335 -0
- package/dist/core/types.d.ts +17 -0
- package/dist/core/types.js +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +14 -0
- package/dist/utils/format.d.ts +74 -0
- package/dist/utils/format.js +150 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +2 -0
- package/package.json +94 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { HEAVENLY_STEMS } from '../constants/heavenly-stems.js';
|
|
2
|
+
import { EARTHLY_BRANCHES } from '../constants/earthly-branches.js';
|
|
3
|
+
/**
|
|
4
|
+
* Thuật toán chuyển đổi Dương lịch ↔ Âm lịch Việt Nam
|
|
5
|
+
* Dựa trên công trình của Hồ Ngọc Đức (Đại học Leipzig)
|
|
6
|
+
* Tham khảo: Jean Meeus, "Astronomical Algorithms" (1998)
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2006 Ho Ngoc Duc. All Rights Reserved.
|
|
9
|
+
* TypeScript adaptation for Lichta library.
|
|
10
|
+
*/
|
|
11
|
+
const PI = Math.PI;
|
|
12
|
+
function INT(d) {
|
|
13
|
+
return Math.floor(d);
|
|
14
|
+
}
|
|
15
|
+
// ============================================================
|
|
16
|
+
// Julian Day Number
|
|
17
|
+
// ============================================================
|
|
18
|
+
/**
|
|
19
|
+
* Chuyển ngày Gregorian sang Julian Day Number.
|
|
20
|
+
*
|
|
21
|
+
* @param dd - Ngày (1-31)
|
|
22
|
+
* @param mm - Tháng (1-12)
|
|
23
|
+
* @param yy - Năm
|
|
24
|
+
*/
|
|
25
|
+
export function jdFromDate(dd, mm, yy) {
|
|
26
|
+
const a = INT((14 - mm) / 12);
|
|
27
|
+
const y = yy + 4800 - a;
|
|
28
|
+
const m = mm + 12 * a - 3;
|
|
29
|
+
let jd = dd + INT((153 * m + 2) / 5) + 365 * y + INT(y / 4) - INT(y / 100) + INT(y / 400) - 32045;
|
|
30
|
+
if (jd < 2299161) {
|
|
31
|
+
jd = dd + INT((153 * m + 2) / 5) + 365 * y + INT(y / 4) - 32083;
|
|
32
|
+
}
|
|
33
|
+
return jd;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Chuyển Julian Day Number sang ngày Gregorian.
|
|
37
|
+
*
|
|
38
|
+
* @param jd - Julian Day Number
|
|
39
|
+
* @returns Tuple [day, month, year]
|
|
40
|
+
*/
|
|
41
|
+
export function jdToDate(jd) {
|
|
42
|
+
let a, b, c;
|
|
43
|
+
if (jd > 2299160) {
|
|
44
|
+
a = jd + 32044;
|
|
45
|
+
b = INT((4 * a + 3) / 146097);
|
|
46
|
+
c = a - INT((b * 146097) / 4);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
b = 0;
|
|
50
|
+
c = jd + 32082;
|
|
51
|
+
}
|
|
52
|
+
const d = INT((4 * c + 3) / 1461);
|
|
53
|
+
const e = c - INT((1461 * d) / 4);
|
|
54
|
+
const m = INT((5 * e + 2) / 153);
|
|
55
|
+
const day = e - INT((153 * m + 2) / 5) + 1;
|
|
56
|
+
const month = m + 3 - 12 * INT(m / 10);
|
|
57
|
+
const year = b * 100 + d - 4800 + INT(m / 10);
|
|
58
|
+
return [day, month, year];
|
|
59
|
+
}
|
|
60
|
+
// ============================================================
|
|
61
|
+
// Điểm Sóc (New Moon) — Thuật toán Hồ Ngọc Đức / Jean Meeus
|
|
62
|
+
// ============================================================
|
|
63
|
+
/**
|
|
64
|
+
* Tính thời điểm điểm Sóc (New Moon) thứ k
|
|
65
|
+
* (đo bằng số ngày Julian kể từ 1/1/4713 BC trưa UTC).
|
|
66
|
+
*
|
|
67
|
+
* k=0 tương ứng New Moon ngày 1/1/1900 13:52 UTC.
|
|
68
|
+
*
|
|
69
|
+
* @param k - Số thứ tự New Moon
|
|
70
|
+
*/
|
|
71
|
+
function NewMoon(k) {
|
|
72
|
+
const T = k / 1236.85;
|
|
73
|
+
const T2 = T * T;
|
|
74
|
+
const T3 = T2 * T;
|
|
75
|
+
const dr = PI / 180;
|
|
76
|
+
let Jd1 = 2415020.75933 + 29.53058868 * k + 0.0001178 * T2 - 0.000000155 * T3;
|
|
77
|
+
Jd1 = Jd1 + 0.00033 * Math.sin((166.56 + 132.87 * T - 0.009173 * T2) * dr);
|
|
78
|
+
// Mean anomaly của Mặt Trời
|
|
79
|
+
const M = 359.2242 + 29.10535608 * k - 0.0000333 * T2 - 0.00000347 * T3;
|
|
80
|
+
// Mean anomaly của Mặt Trăng
|
|
81
|
+
const Mpr = 306.0253 + 385.81691806 * k + 0.0107306 * T2 + 0.00001236 * T3;
|
|
82
|
+
// Argument of latitude của Mặt Trăng
|
|
83
|
+
const F = 21.2964 + 390.67050646 * k - 0.0016528 * T2 - 0.00000239 * T3;
|
|
84
|
+
// Hiệu chỉnh
|
|
85
|
+
let C1 = (0.1734 - 0.000393 * T) * Math.sin(M * dr) + 0.0021 * Math.sin(2 * dr * M);
|
|
86
|
+
C1 = C1 - 0.4068 * Math.sin(Mpr * dr) + 0.0161 * Math.sin(dr * 2 * Mpr);
|
|
87
|
+
C1 = C1 - 0.0004 * Math.sin(dr * 3 * Mpr);
|
|
88
|
+
C1 = C1 + 0.0104 * Math.sin(dr * 2 * F) - 0.0051 * Math.sin(dr * (M + Mpr));
|
|
89
|
+
C1 = C1 - 0.0074 * Math.sin(dr * (M - Mpr)) + 0.0004 * Math.sin(dr * (2 * F + M));
|
|
90
|
+
C1 = C1 - 0.0004 * Math.sin(dr * (2 * F - M)) - 0.0006 * Math.sin(dr * (2 * F + Mpr));
|
|
91
|
+
C1 = C1 + 0.001 * Math.sin(dr * (2 * F - Mpr)) + 0.0005 * Math.sin(dr * (2 * Mpr + M));
|
|
92
|
+
const JdNew = Jd1 + C1;
|
|
93
|
+
return JdNew;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Tính ngày Julian (integer) của điểm Sóc thứ k theo múi giờ.
|
|
97
|
+
*
|
|
98
|
+
* @param k - Số thứ tự New Moon
|
|
99
|
+
* @param timeZone - Múi giờ (7 = GMT+7)
|
|
100
|
+
*/
|
|
101
|
+
export function getNewMoonDay(k, timeZone) {
|
|
102
|
+
return INT(NewMoon(k) + 0.5 + timeZone / 24);
|
|
103
|
+
}
|
|
104
|
+
// ============================================================
|
|
105
|
+
// Kinh độ Mặt Trời (Sun Longitude)
|
|
106
|
+
// ============================================================
|
|
107
|
+
/**
|
|
108
|
+
* Tính kinh độ Mặt Trời tại ngày Julian cho trước.
|
|
109
|
+
* Trả về index 0-11 (mỗi 30°), dùng để xác định Trung khí.
|
|
110
|
+
*
|
|
111
|
+
* Index 9 = Đông Chí (270°-300°)
|
|
112
|
+
*
|
|
113
|
+
* @param jdn - Julian Day Number
|
|
114
|
+
* @param timeZone - Múi giờ
|
|
115
|
+
*/
|
|
116
|
+
export function getSunLongitude(jdn, timeZone) {
|
|
117
|
+
const T = (jdn - 2451545.5 - timeZone / 24) / 36525;
|
|
118
|
+
const T2 = T * T;
|
|
119
|
+
const dr = PI / 180;
|
|
120
|
+
// Mean longitude
|
|
121
|
+
const M = 357.5291 + 35999.0503 * T - 0.0001559 * T2 - 0.00000048 * T * T2;
|
|
122
|
+
// Mean longitude
|
|
123
|
+
const L0 = 280.46645 + 36000.76983 * T + 0.0003032 * T2;
|
|
124
|
+
let DL = (1.9146 - 0.004817 * T - 0.000014 * T2) * Math.sin(dr * M);
|
|
125
|
+
DL = DL + (0.019993 - 0.000101 * T) * Math.sin(dr * 2 * M) + 0.00029 * Math.sin(dr * 3 * M);
|
|
126
|
+
let L = L0 + DL;
|
|
127
|
+
// Chuẩn hóa
|
|
128
|
+
L = L - 360 * INT(L / 360);
|
|
129
|
+
return INT(L / 30);
|
|
130
|
+
}
|
|
131
|
+
// ============================================================
|
|
132
|
+
// Tháng 11 âm lịch & Tháng nhuận
|
|
133
|
+
// ============================================================
|
|
134
|
+
/**
|
|
135
|
+
* Tìm JDN của mùng 1 tháng 11 âm lịch (tháng chứa Đông Chí).
|
|
136
|
+
*/
|
|
137
|
+
function getLunarMonth11(yy, timeZone) {
|
|
138
|
+
const off = jdFromDate(31, 12, yy) - 2415021.076998695;
|
|
139
|
+
const k = INT(off / 29.530588853);
|
|
140
|
+
let nm = getNewMoonDay(k, timeZone);
|
|
141
|
+
const sunLong = getSunLongitude(nm, timeZone);
|
|
142
|
+
if (sunLong >= 9) {
|
|
143
|
+
nm = getNewMoonDay(k - 1, timeZone);
|
|
144
|
+
}
|
|
145
|
+
return nm;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Tìm offset tháng nhuận (tháng đầu tiên không chứa Trung khí
|
|
149
|
+
* giữa 2 tháng 11 âm lịch liên tiếp).
|
|
150
|
+
*/
|
|
151
|
+
function getLeapMonthOffset(a11, timeZone) {
|
|
152
|
+
const k = INT((a11 - 2415021.076998695) / 29.530588853 + 0.5);
|
|
153
|
+
let last;
|
|
154
|
+
let i = 1;
|
|
155
|
+
let arc = getSunLongitude(getNewMoonDay(k + i, timeZone), timeZone);
|
|
156
|
+
last = arc;
|
|
157
|
+
while (i < 14) {
|
|
158
|
+
i++;
|
|
159
|
+
arc = getSunLongitude(getNewMoonDay(k + i, timeZone), timeZone);
|
|
160
|
+
if (arc !== last) {
|
|
161
|
+
last = arc;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// 2 tháng liên tiếp cùng Trung khí → tháng trước đó là tháng nhuận
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return i - 1;
|
|
169
|
+
}
|
|
170
|
+
// ============================================================
|
|
171
|
+
// Can Chi helpers
|
|
172
|
+
// ============================================================
|
|
173
|
+
function getYearCanChi(lunarYear) {
|
|
174
|
+
const stemIndex = (lunarYear + 6) % 10;
|
|
175
|
+
const branchIndex = (lunarYear + 8) % 12;
|
|
176
|
+
return `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]}`;
|
|
177
|
+
}
|
|
178
|
+
function getMonthCanChiInternal(lunarMonth, lunarYear) {
|
|
179
|
+
const yearStemIndex = (lunarYear + 6) % 10;
|
|
180
|
+
const monthStemOffset = (yearStemIndex % 5) * 2 + 2;
|
|
181
|
+
const monthStemIndex = (monthStemOffset + lunarMonth - 1) % 10;
|
|
182
|
+
const monthBranchIndex = (lunarMonth + 1) % 12;
|
|
183
|
+
return `${HEAVENLY_STEMS[monthStemIndex]} ${EARTHLY_BRANCHES[monthBranchIndex]}`;
|
|
184
|
+
}
|
|
185
|
+
function getDayCanChiInternal(jd) {
|
|
186
|
+
const stemIndex = (jd + 9) % 10;
|
|
187
|
+
const branchIndex = (jd + 1) % 12;
|
|
188
|
+
return `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]}`;
|
|
189
|
+
}
|
|
190
|
+
// ============================================================
|
|
191
|
+
// LichTa — Public API
|
|
192
|
+
// ============================================================
|
|
193
|
+
export class LichTa {
|
|
194
|
+
/**
|
|
195
|
+
* Chuyển đổi ngày Dương lịch sang Âm lịch.
|
|
196
|
+
*
|
|
197
|
+
* Sử dụng thuật toán Hồ Ngọc Đức để tìm Điểm Sóc và Tiết Khí,
|
|
198
|
+
* từ đó xác định ngày, tháng, năm âm lịch tương ứng.
|
|
199
|
+
*
|
|
200
|
+
* @param day - Ngày dương lịch (1-31)
|
|
201
|
+
* @param month - Tháng dương lịch (1-12)
|
|
202
|
+
* @param year - Năm dương lịch (1800-2199)
|
|
203
|
+
* @param timeZone - Múi giờ (mặc định: 7 cho GMT+7 Việt Nam)
|
|
204
|
+
* @returns Đối tượng LunarDate chứa thông tin ngày âm lịch
|
|
205
|
+
* @throws {RangeError} Khi input ngoài phạm vi hợp lệ
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```typescript
|
|
209
|
+
* const lunar = LichTa.toLunar(10, 2, 2024);
|
|
210
|
+
* // → { day: 1, month: 1, year: 2024, isLeap: false, yearCanChi: 'Giáp Thìn' }
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
static toLunar(day, month, year, timeZone = 7) {
|
|
214
|
+
if (year < 1800 || year > 2199) {
|
|
215
|
+
throw new RangeError(`Lichta: Year must be between 1800 and 2199, got ${year}`);
|
|
216
|
+
}
|
|
217
|
+
if (month < 1 || month > 12) {
|
|
218
|
+
throw new RangeError(`Lichta: Month must be between 1 and 12, got ${month}`);
|
|
219
|
+
}
|
|
220
|
+
if (day < 1 || day > 31) {
|
|
221
|
+
throw new RangeError(`Lichta: Day must be between 1 and 31, got ${day}`);
|
|
222
|
+
}
|
|
223
|
+
const dayNumber = jdFromDate(day, month, year);
|
|
224
|
+
const k = INT((dayNumber - 2415021.076998695) / 29.530588853);
|
|
225
|
+
let monthStart = getNewMoonDay(k + 1, timeZone);
|
|
226
|
+
if (monthStart > dayNumber) {
|
|
227
|
+
monthStart = getNewMoonDay(k, timeZone);
|
|
228
|
+
}
|
|
229
|
+
let a11 = getLunarMonth11(year, timeZone);
|
|
230
|
+
let b11 = getLunarMonth11(year + 1, timeZone);
|
|
231
|
+
let lunarYear;
|
|
232
|
+
if (a11 >= monthStart) {
|
|
233
|
+
lunarYear = year;
|
|
234
|
+
a11 = getLunarMonth11(year - 1, timeZone);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
lunarYear = year + 1;
|
|
238
|
+
if (b11 <= monthStart) {
|
|
239
|
+
a11 = b11;
|
|
240
|
+
b11 = getLunarMonth11(year + 2, timeZone);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
lunarYear = year;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const diff = INT((monthStart - a11) / 29);
|
|
247
|
+
let lunarLeap = false;
|
|
248
|
+
let lunarMonth = diff + 11;
|
|
249
|
+
if (lunarMonth > 12) {
|
|
250
|
+
lunarMonth = lunarMonth - 12;
|
|
251
|
+
}
|
|
252
|
+
// Kiểm tra tháng nhuận
|
|
253
|
+
const leapMonthDiff = INT((b11 - a11) / 29) === 13 ? getLeapMonthOffset(a11, timeZone) : 0;
|
|
254
|
+
if (leapMonthDiff !== 0) {
|
|
255
|
+
if (diff === leapMonthDiff) {
|
|
256
|
+
lunarLeap = true;
|
|
257
|
+
lunarMonth = diff + 11;
|
|
258
|
+
if (lunarMonth > 12)
|
|
259
|
+
lunarMonth -= 12;
|
|
260
|
+
lunarMonth -= 1;
|
|
261
|
+
if (lunarMonth <= 0)
|
|
262
|
+
lunarMonth += 12;
|
|
263
|
+
}
|
|
264
|
+
else if (diff > leapMonthDiff) {
|
|
265
|
+
lunarMonth = diff + 11 - 1;
|
|
266
|
+
if (lunarMonth > 12)
|
|
267
|
+
lunarMonth -= 12;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const lunarDay = dayNumber - monthStart + 1;
|
|
271
|
+
const yearCanChi = getYearCanChi(lunarYear);
|
|
272
|
+
const monthCanChi = getMonthCanChiInternal(lunarMonth, lunarYear);
|
|
273
|
+
const dayCanChi = getDayCanChiInternal(dayNumber);
|
|
274
|
+
return {
|
|
275
|
+
day: lunarDay,
|
|
276
|
+
month: lunarMonth,
|
|
277
|
+
year: lunarYear,
|
|
278
|
+
isLeap: lunarLeap,
|
|
279
|
+
jd: dayNumber,
|
|
280
|
+
dayCanChi,
|
|
281
|
+
monthCanChi,
|
|
282
|
+
yearCanChi,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Chuyển đổi ngày Âm lịch sang Dương lịch.
|
|
287
|
+
*
|
|
288
|
+
* @param lunarDay - Ngày âm lịch
|
|
289
|
+
* @param lunarMonth - Tháng âm lịch
|
|
290
|
+
* @param lunarYear - Năm âm lịch
|
|
291
|
+
* @param isLeap - Có phải tháng nhuận không
|
|
292
|
+
* @param timeZone - Múi giờ (mặc định: 7 cho GMT+7 Việt Nam)
|
|
293
|
+
* @returns Đối tượng SolarDate
|
|
294
|
+
* @throws {RangeError} Khi năm ngoài phạm vi 1800-2199
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```typescript
|
|
298
|
+
* const solar = LichTa.toSolar(1, 1, 2024, false);
|
|
299
|
+
* // → { day: 10, month: 2, year: 2024 }
|
|
300
|
+
* ```
|
|
301
|
+
*/
|
|
302
|
+
static toSolar(lunarDay, lunarMonth, lunarYear, isLeap = false, timeZone = 7) {
|
|
303
|
+
if (lunarYear < 1800 || lunarYear > 2199) {
|
|
304
|
+
throw new RangeError(`Lichta: Year must be between 1800 and 2199, got ${lunarYear}`);
|
|
305
|
+
}
|
|
306
|
+
let a11, b11;
|
|
307
|
+
if (lunarMonth < 11) {
|
|
308
|
+
a11 = getLunarMonth11(lunarYear - 1, timeZone);
|
|
309
|
+
b11 = getLunarMonth11(lunarYear, timeZone);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
a11 = getLunarMonth11(lunarYear, timeZone);
|
|
313
|
+
b11 = getLunarMonth11(lunarYear + 1, timeZone);
|
|
314
|
+
}
|
|
315
|
+
const k = INT(0.5 + (a11 - 2415021.076998695) / 29.530588853);
|
|
316
|
+
let off = lunarMonth - 11;
|
|
317
|
+
if (off < 0) {
|
|
318
|
+
off += 12;
|
|
319
|
+
}
|
|
320
|
+
// Xử lý tháng nhuận
|
|
321
|
+
if (INT((b11 - a11) / 29) === 13) {
|
|
322
|
+
const leapOff = getLeapMonthOffset(a11, timeZone);
|
|
323
|
+
if (off >= leapOff) {
|
|
324
|
+
off += 1;
|
|
325
|
+
if (isLeap) {
|
|
326
|
+
// isLeap flag đã đúng vị trí, không cần thêm offset
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const nm = getNewMoonDay(k + off, timeZone);
|
|
331
|
+
const jd = nm + lunarDay - 1;
|
|
332
|
+
const [day, month, year] = jdToDate(jd);
|
|
333
|
+
return { day, month, year };
|
|
334
|
+
}
|
|
335
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Kết quả chuyển đổi sang Âm lịch */
|
|
2
|
+
export interface LunarDate {
|
|
3
|
+
day: number;
|
|
4
|
+
month: number;
|
|
5
|
+
year: number;
|
|
6
|
+
isLeap: boolean;
|
|
7
|
+
jd: number;
|
|
8
|
+
dayCanChi?: string;
|
|
9
|
+
monthCanChi?: string;
|
|
10
|
+
yearCanChi?: string;
|
|
11
|
+
}
|
|
12
|
+
/** Kết quả chuyển đổi sang Dương lịch */
|
|
13
|
+
export interface SolarDate {
|
|
14
|
+
day: number;
|
|
15
|
+
month: number;
|
|
16
|
+
year: number;
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { LichTa, jdFromDate, jdToDate } from './core/lunar.js';
|
|
2
|
+
export type { LunarDate, SolarDate } from './core/types.js';
|
|
3
|
+
export { getYearDetails, getDayCanChi, getMonthCanChi, getHourCanChi, getAuspiciousHours, } from './core/feng-shui.js';
|
|
4
|
+
export { formatLunarDate, formatTraditional, getMonthName, getDayName } from './utils/format.js';
|
|
5
|
+
export { t, getZodiacAnimal } from './constants/i18n.js';
|
|
6
|
+
export type { Locale } from './constants/i18n.js';
|
|
7
|
+
export { default as Formatter } from './components/Formatter.svelte';
|
|
8
|
+
export { default as Calendar } from './components/Calendar.svelte';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Lichta — Public API (Root Entry Point)
|
|
3
|
+
// ============================================================
|
|
4
|
+
// Xuất bản phần lõi TypeScript (Cho những ai chỉ muốn dùng logic toán học)
|
|
5
|
+
export { LichTa, jdFromDate, jdToDate } from './core/lunar.js';
|
|
6
|
+
// Xuất bản phần phong thủy
|
|
7
|
+
export { getYearDetails, getDayCanChi, getMonthCanChi, getHourCanChi, getAuspiciousHours, } from './core/feng-shui.js';
|
|
8
|
+
// Xuất bản phần format/tiện ích
|
|
9
|
+
export { formatLunarDate, formatTraditional, getMonthName, getDayName } from './utils/format.js';
|
|
10
|
+
// Xuất bản phần i18n
|
|
11
|
+
export { t, getZodiacAnimal } from './constants/i18n.js';
|
|
12
|
+
// Xuất bản phần Svelte Component (Cho những ai muốn dùng UI ăn liền)
|
|
13
|
+
export { default as Formatter } from './components/Formatter.svelte';
|
|
14
|
+
export { default as Calendar } from './components/Calendar.svelte';
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { LunarDate } from '../core/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Lấy tên tháng âm lịch dạng chữ truyền thống.
|
|
4
|
+
*
|
|
5
|
+
* @param month - Tháng âm lịch (1-12)
|
|
6
|
+
* @returns Tên tháng (ví dụ: 1 → "Giêng", 12 → "Chạp")
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* getMonthName(1); // "Giêng"
|
|
11
|
+
* getMonthName(12); // "Chạp"
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function getMonthName(month: number): string;
|
|
15
|
+
/**
|
|
16
|
+
* Lấy tên ngày âm lịch theo cách gọi truyền thống Việt Nam.
|
|
17
|
+
*
|
|
18
|
+
* - 1-10: "Mùng Một", "Mùng Hai", ..., "Mùng Mười"
|
|
19
|
+
* - 11-20: "Mười Một", ..., "Hai Mươi"
|
|
20
|
+
* - 21-30: "Hăm Mốt", "Hăm Hai", ..., "Ba Mươi"
|
|
21
|
+
*
|
|
22
|
+
* @param day - Ngày âm lịch (1-30)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* getDayName(1); // "Mùng Một"
|
|
27
|
+
* getDayName(15); // "Rằm"
|
|
28
|
+
* getDayName(30); // "Ba Mươi"
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function getDayName(day: number): string;
|
|
32
|
+
/**
|
|
33
|
+
* Format ngày âm lịch theo pattern.
|
|
34
|
+
*
|
|
35
|
+
* **Patterns hỗ trợ:**
|
|
36
|
+
* | Token | Mô tả | Ví dụ |
|
|
37
|
+
* |-------|------------------------------------------|----------------|
|
|
38
|
+
* | `dd` | Ngày 2 chữ số | 01, 15, 30 |
|
|
39
|
+
* | `d` | Ngày | 1, 15, 30 |
|
|
40
|
+
* | `MM` | Tháng 2 chữ số | 01, 12 |
|
|
41
|
+
* | `M` | Tháng | 1, 12 |
|
|
42
|
+
* | `yyyy`| Năm 4 chữ số | 2024 |
|
|
43
|
+
* | `yy` | Năm 2 chữ số cuối | 24 |
|
|
44
|
+
* | `L` | "Nhuận" nếu tháng nhuận, "" nếu không | Nhuận |
|
|
45
|
+
* | `CC` | Can Chi năm | Giáp Thìn |
|
|
46
|
+
* | `DC` | Can Chi ngày | Giáp Tý |
|
|
47
|
+
* | `MC` | Can Chi tháng | Bính Dần |
|
|
48
|
+
*
|
|
49
|
+
* @param lunar - Đối tượng LunarDate
|
|
50
|
+
* @param pattern - Chuỗi pattern
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* formatLunarDate(lunar, 'dd/MM/yyyy');
|
|
55
|
+
* // → "01/01/2024"
|
|
56
|
+
*
|
|
57
|
+
* formatLunarDate(lunar, 'Ngày d tháng M năm CC');
|
|
58
|
+
* // → "Ngày 1 tháng 1 năm Giáp Thìn"
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function formatLunarDate(lunar: LunarDate, pattern: string): string;
|
|
62
|
+
/**
|
|
63
|
+
* Format ngày âm lịch theo kiểu truyền thống Việt Nam.
|
|
64
|
+
*
|
|
65
|
+
* @param lunar - Đối tượng LunarDate
|
|
66
|
+
* @returns Chuỗi truyền thống (ví dụ: "Mùng Một tháng Giêng năm Giáp Thìn")
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* formatTraditional(lunar);
|
|
71
|
+
* // → "Mùng Một tháng Giêng năm Giáp Thìn"
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function formatTraditional(lunar: LunarDate): string;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Tên tháng & ngày truyền thống
|
|
3
|
+
// ============================================================
|
|
4
|
+
/** Tên tháng âm lịch truyền thống */
|
|
5
|
+
const MONTH_NAMES = [
|
|
6
|
+
'Giêng', 'Hai', 'Ba', 'Tư', 'Năm', 'Sáu',
|
|
7
|
+
'Bảy', 'Tám', 'Chín', 'Mười', 'Một', 'Chạp',
|
|
8
|
+
];
|
|
9
|
+
/** Tên số đếm truyền thống */
|
|
10
|
+
const DAY_UNITS = [
|
|
11
|
+
'', 'Một', 'Hai', 'Ba', 'Bốn', 'Năm',
|
|
12
|
+
'Sáu', 'Bảy', 'Tám', 'Chín', 'Mười',
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Lấy tên tháng âm lịch dạng chữ truyền thống.
|
|
16
|
+
*
|
|
17
|
+
* @param month - Tháng âm lịch (1-12)
|
|
18
|
+
* @returns Tên tháng (ví dụ: 1 → "Giêng", 12 → "Chạp")
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* getMonthName(1); // "Giêng"
|
|
23
|
+
* getMonthName(12); // "Chạp"
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function getMonthName(month) {
|
|
27
|
+
if (month < 1 || month > 12) {
|
|
28
|
+
throw new RangeError(`Lichta: Month must be between 1 and 12, got ${month}`);
|
|
29
|
+
}
|
|
30
|
+
return MONTH_NAMES[month - 1];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Lấy tên ngày âm lịch theo cách gọi truyền thống Việt Nam.
|
|
34
|
+
*
|
|
35
|
+
* - 1-10: "Mùng Một", "Mùng Hai", ..., "Mùng Mười"
|
|
36
|
+
* - 11-20: "Mười Một", ..., "Hai Mươi"
|
|
37
|
+
* - 21-30: "Hăm Mốt", "Hăm Hai", ..., "Ba Mươi"
|
|
38
|
+
*
|
|
39
|
+
* @param day - Ngày âm lịch (1-30)
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* getDayName(1); // "Mùng Một"
|
|
44
|
+
* getDayName(15); // "Rằm"
|
|
45
|
+
* getDayName(30); // "Ba Mươi"
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function getDayName(day) {
|
|
49
|
+
if (day < 1 || day > 30) {
|
|
50
|
+
throw new RangeError(`Lichta: Day must be between 1 and 30, got ${day}`);
|
|
51
|
+
}
|
|
52
|
+
// Ngày Rằm
|
|
53
|
+
if (day === 15)
|
|
54
|
+
return 'Rằm';
|
|
55
|
+
// Mùng 1-10
|
|
56
|
+
if (day <= 10) {
|
|
57
|
+
return `Mùng ${DAY_UNITS[day]}`;
|
|
58
|
+
}
|
|
59
|
+
// 11-19
|
|
60
|
+
if (day < 20) {
|
|
61
|
+
if (day === 11)
|
|
62
|
+
return 'Mười Một';
|
|
63
|
+
if (day === 14)
|
|
64
|
+
return 'Mười Bốn';
|
|
65
|
+
return `Mười ${DAY_UNITS[day - 10]}`;
|
|
66
|
+
}
|
|
67
|
+
// 20
|
|
68
|
+
if (day === 20)
|
|
69
|
+
return 'Hai Mươi';
|
|
70
|
+
// 21-29
|
|
71
|
+
if (day < 30) {
|
|
72
|
+
if (day === 21)
|
|
73
|
+
return 'Hăm Mốt';
|
|
74
|
+
if (day === 24)
|
|
75
|
+
return 'Hăm Tư';
|
|
76
|
+
if (day === 25)
|
|
77
|
+
return 'Hăm Lăm';
|
|
78
|
+
return `Hăm ${DAY_UNITS[day - 20]}`;
|
|
79
|
+
}
|
|
80
|
+
// 30
|
|
81
|
+
return 'Ba Mươi';
|
|
82
|
+
}
|
|
83
|
+
// ============================================================
|
|
84
|
+
// Format functions
|
|
85
|
+
// ============================================================
|
|
86
|
+
/**
|
|
87
|
+
* Format ngày âm lịch theo pattern.
|
|
88
|
+
*
|
|
89
|
+
* **Patterns hỗ trợ:**
|
|
90
|
+
* | Token | Mô tả | Ví dụ |
|
|
91
|
+
* |-------|------------------------------------------|----------------|
|
|
92
|
+
* | `dd` | Ngày 2 chữ số | 01, 15, 30 |
|
|
93
|
+
* | `d` | Ngày | 1, 15, 30 |
|
|
94
|
+
* | `MM` | Tháng 2 chữ số | 01, 12 |
|
|
95
|
+
* | `M` | Tháng | 1, 12 |
|
|
96
|
+
* | `yyyy`| Năm 4 chữ số | 2024 |
|
|
97
|
+
* | `yy` | Năm 2 chữ số cuối | 24 |
|
|
98
|
+
* | `L` | "Nhuận" nếu tháng nhuận, "" nếu không | Nhuận |
|
|
99
|
+
* | `CC` | Can Chi năm | Giáp Thìn |
|
|
100
|
+
* | `DC` | Can Chi ngày | Giáp Tý |
|
|
101
|
+
* | `MC` | Can Chi tháng | Bính Dần |
|
|
102
|
+
*
|
|
103
|
+
* @param lunar - Đối tượng LunarDate
|
|
104
|
+
* @param pattern - Chuỗi pattern
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* formatLunarDate(lunar, 'dd/MM/yyyy');
|
|
109
|
+
* // → "01/01/2024"
|
|
110
|
+
*
|
|
111
|
+
* formatLunarDate(lunar, 'Ngày d tháng M năm CC');
|
|
112
|
+
* // → "Ngày 1 tháng 1 năm Giáp Thìn"
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export function formatLunarDate(lunar, pattern) {
|
|
116
|
+
let result = pattern;
|
|
117
|
+
// Thay thế theo thứ tự dài → ngắn để tránh xung đột (yyyy trước yy, dd trước d, MM trước M)
|
|
118
|
+
result = result.replace(/yyyy/g, String(lunar.year));
|
|
119
|
+
result = result.replace(/yy/g, String(lunar.year).slice(-2));
|
|
120
|
+
result = result.replace(/dd/g, String(lunar.day).padStart(2, '0'));
|
|
121
|
+
result = result.replace(/MM/g, String(lunar.month).padStart(2, '0'));
|
|
122
|
+
result = result.replace(/CC/g, lunar.yearCanChi ?? '');
|
|
123
|
+
result = result.replace(/DC/g, lunar.dayCanChi ?? '');
|
|
124
|
+
result = result.replace(/MC/g, lunar.monthCanChi ?? '');
|
|
125
|
+
result = result.replace(/L/g, lunar.isLeap ? 'Nhuận' : '');
|
|
126
|
+
// Thay d và M cuối cùng (sau khi dd, MM đã được xử lý, tránh double-replace)
|
|
127
|
+
// Dùng regex negative lookbehind để không match các token đã được thay
|
|
128
|
+
result = result.replace(/(?<![0-9])d(?![0-9d])/g, String(lunar.day));
|
|
129
|
+
result = result.replace(/(?<![0-9])M(?![0-9MC])/g, String(lunar.month));
|
|
130
|
+
return result.trim();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Format ngày âm lịch theo kiểu truyền thống Việt Nam.
|
|
134
|
+
*
|
|
135
|
+
* @param lunar - Đối tượng LunarDate
|
|
136
|
+
* @returns Chuỗi truyền thống (ví dụ: "Mùng Một tháng Giêng năm Giáp Thìn")
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* formatTraditional(lunar);
|
|
141
|
+
* // → "Mùng Một tháng Giêng năm Giáp Thìn"
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export function formatTraditional(lunar) {
|
|
145
|
+
const dayName = getDayName(lunar.day);
|
|
146
|
+
const monthName = getMonthName(lunar.month);
|
|
147
|
+
const leapSuffix = lunar.isLeap ? ' Nhuận' : '';
|
|
148
|
+
const yearCanChi = lunar.yearCanChi ?? '';
|
|
149
|
+
return `${dayName} tháng ${monthName}${leapSuffix} năm ${yearCanChi}`.trim();
|
|
150
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { formatLunarDate, formatTraditional, getMonthName, getDayName } from './format.js';
|