@lichta/core 2.1.0 → 2.2.1
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 +104 -19
- package/dist/index.d.mts +385 -62
- package/dist/index.d.ts +385 -62
- package/dist/index.js +465 -47
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +436 -47
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/styles/calendar-base.css +14 -0
package/dist/index.mjs
CHANGED
|
@@ -11,9 +11,6 @@ var HEAVENLY_STEMS = [
|
|
|
11
11
|
"Nh\xE2m",
|
|
12
12
|
"Qu\xFD"
|
|
13
13
|
];
|
|
14
|
-
function getStemWeight(index) {
|
|
15
|
-
return Math.floor(index / 2) + 1;
|
|
16
|
-
}
|
|
17
14
|
|
|
18
15
|
// src/constants/earthly-branches.ts
|
|
19
16
|
var EARTHLY_BRANCHES = [
|
|
@@ -30,12 +27,8 @@ var EARTHLY_BRANCHES = [
|
|
|
30
27
|
"Tu\u1EA5t",
|
|
31
28
|
"H\u1EE3i"
|
|
32
29
|
];
|
|
33
|
-
function getBranchWeight(index) {
|
|
34
|
-
const normalizedIndex = index % 6;
|
|
35
|
-
return Math.floor(normalizedIndex / 2);
|
|
36
|
-
}
|
|
37
30
|
|
|
38
|
-
// src/core/
|
|
31
|
+
// src/core/astronomical.ts
|
|
39
32
|
var PI = Math.PI;
|
|
40
33
|
function INT(d) {
|
|
41
34
|
return Math.floor(d);
|
|
@@ -91,7 +84,7 @@ function NewMoon(k) {
|
|
|
91
84
|
function getNewMoonDay(k, timeZone) {
|
|
92
85
|
return INT(NewMoon(k) + 0.5 + timeZone / 24);
|
|
93
86
|
}
|
|
94
|
-
function
|
|
87
|
+
function sunLongitudeDegrees(jdn, timeZone) {
|
|
95
88
|
const T = (jdn - 24515455e-1 - timeZone / 24) / 36525;
|
|
96
89
|
const T2 = T * T;
|
|
97
90
|
const dr = PI / 180;
|
|
@@ -101,11 +94,22 @@ function getSunLongitude(jdn, timeZone) {
|
|
|
101
94
|
DL = DL + (0.019993 - 101e-6 * T) * Math.sin(dr * 2 * M) + 29e-5 * Math.sin(dr * 3 * M);
|
|
102
95
|
let L = L0 + DL;
|
|
103
96
|
L = L - 360 * INT(L / 360);
|
|
104
|
-
return
|
|
97
|
+
return L;
|
|
98
|
+
}
|
|
99
|
+
function getSunLongitude(jdn, timeZone) {
|
|
100
|
+
return INT(sunLongitudeDegrees(jdn, timeZone) / 30);
|
|
101
|
+
}
|
|
102
|
+
function getSolarTermIndex(jdn, timeZone) {
|
|
103
|
+
return INT(sunLongitudeDegrees(jdn, timeZone) / 15);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/core/calendar-engine.ts
|
|
107
|
+
function INT2(d) {
|
|
108
|
+
return Math.floor(d);
|
|
105
109
|
}
|
|
106
110
|
function getLunarMonth11(yy, timeZone) {
|
|
107
111
|
const off = jdFromDate(31, 12, yy) - 2415021076998695e-9;
|
|
108
|
-
const k =
|
|
112
|
+
const k = INT2(off / 29.530588853);
|
|
109
113
|
let nm = getNewMoonDay(k, timeZone);
|
|
110
114
|
const sunLong = getSunLongitude(nm, timeZone);
|
|
111
115
|
if (sunLong >= 9) {
|
|
@@ -114,7 +118,7 @@ function getLunarMonth11(yy, timeZone) {
|
|
|
114
118
|
return nm;
|
|
115
119
|
}
|
|
116
120
|
function getLeapMonthOffset(a11, timeZone) {
|
|
117
|
-
const k =
|
|
121
|
+
const k = INT2((a11 - 2415021076998695e-9) / 29.530588853 + 0.5);
|
|
118
122
|
let last;
|
|
119
123
|
let i = 1;
|
|
120
124
|
let arc = getSunLongitude(getNewMoonDay(k + i, timeZone), timeZone);
|
|
@@ -178,7 +182,7 @@ var LichTa = class {
|
|
|
178
182
|
throw new RangeError(`Lichta: Day must be between 1 and 31, got ${day}`);
|
|
179
183
|
}
|
|
180
184
|
const dayNumber = jdFromDate(day, month, year);
|
|
181
|
-
const k =
|
|
185
|
+
const k = INT2((dayNumber - 2415021076998695e-9) / 29.530588853);
|
|
182
186
|
let monthStart = getNewMoonDay(k + 1, timeZone);
|
|
183
187
|
if (monthStart > dayNumber) {
|
|
184
188
|
monthStart = getNewMoonDay(k, timeZone);
|
|
@@ -194,7 +198,7 @@ var LichTa = class {
|
|
|
194
198
|
b11 = getLunarMonth11(year + 1, timeZone);
|
|
195
199
|
}
|
|
196
200
|
const lunarDay = dayNumber - monthStart + 1;
|
|
197
|
-
const diff =
|
|
201
|
+
const diff = INT2((monthStart - a11) / 29);
|
|
198
202
|
let lunarLeap = false;
|
|
199
203
|
let lunarMonth = diff + 11;
|
|
200
204
|
if (b11 - a11 > 365) {
|
|
@@ -255,7 +259,7 @@ var LichTa = class {
|
|
|
255
259
|
a11 = getLunarMonth11(lunarYear, timeZone);
|
|
256
260
|
b11 = getLunarMonth11(lunarYear + 1, timeZone);
|
|
257
261
|
}
|
|
258
|
-
const k =
|
|
262
|
+
const k = INT2(0.5 + (a11 - 2415021076998695e-9) / 29.530588853);
|
|
259
263
|
let off = lunarMonth - 11;
|
|
260
264
|
if (off < 0) {
|
|
261
265
|
off += 12;
|
|
@@ -279,9 +283,6 @@ var LichTa = class {
|
|
|
279
283
|
}
|
|
280
284
|
};
|
|
281
285
|
|
|
282
|
-
// src/constants/five-elements.ts
|
|
283
|
-
var FIVE_ELEMENTS = ["Kim", "M\u1ED9c", "Th\u1EE7y", "H\u1ECFa", "Th\u1ED5"];
|
|
284
|
-
|
|
285
286
|
// src/constants/i18n.ts
|
|
286
287
|
var translations = {
|
|
287
288
|
vi: {
|
|
@@ -297,7 +298,40 @@ var translations = {
|
|
|
297
298
|
leapLabel: "Nhu\u1EADn",
|
|
298
299
|
yearLabel: "N\u0103m",
|
|
299
300
|
monthLabel: "Th\xE1ng",
|
|
300
|
-
destiny: "M\u1EC7nh"
|
|
301
|
+
destiny: "M\u1EC7nh",
|
|
302
|
+
// Thứ tự bắt đầu từ Xuân Phân (kinh độ Mặt Trời 0°), xem getSolarTermIndex trong lunar.ts
|
|
303
|
+
solarTermNames: [
|
|
304
|
+
"Xu\xE2n Ph\xE2n",
|
|
305
|
+
"Thanh Minh",
|
|
306
|
+
"C\u1ED1c V\u0169",
|
|
307
|
+
"L\u1EADp H\u1EA1",
|
|
308
|
+
"Ti\u1EC3u M\xE3n",
|
|
309
|
+
"Mang Ch\u1EE7ng",
|
|
310
|
+
"H\u1EA1 Ch\xED",
|
|
311
|
+
"Ti\u1EC3u Th\u1EED",
|
|
312
|
+
"\u0110\u1EA1i Th\u1EED",
|
|
313
|
+
"L\u1EADp Thu",
|
|
314
|
+
"X\u1EED Th\u1EED",
|
|
315
|
+
"B\u1EA1ch L\u1ED9",
|
|
316
|
+
"Thu Ph\xE2n",
|
|
317
|
+
"H\xE0n L\u1ED9",
|
|
318
|
+
"S\u01B0\u01A1ng Gi\xE1ng",
|
|
319
|
+
"L\u1EADp \u0110\xF4ng",
|
|
320
|
+
"Ti\u1EC3u Tuy\u1EBFt",
|
|
321
|
+
"\u0110\u1EA1i Tuy\u1EBFt",
|
|
322
|
+
"\u0110\xF4ng Ch\xED",
|
|
323
|
+
"Ti\u1EC3u H\xE0n",
|
|
324
|
+
"\u0110\u1EA1i H\xE0n",
|
|
325
|
+
"L\u1EADp Xu\xE2n",
|
|
326
|
+
"V\u0169 Th\u1EE7y",
|
|
327
|
+
"Kinh Tr\u1EADp"
|
|
328
|
+
],
|
|
329
|
+
// Thứ tự bắt đầu từ Kiến (0), xem getTrucIndex trong feng-shui.ts
|
|
330
|
+
trucNames: ["Ki\u1EBFn", "Tr\u1EEB", "M\xE3n", "B\xECnh", "\u0110\u1ECBnh", "Ch\u1EA5p", "Ph\xE1", "Nguy", "Th\xE0nh", "Thu", "Khai", "B\u1EBF"],
|
|
331
|
+
// Thứ tự: sinh, được sinh, khắc, bị khắc, hòa — xem getElementRelationIndex trong feng-shui.ts
|
|
332
|
+
elementRelationNames: ["T\u01B0\u01A1ng sinh", "\u0110\u01B0\u1EE3c sinh", "T\u01B0\u01A1ng kh\u1EAFc", "B\u1ECB kh\u1EAFc", "T\u01B0\u01A1ng h\xF2a"],
|
|
333
|
+
// Thứ tự: xấu, trung bình, tốt — xem getTrucQualityIndex trong feng-shui.ts
|
|
334
|
+
trucQualityNames: ["X\u1EA5u", "Trung b\xECnh", "T\u1ED1t"]
|
|
301
335
|
},
|
|
302
336
|
en: {
|
|
303
337
|
heavenlyStems: ["Gi\xE1p", "\u1EA4t", "B\xEDnh", "\u0110inh", "M\u1EADu", "K\u1EF7", "Canh", "T\xE2n", "Nh\xE2m", "Qu\xFD"],
|
|
@@ -312,7 +346,36 @@ var translations = {
|
|
|
312
346
|
leapLabel: "Leap",
|
|
313
347
|
yearLabel: "Year",
|
|
314
348
|
monthLabel: "Month",
|
|
315
|
-
destiny: "Destiny"
|
|
349
|
+
destiny: "Destiny",
|
|
350
|
+
solarTermNames: [
|
|
351
|
+
"Spring Equinox",
|
|
352
|
+
"Clear and Bright",
|
|
353
|
+
"Grain Rain",
|
|
354
|
+
"Start of Summer",
|
|
355
|
+
"Grain Full",
|
|
356
|
+
"Grain in Ear",
|
|
357
|
+
"Summer Solstice",
|
|
358
|
+
"Minor Heat",
|
|
359
|
+
"Major Heat",
|
|
360
|
+
"Start of Autumn",
|
|
361
|
+
"End of Heat",
|
|
362
|
+
"White Dew",
|
|
363
|
+
"Autumn Equinox",
|
|
364
|
+
"Cold Dew",
|
|
365
|
+
"Frost's Descent",
|
|
366
|
+
"Start of Winter",
|
|
367
|
+
"Minor Snow",
|
|
368
|
+
"Major Snow",
|
|
369
|
+
"Winter Solstice",
|
|
370
|
+
"Minor Cold",
|
|
371
|
+
"Major Cold",
|
|
372
|
+
"Start of Spring",
|
|
373
|
+
"Rain Water",
|
|
374
|
+
"Awakening of Insects"
|
|
375
|
+
],
|
|
376
|
+
trucNames: ["Ki\u1EBFn", "Tr\u1EEB", "M\xE3n", "B\xECnh", "\u0110\u1ECBnh", "Ch\u1EA5p", "Ph\xE1", "Nguy", "Th\xE0nh", "Thu", "Khai", "B\u1EBF"],
|
|
377
|
+
elementRelationNames: ["Generates", "Generated By", "Overcomes", "Overcome By", "Same Element"],
|
|
378
|
+
trucQualityNames: ["Bad", "Neutral", "Good"]
|
|
316
379
|
},
|
|
317
380
|
ja: {
|
|
318
381
|
heavenlyStems: ["\u7532", "\u4E59", "\u4E19", "\u4E01", "\u620A", "\u5DF1", "\u5E9A", "\u8F9B", "\u58EC", "\u7678"],
|
|
@@ -327,7 +390,36 @@ var translations = {
|
|
|
327
390
|
leapLabel: "\u958F",
|
|
328
391
|
yearLabel: "\u5E74",
|
|
329
392
|
monthLabel: "\u6708",
|
|
330
|
-
destiny: "\u547D"
|
|
393
|
+
destiny: "\u547D",
|
|
394
|
+
solarTermNames: [
|
|
395
|
+
"\u6625\u5206",
|
|
396
|
+
"\u6E05\u660E",
|
|
397
|
+
"\u7A40\u96E8",
|
|
398
|
+
"\u7ACB\u590F",
|
|
399
|
+
"\u5C0F\u6E80",
|
|
400
|
+
"\u8292\u7A2E",
|
|
401
|
+
"\u590F\u81F3",
|
|
402
|
+
"\u5C0F\u6691",
|
|
403
|
+
"\u5927\u6691",
|
|
404
|
+
"\u7ACB\u79CB",
|
|
405
|
+
"\u51E6\u6691",
|
|
406
|
+
"\u767D\u9732",
|
|
407
|
+
"\u79CB\u5206",
|
|
408
|
+
"\u5BD2\u9732",
|
|
409
|
+
"\u971C\u964D",
|
|
410
|
+
"\u7ACB\u51AC",
|
|
411
|
+
"\u5C0F\u96EA",
|
|
412
|
+
"\u5927\u96EA",
|
|
413
|
+
"\u51AC\u81F3",
|
|
414
|
+
"\u5C0F\u5BD2",
|
|
415
|
+
"\u5927\u5BD2",
|
|
416
|
+
"\u7ACB\u6625",
|
|
417
|
+
"\u96E8\u6C34",
|
|
418
|
+
"\u5553\u87C4"
|
|
419
|
+
],
|
|
420
|
+
trucNames: ["\u5EFA", "\u9664", "\u6E80", "\u5E73", "\u5B9A", "\u57F7", "\u7834", "\u5371", "\u6210", "\u53CE", "\u958B", "\u9589"],
|
|
421
|
+
elementRelationNames: ["\u76F8\u751F", "\u88AB\u751F", "\u76F8\u514B", "\u88AB\u514B", "\u6BD4\u548C"],
|
|
422
|
+
trucQualityNames: ["\u51F6", "\u666E\u901A", "\u5409"]
|
|
331
423
|
},
|
|
332
424
|
ko: {
|
|
333
425
|
heavenlyStems: ["\uAC11", "\uC744", "\uBCD1", "\uC815", "\uBB34", "\uAE30", "\uACBD", "\uC2E0", "\uC784", "\uACC4"],
|
|
@@ -342,7 +434,36 @@ var translations = {
|
|
|
342
434
|
leapLabel: "\uC724",
|
|
343
435
|
yearLabel: "\uB144",
|
|
344
436
|
monthLabel: "\uC6D4",
|
|
345
|
-
destiny: "\uBA85"
|
|
437
|
+
destiny: "\uBA85",
|
|
438
|
+
solarTermNames: [
|
|
439
|
+
"\uCD98\uBD84",
|
|
440
|
+
"\uCCAD\uBA85",
|
|
441
|
+
"\uACE1\uC6B0",
|
|
442
|
+
"\uC785\uD558",
|
|
443
|
+
"\uC18C\uB9CC",
|
|
444
|
+
"\uB9DD\uC885",
|
|
445
|
+
"\uD558\uC9C0",
|
|
446
|
+
"\uC18C\uC11C",
|
|
447
|
+
"\uB300\uC11C",
|
|
448
|
+
"\uC785\uCD94",
|
|
449
|
+
"\uCC98\uC11C",
|
|
450
|
+
"\uBC31\uB85C",
|
|
451
|
+
"\uCD94\uBD84",
|
|
452
|
+
"\uD55C\uB85C",
|
|
453
|
+
"\uC0C1\uAC15",
|
|
454
|
+
"\uC785\uB3D9",
|
|
455
|
+
"\uC18C\uC124",
|
|
456
|
+
"\uB300\uC124",
|
|
457
|
+
"\uB3D9\uC9C0",
|
|
458
|
+
"\uC18C\uD55C",
|
|
459
|
+
"\uB300\uD55C",
|
|
460
|
+
"\uC785\uCD98",
|
|
461
|
+
"\uC6B0\uC218",
|
|
462
|
+
"\uACBD\uCE69"
|
|
463
|
+
],
|
|
464
|
+
trucNames: ["\uAC74", "\uC81C", "\uB9CC", "\uD3C9", "\uC815", "\uC9D1", "\uD30C", "\uC704", "\uC131", "\uC218", "\uAC1C", "\uD3D0"],
|
|
465
|
+
elementRelationNames: ["\uC0C1\uC0DD", "\uD53C\uC0DD", "\uC0C1\uADF9", "\uD53C\uADF9", "\uBE44\uD654"],
|
|
466
|
+
trucQualityNames: ["\uD749", "\uBCF4\uD1B5", "\uAE38"]
|
|
346
467
|
}
|
|
347
468
|
};
|
|
348
469
|
function t(locale) {
|
|
@@ -351,28 +472,12 @@ function t(locale) {
|
|
|
351
472
|
function getZodiacAnimal(branchIndex, locale = "vi") {
|
|
352
473
|
return translations[locale].zodiacAnimals[branchIndex % 12];
|
|
353
474
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
return (n % m + m) % m;
|
|
358
|
-
}
|
|
359
|
-
function getYearDetails(year) {
|
|
360
|
-
const stemIndex = mod(year - 4, 10);
|
|
361
|
-
const branchIndex = mod(year - 4, 12);
|
|
362
|
-
const stemWeight = getStemWeight(stemIndex);
|
|
363
|
-
const branchWeight = getBranchWeight(branchIndex);
|
|
364
|
-
let elementValue = stemWeight + branchWeight;
|
|
365
|
-
if (elementValue > 5) {
|
|
366
|
-
elementValue -= 5;
|
|
367
|
-
}
|
|
368
|
-
const elementIndex = elementValue - 1;
|
|
369
|
-
return {
|
|
370
|
-
can: HEAVENLY_STEMS[stemIndex],
|
|
371
|
-
chi: EARTHLY_BRANCHES[branchIndex],
|
|
372
|
-
menh: FIVE_ELEMENTS[elementIndex],
|
|
373
|
-
fullString: `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]} - M\u1EC7nh ${FIVE_ELEMENTS[elementIndex]}`
|
|
374
|
-
};
|
|
475
|
+
function getWeekDayLabels(locale, firstDayOfWeek = 0) {
|
|
476
|
+
const { weekDays } = translations[locale];
|
|
477
|
+
return firstDayOfWeek === 0 ? [...weekDays] : [...weekDays.slice(1), weekDays[0]];
|
|
375
478
|
}
|
|
479
|
+
|
|
480
|
+
// src/core/can-chi.ts
|
|
376
481
|
function getDayCanChi(jd, locale = "vi") {
|
|
377
482
|
const stemIndex = (jd + 9) % 10;
|
|
378
483
|
const branchIndex = (jd + 1) % 12;
|
|
@@ -395,10 +500,235 @@ function getHourCanChi(hour, dayJd, locale = "vi") {
|
|
|
395
500
|
const { heavenlyStems, earthlyBranches } = t(locale);
|
|
396
501
|
return `${heavenlyStems[hourStemIndex]} ${earthlyBranches[hourBranchIndex]}`;
|
|
397
502
|
}
|
|
503
|
+
|
|
504
|
+
// src/utils/math.ts
|
|
505
|
+
function mod(n, m) {
|
|
506
|
+
return (n % m + m) % m;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// src/core/ngu-hanh.ts
|
|
510
|
+
var NAP_AM_ELEMENT_INDEX = [
|
|
511
|
+
0,
|
|
512
|
+
3,
|
|
513
|
+
1,
|
|
514
|
+
4,
|
|
515
|
+
0,
|
|
516
|
+
3,
|
|
517
|
+
2,
|
|
518
|
+
4,
|
|
519
|
+
0,
|
|
520
|
+
1,
|
|
521
|
+
2,
|
|
522
|
+
4,
|
|
523
|
+
3,
|
|
524
|
+
1,
|
|
525
|
+
2,
|
|
526
|
+
0,
|
|
527
|
+
3,
|
|
528
|
+
1,
|
|
529
|
+
4,
|
|
530
|
+
0,
|
|
531
|
+
3,
|
|
532
|
+
2,
|
|
533
|
+
4,
|
|
534
|
+
0,
|
|
535
|
+
1,
|
|
536
|
+
2,
|
|
537
|
+
4,
|
|
538
|
+
3,
|
|
539
|
+
1,
|
|
540
|
+
2
|
|
541
|
+
];
|
|
542
|
+
function getSexagenaryIndex(stemIndex, branchIndex) {
|
|
543
|
+
for (let i = 0; i < 60; i++) {
|
|
544
|
+
if (i % 10 === stemIndex && i % 12 === branchIndex) {
|
|
545
|
+
return i;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
throw new RangeError(`Lichta: Invalid Can Chi combination (stem=${stemIndex}, chi=${branchIndex})`);
|
|
549
|
+
}
|
|
550
|
+
function getNapAmElementIndex(stemIndex, branchIndex) {
|
|
551
|
+
const sexagenaryIndex = getSexagenaryIndex(stemIndex, branchIndex);
|
|
552
|
+
return NAP_AM_ELEMENT_INDEX[Math.floor(sexagenaryIndex / 2)];
|
|
553
|
+
}
|
|
554
|
+
function getElementName(index, locale = "vi") {
|
|
555
|
+
return t(locale).fiveElements[mod(index, 5)];
|
|
556
|
+
}
|
|
557
|
+
function getDayElementIndex(jd) {
|
|
558
|
+
const stemIndex = (jd + 9) % 10;
|
|
559
|
+
const branchIndex = (jd + 1) % 12;
|
|
560
|
+
return getNapAmElementIndex(stemIndex, branchIndex);
|
|
561
|
+
}
|
|
562
|
+
function getDayElement(jd, locale = "vi") {
|
|
563
|
+
return getElementName(getDayElementIndex(jd), locale);
|
|
564
|
+
}
|
|
565
|
+
function getMonthElementIndex(lunarMonth, lunarYear) {
|
|
566
|
+
const yearStemIndex = (lunarYear + 6) % 10;
|
|
567
|
+
const monthStemOffset = yearStemIndex % 5 * 2 + 2;
|
|
568
|
+
const monthStemIndex = (monthStemOffset + lunarMonth - 1) % 10;
|
|
569
|
+
const monthBranchIndex = (lunarMonth + 1) % 12;
|
|
570
|
+
return getNapAmElementIndex(monthStemIndex, monthBranchIndex);
|
|
571
|
+
}
|
|
572
|
+
function getMonthElement(lunarMonth, lunarYear, locale = "vi") {
|
|
573
|
+
return getElementName(getMonthElementIndex(lunarMonth, lunarYear), locale);
|
|
574
|
+
}
|
|
575
|
+
function getHourElementIndex(hour, dayJd) {
|
|
576
|
+
const hourBranchIndex = Math.floor((hour + 1) / 2) % 12;
|
|
577
|
+
const dayStemIndex = (dayJd + 9) % 10;
|
|
578
|
+
const hourStemOffset = dayStemIndex % 5 * 2;
|
|
579
|
+
const hourStemIndex = (hourStemOffset + hourBranchIndex) % 10;
|
|
580
|
+
return getNapAmElementIndex(hourStemIndex, hourBranchIndex);
|
|
581
|
+
}
|
|
582
|
+
function getHourElement(hour, dayJd, locale = "vi") {
|
|
583
|
+
return getElementName(getHourElementIndex(hour, dayJd), locale);
|
|
584
|
+
}
|
|
585
|
+
var ELEMENT_SINH_TARGET = [2, 3, 1, 4, 0];
|
|
586
|
+
var ELEMENT_KHAC_TARGET = [1, 4, 3, 0, 2];
|
|
587
|
+
function getElementRelationIndex(fromIndex, toIndex) {
|
|
588
|
+
const a = mod(fromIndex, 5);
|
|
589
|
+
const b = mod(toIndex, 5);
|
|
590
|
+
if (a === b) return 4;
|
|
591
|
+
if (ELEMENT_SINH_TARGET[a] === b) return 0;
|
|
592
|
+
if (ELEMENT_SINH_TARGET[b] === a) return 1;
|
|
593
|
+
if (ELEMENT_KHAC_TARGET[a] === b) return 2;
|
|
594
|
+
return 3;
|
|
595
|
+
}
|
|
596
|
+
function getElementRelation(fromIndex, toIndex, locale = "vi") {
|
|
597
|
+
const { elementRelationNames } = t(locale);
|
|
598
|
+
return elementRelationNames[getElementRelationIndex(fromIndex, toIndex)];
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// src/core/tiet-khi.ts
|
|
602
|
+
function getSolarTermName(index, locale = "vi") {
|
|
603
|
+
const { solarTermNames } = t(locale);
|
|
604
|
+
return solarTermNames[(index % 24 + 24) % 24];
|
|
605
|
+
}
|
|
606
|
+
function getSolarTerm(day, month, year, timeZone = 7, locale = "vi") {
|
|
607
|
+
const jd = jdFromDate(day, month, year);
|
|
608
|
+
const index = getSolarTermIndex(jd + 1, timeZone);
|
|
609
|
+
return { index, name: getSolarTermName(index, locale), date: { day, month, year }, jd };
|
|
610
|
+
}
|
|
611
|
+
var occurrencesCache = /* @__PURE__ */ new Map();
|
|
612
|
+
function getSolarTermOccurrencesInYear(year, timeZone) {
|
|
613
|
+
const cacheKey = `${year}:${timeZone}`;
|
|
614
|
+
const cached = occurrencesCache.get(cacheKey);
|
|
615
|
+
if (cached) return cached;
|
|
616
|
+
const startJd = jdFromDate(1, 1, year) - 5;
|
|
617
|
+
const endJd = jdFromDate(31, 12, year) + 5;
|
|
618
|
+
const occurrences = [];
|
|
619
|
+
let prevIndex = getSolarTermIndex(startJd, timeZone);
|
|
620
|
+
for (let jd = startJd + 1; jd <= endJd; jd++) {
|
|
621
|
+
const index = getSolarTermIndex(jd, timeZone);
|
|
622
|
+
if (index !== prevIndex) {
|
|
623
|
+
const termJd = jd - 1;
|
|
624
|
+
const [, , jdYear] = jdToDate(termJd);
|
|
625
|
+
if (jdYear === year) {
|
|
626
|
+
occurrences.push({ index, jd: termJd });
|
|
627
|
+
}
|
|
628
|
+
prevIndex = index;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
occurrencesCache.set(cacheKey, occurrences);
|
|
632
|
+
return occurrences;
|
|
633
|
+
}
|
|
634
|
+
function getSolarTermsInYear(year, timeZone = 7, locale = "vi") {
|
|
635
|
+
return getSolarTermOccurrencesInYear(year, timeZone).map(({ index, jd }) => {
|
|
636
|
+
const [day, month, jdYear] = jdToDate(jd);
|
|
637
|
+
return { index, name: getSolarTermName(index, locale), date: { day, month, year: jdYear }, jd };
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// src/core/truc-zodiac.ts
|
|
642
|
+
var TRUC_COUNT = 12;
|
|
643
|
+
function getTrucIndex(jd, timeZone = 7) {
|
|
644
|
+
const [, , year] = jdToDate(jd);
|
|
645
|
+
const tietTerms = [year - 1, year, year + 1].flatMap((y) => getSolarTermOccurrencesInYear(y, timeZone)).filter((term) => term.index % 2 === 1);
|
|
646
|
+
let governingTiet = tietTerms[0];
|
|
647
|
+
for (const term of tietTerms) {
|
|
648
|
+
if (term.jd <= jd && term.jd > governingTiet.jd) {
|
|
649
|
+
governingTiet = term;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
const kienBranchIndex = mod((governingTiet.index - 21) / 2 + 2, TRUC_COUNT);
|
|
653
|
+
const dayBranchIndex = mod(jd + 1, TRUC_COUNT);
|
|
654
|
+
return mod(dayBranchIndex - kienBranchIndex, TRUC_COUNT);
|
|
655
|
+
}
|
|
656
|
+
function getTrucName(index, locale = "vi") {
|
|
657
|
+
const { trucNames } = t(locale);
|
|
658
|
+
return trucNames[mod(index, TRUC_COUNT)];
|
|
659
|
+
}
|
|
660
|
+
function getTruc(jd, timeZone = 7, locale = "vi") {
|
|
661
|
+
return getTrucName(getTrucIndex(jd, timeZone), locale);
|
|
662
|
+
}
|
|
663
|
+
var TRUC_QUALITY_INDEX = [1, 1, 1, 1, 1, 1, 0, 0, 2, 1, 2, 1];
|
|
664
|
+
function getTrucQualityIndex(trucIndex) {
|
|
665
|
+
return TRUC_QUALITY_INDEX[mod(trucIndex, TRUC_COUNT)];
|
|
666
|
+
}
|
|
667
|
+
function getTrucQuality(trucIndex, locale = "vi") {
|
|
668
|
+
const { trucQualityNames } = t(locale);
|
|
669
|
+
return trucQualityNames[getTrucQualityIndex(trucIndex)];
|
|
670
|
+
}
|
|
671
|
+
function getXungBranchIndex(branchIndex) {
|
|
672
|
+
return mod(branchIndex + 6, 12);
|
|
673
|
+
}
|
|
674
|
+
function isXung(branchIndexA, branchIndexB) {
|
|
675
|
+
return getXungBranchIndex(mod(branchIndexA, 12)) === mod(branchIndexB, 12);
|
|
676
|
+
}
|
|
677
|
+
var HAI_BRANCH_TARGET = [7, 6, 5, 4, 3, 2, 1, 0, 11, 10, 9, 8];
|
|
678
|
+
function getHaiBranchIndex(branchIndex) {
|
|
679
|
+
return HAI_BRANCH_TARGET[mod(branchIndex, 12)];
|
|
680
|
+
}
|
|
681
|
+
function isHai(branchIndexA, branchIndexB) {
|
|
682
|
+
return getHaiBranchIndex(mod(branchIndexA, 12)) === mod(branchIndexB, 12);
|
|
683
|
+
}
|
|
684
|
+
var TU_HANH_XUNG_GROUP = [0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1];
|
|
685
|
+
var TU_HANH_XUNG_MEMBERS = [
|
|
686
|
+
[0, 3, 6, 9],
|
|
687
|
+
// Tý, Mão, Ngọ, Dậu
|
|
688
|
+
[2, 5, 8, 11],
|
|
689
|
+
// Dần, Tỵ, Thân, Hợi
|
|
690
|
+
[1, 4, 7, 10]
|
|
691
|
+
// Sửu, Thìn, Mùi, Tuất
|
|
692
|
+
];
|
|
693
|
+
function getTuHanhXungGroupIndex(branchIndex) {
|
|
694
|
+
return TU_HANH_XUNG_GROUP[mod(branchIndex, 12)];
|
|
695
|
+
}
|
|
696
|
+
function getTuHanhXungGroupMembers(branchIndex) {
|
|
697
|
+
return [...TU_HANH_XUNG_MEMBERS[getTuHanhXungGroupIndex(branchIndex)]];
|
|
698
|
+
}
|
|
699
|
+
function isTuHanhXung(branchIndexA, branchIndexB) {
|
|
700
|
+
const a = mod(branchIndexA, 12);
|
|
701
|
+
const b = mod(branchIndexB, 12);
|
|
702
|
+
return a !== b && getTuHanhXungGroupIndex(a) === getTuHanhXungGroupIndex(b);
|
|
703
|
+
}
|
|
704
|
+
function getZodiacConflicts(branchIndexA, branchIndexB) {
|
|
705
|
+
return {
|
|
706
|
+
xung: isXung(branchIndexA, branchIndexB),
|
|
707
|
+
hai: isHai(branchIndexA, branchIndexB),
|
|
708
|
+
tuHanhXung: isTuHanhXung(branchIndexA, branchIndexB)
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// src/constants/five-elements.ts
|
|
713
|
+
var FIVE_ELEMENTS = ["Kim", "M\u1ED9c", "Th\u1EE7y", "H\u1ECFa", "Th\u1ED5"];
|
|
714
|
+
|
|
715
|
+
// src/core/almanac.ts
|
|
716
|
+
function getYearDetails(year) {
|
|
717
|
+
const stemIndex = mod(year - 4, 10);
|
|
718
|
+
const branchIndex = mod(year - 4, 12);
|
|
719
|
+
const elementIndex = getNapAmElementIndex(stemIndex, branchIndex);
|
|
720
|
+
return {
|
|
721
|
+
can: HEAVENLY_STEMS[stemIndex],
|
|
722
|
+
chi: EARTHLY_BRANCHES[branchIndex],
|
|
723
|
+
menh: FIVE_ELEMENTS[elementIndex],
|
|
724
|
+
menhIndex: elementIndex,
|
|
725
|
+
fullString: `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]} - M\u1EC7nh ${FIVE_ELEMENTS[elementIndex]}`
|
|
726
|
+
};
|
|
727
|
+
}
|
|
398
728
|
var AUSPICIOUS_HOURS_TABLE = [
|
|
399
729
|
[0, 1, 3, 6, 7, 9],
|
|
400
730
|
// Ngày Tý (0) / Ngọ (6)
|
|
401
|
-
[2, 3, 5, 8,
|
|
731
|
+
[2, 3, 5, 8, 10, 11],
|
|
402
732
|
// Ngày Sửu (1) / Mùi (7)
|
|
403
733
|
[0, 1, 4, 5, 7, 10],
|
|
404
734
|
// Ngày Dần (2) / Thân (8)
|
|
@@ -421,6 +751,18 @@ function getAuspiciousHourIndices(dayJd) {
|
|
|
421
751
|
const groupIndex = branchIndex % 6;
|
|
422
752
|
return [...AUSPICIOUS_HOURS_TABLE[groupIndex]];
|
|
423
753
|
}
|
|
754
|
+
function getInauspiciousHourIndices(dayJd) {
|
|
755
|
+
const auspicious = new Set(getAuspiciousHourIndices(dayJd));
|
|
756
|
+
const inauspicious = [];
|
|
757
|
+
for (let i = 0; i < 12; i++) {
|
|
758
|
+
if (!auspicious.has(i)) inauspicious.push(i);
|
|
759
|
+
}
|
|
760
|
+
return inauspicious;
|
|
761
|
+
}
|
|
762
|
+
function getInauspiciousHours(dayJd, locale = "vi") {
|
|
763
|
+
const { earthlyBranches } = t(locale);
|
|
764
|
+
return getInauspiciousHourIndices(dayJd).map((i) => earthlyBranches[i]);
|
|
765
|
+
}
|
|
424
766
|
|
|
425
767
|
// src/utils/format.ts
|
|
426
768
|
var MONTH_NAMES = [
|
|
@@ -504,11 +846,20 @@ function formatTraditional(lunar) {
|
|
|
504
846
|
function dateKey(date) {
|
|
505
847
|
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
|
|
506
848
|
}
|
|
507
|
-
function
|
|
849
|
+
function getISOWeekNumber(date) {
|
|
850
|
+
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
|
851
|
+
const dayNum = (d.getUTCDay() + 6) % 7;
|
|
852
|
+
d.setUTCDate(d.getUTCDate() - dayNum + 3);
|
|
853
|
+
const firstThursday = new Date(Date.UTC(d.getUTCFullYear(), 0, 4));
|
|
854
|
+
const firstThursdayDayNum = (firstThursday.getUTCDay() + 6) % 7;
|
|
855
|
+
firstThursday.setUTCDate(firstThursday.getUTCDate() - firstThursdayDayNum + 3);
|
|
856
|
+
return 1 + Math.round((d.getTime() - firstThursday.getTime()) / 6048e5);
|
|
857
|
+
}
|
|
858
|
+
function getCalendarGrid(month, year, selectedDate, firstDayOfWeek = 0) {
|
|
508
859
|
const grid = [];
|
|
509
860
|
const firstDay = new Date(year, month - 1, 1);
|
|
510
861
|
const lastDay = new Date(year, month, 0);
|
|
511
|
-
const startingDayOfWeek = firstDay.getDay();
|
|
862
|
+
const startingDayOfWeek = (firstDay.getDay() - firstDayOfWeek + 7) % 7;
|
|
512
863
|
const daysInMonth = lastDay.getDate();
|
|
513
864
|
const todayKey = dateKey(/* @__PURE__ */ new Date());
|
|
514
865
|
const selectedKey = selectedDate ? dateKey(selectedDate) : "";
|
|
@@ -519,7 +870,9 @@ function getCalendarGrid(month, year, selectedDate) {
|
|
|
519
870
|
lunar: LichTa.toLunar(d, m, y),
|
|
520
871
|
isToday: dateKey(solar) === todayKey,
|
|
521
872
|
isSelected: dateKey(solar) === selectedKey,
|
|
522
|
-
isCurrentMonth
|
|
873
|
+
isCurrentMonth,
|
|
874
|
+
weekNumber: 0
|
|
875
|
+
// gán lại theo từng hàng ở bước cuối, xem vòng lặp bên dưới
|
|
523
876
|
});
|
|
524
877
|
};
|
|
525
878
|
for (let i = startingDayOfWeek - 1; i >= 0; i--) {
|
|
@@ -537,6 +890,13 @@ function getCalendarGrid(month, year, selectedDate) {
|
|
|
537
890
|
const y = month + 1 > 12 ? year + 1 : year;
|
|
538
891
|
pushCell(new Date(y, m - 1, d), d, m, y, false);
|
|
539
892
|
}
|
|
893
|
+
const thursdayOffset = (4 - firstDayOfWeek + 7) % 7;
|
|
894
|
+
for (let row = 0; row < grid.length; row += 7) {
|
|
895
|
+
const weekNumber = getISOWeekNumber(grid[row + thursdayOffset].solar);
|
|
896
|
+
for (let i = row; i < row + 7; i++) {
|
|
897
|
+
grid[i].weekNumber = weekNumber;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
540
900
|
return grid;
|
|
541
901
|
}
|
|
542
902
|
export {
|
|
@@ -547,12 +907,41 @@ export {
|
|
|
547
907
|
getAuspiciousHours,
|
|
548
908
|
getCalendarGrid,
|
|
549
909
|
getDayCanChi,
|
|
910
|
+
getDayElement,
|
|
911
|
+
getDayElementIndex,
|
|
550
912
|
getDayName,
|
|
913
|
+
getElementName,
|
|
914
|
+
getElementRelation,
|
|
915
|
+
getElementRelationIndex,
|
|
916
|
+
getHaiBranchIndex,
|
|
551
917
|
getHourCanChi,
|
|
918
|
+
getHourElement,
|
|
919
|
+
getHourElementIndex,
|
|
920
|
+
getISOWeekNumber,
|
|
921
|
+
getInauspiciousHourIndices,
|
|
922
|
+
getInauspiciousHours,
|
|
552
923
|
getMonthCanChi,
|
|
924
|
+
getMonthElement,
|
|
925
|
+
getMonthElementIndex,
|
|
553
926
|
getMonthName,
|
|
927
|
+
getSolarTerm,
|
|
928
|
+
getSolarTermName,
|
|
929
|
+
getSolarTermsInYear,
|
|
930
|
+
getTruc,
|
|
931
|
+
getTrucIndex,
|
|
932
|
+
getTrucName,
|
|
933
|
+
getTrucQuality,
|
|
934
|
+
getTrucQualityIndex,
|
|
935
|
+
getTuHanhXungGroupIndex,
|
|
936
|
+
getTuHanhXungGroupMembers,
|
|
937
|
+
getWeekDayLabels,
|
|
938
|
+
getXungBranchIndex,
|
|
554
939
|
getYearDetails,
|
|
555
940
|
getZodiacAnimal,
|
|
941
|
+
getZodiacConflicts,
|
|
942
|
+
isHai,
|
|
943
|
+
isTuHanhXung,
|
|
944
|
+
isXung,
|
|
556
945
|
jdFromDate,
|
|
557
946
|
jdToDate,
|
|
558
947
|
t
|