@lichta/core 2.0.1 → 2.2.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/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/lunar.ts
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 getSunLongitude(jdn, timeZone) {
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 INT(L / 30);
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 = INT(off / 29.530588853);
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 = INT((a11 - 2415021076998695e-9) / 29.530588853 + 0.5);
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 = INT((dayNumber - 2415021076998695e-9) / 29.530588853);
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 = INT((monthStart - a11) / 29);
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 = INT(0.5 + (a11 - 2415021076998695e-9) / 29.530588853);
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,45 +283,445 @@ 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"];
286
+ // src/constants/i18n.ts
287
+ var translations = {
288
+ vi: {
289
+ heavenlyStems: ["Gi\xE1p", "\u1EA4t", "B\xEDnh", "\u0110inh", "M\u1EADu", "K\u1EF7", "Canh", "T\xE2n", "Nh\xE2m", "Qu\xFD"],
290
+ earthlyBranches: ["T\xFD", "S\u1EEDu", "D\u1EA7n", "M\xE3o", "Th\xECn", "T\u1EF5", "Ng\u1ECD", "M\xF9i", "Th\xE2n", "D\u1EADu", "Tu\u1EA5t", "H\u1EE3i"],
291
+ fiveElements: ["Kim", "M\u1ED9c", "Th\u1EE7y", "H\u1ECFa", "Th\u1ED5"],
292
+ zodiacAnimals: ["Chu\u1ED9t", "Tr\xE2u", "C\u1ECDp", "Th\u1ECF", "R\u1ED3ng", "R\u1EAFn", "Ng\u1EF1a", "D\xEA", "Kh\u1EC9", "G\xE0", "Ch\xF3", "Heo"],
293
+ // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).
294
+ monthNames: ["Gi\xEAng", "Hai", "Ba", "T\u01B0", "N\u0103m", "S\xE1u", "B\u1EA3y", "T\xE1m", "Ch\xEDn", "M\u01B0\u1EDDi", "M\u1ED9t", "Ch\u1EA1p"],
295
+ lunarMonthNames: ["Gi\xEAng", "Hai", "Ba", "T\u01B0", "N\u0103m", "S\xE1u", "B\u1EA3y", "T\xE1m", "Ch\xEDn", "M\u01B0\u1EDDi", "M\u1ED9t", "Ch\u1EA1p"],
296
+ solarMonthNames: ["Th\xE1ng 1", "Th\xE1ng 2", "Th\xE1ng 3", "Th\xE1ng 4", "Th\xE1ng 5", "Th\xE1ng 6", "Th\xE1ng 7", "Th\xE1ng 8", "Th\xE1ng 9", "Th\xE1ng 10", "Th\xE1ng 11", "Th\xE1ng 12"],
297
+ weekDays: ["CN", "T2", "T3", "T4", "T5", "T6", "T7"],
298
+ leapLabel: "Nhu\u1EADn",
299
+ yearLabel: "N\u0103m",
300
+ monthLabel: "Th\xE1ng",
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"]
335
+ },
336
+ en: {
337
+ heavenlyStems: ["Gi\xE1p", "\u1EA4t", "B\xEDnh", "\u0110inh", "M\u1EADu", "K\u1EF7", "Canh", "T\xE2n", "Nh\xE2m", "Qu\xFD"],
338
+ earthlyBranches: ["T\xFD", "S\u1EEDu", "D\u1EA7n", "M\xE3o", "Th\xECn", "T\u1EF5", "Ng\u1ECD", "M\xF9i", "Th\xE2n", "D\u1EADu", "Tu\u1EA5t", "H\u1EE3i"],
339
+ fiveElements: ["Metal", "Wood", "Water", "Fire", "Earth"],
340
+ zodiacAnimals: ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"],
341
+ // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).
342
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
343
+ lunarMonthNames: ["Month 1", "Month 2", "Month 3", "Month 4", "Month 5", "Month 6", "Month 7", "Month 8", "Month 9", "Month 10", "Month 11", "Month 12"],
344
+ solarMonthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
345
+ weekDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
346
+ leapLabel: "Leap",
347
+ yearLabel: "Year",
348
+ monthLabel: "Month",
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"]
379
+ },
380
+ ja: {
381
+ heavenlyStems: ["\u7532", "\u4E59", "\u4E19", "\u4E01", "\u620A", "\u5DF1", "\u5E9A", "\u8F9B", "\u58EC", "\u7678"],
382
+ earthlyBranches: ["\u5B50", "\u4E11", "\u5BC5", "\u536F", "\u8FB0", "\u5DF3", "\u5348", "\u672A", "\u7533", "\u9149", "\u620C", "\u4EA5"],
383
+ fiveElements: ["\u91D1", "\u6728", "\u6C34", "\u706B", "\u571F"],
384
+ zodiacAnimals: ["\u9F20", "\u725B", "\u864E", "\u514E", "\u7ADC", "\u86C7", "\u99AC", "\u7F8A", "\u733F", "\u9D8F", "\u72AC", "\u732A"],
385
+ // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).
386
+ monthNames: ["1\u6708", "2\u6708", "3\u6708", "4\u6708", "5\u6708", "6\u6708", "7\u6708", "8\u6708", "9\u6708", "10\u6708", "11\u6708", "12\u6708"],
387
+ lunarMonthNames: ["\u65E7\u66A61\u6708", "\u65E7\u66A62\u6708", "\u65E7\u66A63\u6708", "\u65E7\u66A64\u6708", "\u65E7\u66A65\u6708", "\u65E7\u66A66\u6708", "\u65E7\u66A67\u6708", "\u65E7\u66A68\u6708", "\u65E7\u66A69\u6708", "\u65E7\u66A610\u6708", "\u65E7\u66A611\u6708", "\u65E7\u66A612\u6708"],
388
+ solarMonthNames: ["1\u6708", "2\u6708", "3\u6708", "4\u6708", "5\u6708", "6\u6708", "7\u6708", "8\u6708", "9\u6708", "10\u6708", "11\u6708", "12\u6708"],
389
+ weekDays: ["\u65E5", "\u6708", "\u706B", "\u6C34", "\u6728", "\u91D1", "\u571F"],
390
+ leapLabel: "\u958F",
391
+ yearLabel: "\u5E74",
392
+ monthLabel: "\u6708",
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"]
423
+ },
424
+ ko: {
425
+ heavenlyStems: ["\uAC11", "\uC744", "\uBCD1", "\uC815", "\uBB34", "\uAE30", "\uACBD", "\uC2E0", "\uC784", "\uACC4"],
426
+ earthlyBranches: ["\uC790", "\uCD95", "\uC778", "\uBB18", "\uC9C4", "\uC0AC", "\uC624", "\uBBF8", "\uC2E0", "\uC720", "\uC220", "\uD574"],
427
+ fiveElements: ["\uAE08", "\uBAA9", "\uC218", "\uD654", "\uD1A0"],
428
+ zodiacAnimals: ["\uC950", "\uC18C", "\uD638\uB791\uC774", "\uD1A0\uB07C", "\uC6A9", "\uBC40", "\uB9D0", "\uC591", "\uC6D0\uC22D\uC774", "\uB2ED", "\uAC1C", "\uB3FC\uC9C0"],
429
+ // @deprecated Ngữ nghĩa không nhất quán giữa các locale (xem lunarMonthNames/solarMonthNames).
430
+ monthNames: ["1\uC6D4", "2\uC6D4", "3\uC6D4", "4\uC6D4", "5\uC6D4", "6\uC6D4", "7\uC6D4", "8\uC6D4", "9\uC6D4", "10\uC6D4", "11\uC6D4", "12\uC6D4"],
431
+ lunarMonthNames: ["\uC74C\uB825 1\uC6D4", "\uC74C\uB825 2\uC6D4", "\uC74C\uB825 3\uC6D4", "\uC74C\uB825 4\uC6D4", "\uC74C\uB825 5\uC6D4", "\uC74C\uB825 6\uC6D4", "\uC74C\uB825 7\uC6D4", "\uC74C\uB825 8\uC6D4", "\uC74C\uB825 9\uC6D4", "\uC74C\uB825 10\uC6D4", "\uC74C\uB825 11\uC6D4", "\uC74C\uB825 12\uC6D4"],
432
+ solarMonthNames: ["1\uC6D4", "2\uC6D4", "3\uC6D4", "4\uC6D4", "5\uC6D4", "6\uC6D4", "7\uC6D4", "8\uC6D4", "9\uC6D4", "10\uC6D4", "11\uC6D4", "12\uC6D4"],
433
+ weekDays: ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"],
434
+ leapLabel: "\uC724",
435
+ yearLabel: "\uB144",
436
+ monthLabel: "\uC6D4",
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"]
467
+ }
468
+ };
469
+ function t(locale) {
470
+ return translations[locale];
471
+ }
472
+ function getZodiacAnimal(branchIndex, locale = "vi") {
473
+ return translations[locale].zodiacAnimals[branchIndex % 12];
474
+ }
475
+ function getWeekDayLabels(locale, firstDayOfWeek = 0) {
476
+ const { weekDays } = translations[locale];
477
+ return firstDayOfWeek === 0 ? [...weekDays] : [...weekDays.slice(1), weekDays[0]];
478
+ }
284
479
 
285
- // src/core/feng-shui.ts
286
- function getYearDetails(year) {
287
- const stemIndex = (year - 4) % 10;
288
- const branchIndex = (year - 4) % 12;
289
- const stemWeight = getStemWeight(stemIndex);
290
- const branchWeight = getBranchWeight(branchIndex);
291
- let elementValue = stemWeight + branchWeight;
292
- if (elementValue > 5) {
293
- elementValue -= 5;
480
+ // src/core/can-chi.ts
481
+ function getDayCanChi(jd, locale = "vi") {
482
+ const stemIndex = (jd + 9) % 10;
483
+ const branchIndex = (jd + 1) % 12;
484
+ const { heavenlyStems, earthlyBranches } = t(locale);
485
+ return `${heavenlyStems[stemIndex]} ${earthlyBranches[branchIndex]}`;
486
+ }
487
+ function getMonthCanChi(lunarMonth, lunarYear, locale = "vi") {
488
+ const yearStemIndex = (lunarYear + 6) % 10;
489
+ const monthStemOffset = yearStemIndex % 5 * 2 + 2;
490
+ const monthStemIndex = (monthStemOffset + lunarMonth - 1) % 10;
491
+ const monthBranchIndex = (lunarMonth + 1) % 12;
492
+ const { heavenlyStems, earthlyBranches } = t(locale);
493
+ return `${heavenlyStems[monthStemIndex]} ${earthlyBranches[monthBranchIndex]}`;
494
+ }
495
+ function getHourCanChi(hour, dayJd, locale = "vi") {
496
+ const hourBranchIndex = Math.floor((hour + 1) / 2) % 12;
497
+ const dayStemIndex = (dayJd + 9) % 10;
498
+ const hourStemOffset = dayStemIndex % 5 * 2;
499
+ const hourStemIndex = (hourStemOffset + hourBranchIndex) % 10;
500
+ const { heavenlyStems, earthlyBranches } = t(locale);
501
+ return `${heavenlyStems[hourStemIndex]} ${earthlyBranches[hourBranchIndex]}`;
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
+ }
294
547
  }
295
- const elementIndex = elementValue - 1;
296
- return {
297
- can: HEAVENLY_STEMS[stemIndex],
298
- chi: EARTHLY_BRANCHES[branchIndex],
299
- menh: FIVE_ELEMENTS[elementIndex],
300
- fullString: `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]} - M\u1EC7nh ${FIVE_ELEMENTS[elementIndex]}`
301
- };
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)];
302
556
  }
303
- function getDayCanChi(jd) {
557
+ function getDayElementIndex(jd) {
304
558
  const stemIndex = (jd + 9) % 10;
305
559
  const branchIndex = (jd + 1) % 12;
306
- return `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]}`;
560
+ return getNapAmElementIndex(stemIndex, branchIndex);
561
+ }
562
+ function getDayElement(jd, locale = "vi") {
563
+ return getElementName(getDayElementIndex(jd), locale);
307
564
  }
308
- function getMonthCanChi(lunarMonth, lunarYear) {
565
+ function getMonthElementIndex(lunarMonth, lunarYear) {
309
566
  const yearStemIndex = (lunarYear + 6) % 10;
310
567
  const monthStemOffset = yearStemIndex % 5 * 2 + 2;
311
568
  const monthStemIndex = (monthStemOffset + lunarMonth - 1) % 10;
312
569
  const monthBranchIndex = (lunarMonth + 1) % 12;
313
- return `${HEAVENLY_STEMS[monthStemIndex]} ${EARTHLY_BRANCHES[monthBranchIndex]}`;
570
+ return getNapAmElementIndex(monthStemIndex, monthBranchIndex);
314
571
  }
315
- function getHourCanChi(hour, dayJd) {
572
+ function getMonthElement(lunarMonth, lunarYear, locale = "vi") {
573
+ return getElementName(getMonthElementIndex(lunarMonth, lunarYear), locale);
574
+ }
575
+ function getHourElementIndex(hour, dayJd) {
316
576
  const hourBranchIndex = Math.floor((hour + 1) / 2) % 12;
317
577
  const dayStemIndex = (dayJd + 9) % 10;
318
578
  const hourStemOffset = dayStemIndex % 5 * 2;
319
579
  const hourStemIndex = (hourStemOffset + hourBranchIndex) % 10;
320
- return `${HEAVENLY_STEMS[hourStemIndex]} ${EARTHLY_BRANCHES[hourBranchIndex]}`;
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 governingTietJd = -Infinity;
647
+ for (const term of tietTerms) {
648
+ if (term.jd <= jd && term.jd > governingTietJd) {
649
+ governingTietJd = term.jd;
650
+ }
651
+ }
652
+ return mod(jd - governingTietJd, TRUC_COUNT);
653
+ }
654
+ function getTrucName(index, locale = "vi") {
655
+ const { trucNames } = t(locale);
656
+ return trucNames[mod(index, TRUC_COUNT)];
657
+ }
658
+ function getTruc(jd, timeZone = 7, locale = "vi") {
659
+ return getTrucName(getTrucIndex(jd, timeZone), locale);
660
+ }
661
+ var TRUC_QUALITY_INDEX = [1, 1, 1, 1, 1, 1, 0, 0, 2, 1, 2, 1];
662
+ function getTrucQualityIndex(trucIndex) {
663
+ return TRUC_QUALITY_INDEX[mod(trucIndex, TRUC_COUNT)];
664
+ }
665
+ function getTrucQuality(trucIndex, locale = "vi") {
666
+ const { trucQualityNames } = t(locale);
667
+ return trucQualityNames[getTrucQualityIndex(trucIndex)];
668
+ }
669
+ function getXungBranchIndex(branchIndex) {
670
+ return mod(branchIndex + 6, 12);
671
+ }
672
+ function isXung(branchIndexA, branchIndexB) {
673
+ return getXungBranchIndex(mod(branchIndexA, 12)) === mod(branchIndexB, 12);
674
+ }
675
+ var HAI_BRANCH_TARGET = [7, 6, 5, 4, 3, 2, 1, 0, 11, 10, 9, 8];
676
+ function getHaiBranchIndex(branchIndex) {
677
+ return HAI_BRANCH_TARGET[mod(branchIndex, 12)];
678
+ }
679
+ function isHai(branchIndexA, branchIndexB) {
680
+ return getHaiBranchIndex(mod(branchIndexA, 12)) === mod(branchIndexB, 12);
681
+ }
682
+ var TU_HANH_XUNG_GROUP = [0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1];
683
+ var TU_HANH_XUNG_MEMBERS = [
684
+ [0, 3, 6, 9],
685
+ // Tý, Mão, Ngọ, Dậu
686
+ [2, 5, 8, 11],
687
+ // Dần, Tỵ, Thân, Hợi
688
+ [1, 4, 7, 10]
689
+ // Sửu, Thìn, Mùi, Tuất
690
+ ];
691
+ function getTuHanhXungGroupIndex(branchIndex) {
692
+ return TU_HANH_XUNG_GROUP[mod(branchIndex, 12)];
693
+ }
694
+ function getTuHanhXungGroupMembers(branchIndex) {
695
+ return [...TU_HANH_XUNG_MEMBERS[getTuHanhXungGroupIndex(branchIndex)]];
696
+ }
697
+ function isTuHanhXung(branchIndexA, branchIndexB) {
698
+ const a = mod(branchIndexA, 12);
699
+ const b = mod(branchIndexB, 12);
700
+ return a !== b && getTuHanhXungGroupIndex(a) === getTuHanhXungGroupIndex(b);
701
+ }
702
+ function getZodiacConflicts(branchIndexA, branchIndexB) {
703
+ return {
704
+ xung: isXung(branchIndexA, branchIndexB),
705
+ hai: isHai(branchIndexA, branchIndexB),
706
+ tuHanhXung: isTuHanhXung(branchIndexA, branchIndexB)
707
+ };
708
+ }
709
+
710
+ // src/constants/five-elements.ts
711
+ var FIVE_ELEMENTS = ["Kim", "M\u1ED9c", "Th\u1EE7y", "H\u1ECFa", "Th\u1ED5"];
712
+
713
+ // src/core/almanac.ts
714
+ function getYearDetails(year) {
715
+ const stemIndex = mod(year - 4, 10);
716
+ const branchIndex = mod(year - 4, 12);
717
+ const elementIndex = getNapAmElementIndex(stemIndex, branchIndex);
718
+ return {
719
+ can: HEAVENLY_STEMS[stemIndex],
720
+ chi: EARTHLY_BRANCHES[branchIndex],
721
+ menh: FIVE_ELEMENTS[elementIndex],
722
+ menhIndex: elementIndex,
723
+ fullString: `${HEAVENLY_STEMS[stemIndex]} ${EARTHLY_BRANCHES[branchIndex]} - M\u1EC7nh ${FIVE_ELEMENTS[elementIndex]}`
724
+ };
321
725
  }
322
726
  var AUSPICIOUS_HOURS_TABLE = [
323
727
  [0, 1, 3, 6, 7, 9],
@@ -333,11 +737,29 @@ var AUSPICIOUS_HOURS_TABLE = [
333
737
  [2, 5, 6, 8, 11, 0]
334
738
  // Ngày Tỵ (5) / Hợi (11)
335
739
  ];
336
- function getAuspiciousHours(dayJd) {
740
+ function getAuspiciousHours(dayJd, locale = "vi") {
337
741
  const branchIndex = (dayJd + 1) % 12;
338
742
  const groupIndex = branchIndex % 6;
339
743
  const hourIndices = AUSPICIOUS_HOURS_TABLE[groupIndex];
340
- return hourIndices.map((i) => EARTHLY_BRANCHES[i]);
744
+ const { earthlyBranches } = t(locale);
745
+ return hourIndices.map((i) => earthlyBranches[i]);
746
+ }
747
+ function getAuspiciousHourIndices(dayJd) {
748
+ const branchIndex = (dayJd + 1) % 12;
749
+ const groupIndex = branchIndex % 6;
750
+ return [...AUSPICIOUS_HOURS_TABLE[groupIndex]];
751
+ }
752
+ function getInauspiciousHourIndices(dayJd) {
753
+ const auspicious = new Set(getAuspiciousHourIndices(dayJd));
754
+ const inauspicious = [];
755
+ for (let i = 0; i < 12; i++) {
756
+ if (!auspicious.has(i)) inauspicious.push(i);
757
+ }
758
+ return inauspicious;
759
+ }
760
+ function getInauspiciousHours(dayJd, locale = "vi") {
761
+ const { earthlyBranches } = t(locale);
762
+ return getInauspiciousHourIndices(dayJd).map((i) => earthlyBranches[i]);
341
763
  }
342
764
 
343
765
  // src/utils/format.ts
@@ -396,7 +818,7 @@ function getDayName(day) {
396
818
  }
397
819
  return "Ba M\u01B0\u01A1i";
398
820
  }
399
- function formatLunarDate(lunar, pattern) {
821
+ function formatLunarDate(lunar, pattern, locale = "vi") {
400
822
  let result = pattern;
401
823
  result = result.replace(/yyyy/g, String(lunar.year));
402
824
  result = result.replace(/yy/g, String(lunar.year).slice(-2));
@@ -405,7 +827,7 @@ function formatLunarDate(lunar, pattern) {
405
827
  result = result.replace(/CC/g, lunar.yearCanChi ?? "");
406
828
  result = result.replace(/DC/g, lunar.dayCanChi ?? "");
407
829
  result = result.replace(/MC/g, lunar.monthCanChi ?? "");
408
- result = result.replace(/L/g, lunar.isLeap ? "Nhu\u1EADn" : "");
830
+ result = result.replace(/L/g, lunar.isLeap ? t(locale).leapLabel : "");
409
831
  result = result.replace(/(?<![0-9])d(?![0-9d])/g, String(lunar.day));
410
832
  result = result.replace(/(?<![0-9])M(?![0-9MC])/g, String(lunar.month));
411
833
  return result.trim();
@@ -418,75 +840,106 @@ function formatTraditional(lunar) {
418
840
  return `${dayName} th\xE1ng ${monthName}${leapSuffix} n\u0103m ${yearCanChi}`.trim();
419
841
  }
420
842
 
421
- // src/constants/i18n.ts
422
- var translations = {
423
- vi: {
424
- heavenlyStems: ["Gi\xE1p", "\u1EA4t", "B\xEDnh", "\u0110inh", "M\u1EADu", "K\u1EF7", "Canh", "T\xE2n", "Nh\xE2m", "Qu\xFD"],
425
- earthlyBranches: ["T\xFD", "S\u1EEDu", "D\u1EA7n", "M\xE3o", "Th\xECn", "T\u1EF5", "Ng\u1ECD", "M\xF9i", "Th\xE2n", "D\u1EADu", "Tu\u1EA5t", "H\u1EE3i"],
426
- fiveElements: ["Kim", "M\u1ED9c", "Th\u1EE7y", "H\u1ECFa", "Th\u1ED5"],
427
- zodiacAnimals: ["Chu\u1ED9t", "Tr\xE2u", "C\u1ECDp", "Th\u1ECF", "R\u1ED3ng", "R\u1EAFn", "Ng\u1EF1a", "D\xEA", "Kh\u1EC9", "G\xE0", "Ch\xF3", "Heo"],
428
- monthNames: ["Gi\xEAng", "Hai", "Ba", "T\u01B0", "N\u0103m", "S\xE1u", "B\u1EA3y", "T\xE1m", "Ch\xEDn", "M\u01B0\u1EDDi", "M\u1ED9t", "Ch\u1EA1p"],
429
- weekDays: ["CN", "T2", "T3", "T4", "T5", "T6", "T7"],
430
- leapLabel: "Nhu\u1EADn",
431
- yearLabel: "N\u0103m",
432
- monthLabel: "Th\xE1ng",
433
- destiny: "M\u1EC7nh"
434
- },
435
- en: {
436
- heavenlyStems: ["Gi\xE1p", "\u1EA4t", "B\xEDnh", "\u0110inh", "M\u1EADu", "K\u1EF7", "Canh", "T\xE2n", "Nh\xE2m", "Qu\xFD"],
437
- earthlyBranches: ["T\xFD", "S\u1EEDu", "D\u1EA7n", "M\xE3o", "Th\xECn", "T\u1EF5", "Ng\u1ECD", "M\xF9i", "Th\xE2n", "D\u1EADu", "Tu\u1EA5t", "H\u1EE3i"],
438
- fiveElements: ["Metal", "Wood", "Water", "Fire", "Earth"],
439
- zodiacAnimals: ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"],
440
- monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
441
- weekDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
442
- leapLabel: "Leap",
443
- yearLabel: "Year",
444
- monthLabel: "Month",
445
- destiny: "Destiny"
446
- },
447
- ja: {
448
- heavenlyStems: ["\u7532", "\u4E59", "\u4E19", "\u4E01", "\u620A", "\u5DF1", "\u5E9A", "\u8F9B", "\u58EC", "\u7678"],
449
- earthlyBranches: ["\u5B50", "\u4E11", "\u5BC5", "\u536F", "\u8FB0", "\u5DF3", "\u5348", "\u672A", "\u7533", "\u9149", "\u620C", "\u4EA5"],
450
- fiveElements: ["\u91D1", "\u6728", "\u6C34", "\u706B", "\u571F"],
451
- zodiacAnimals: ["\u9F20", "\u725B", "\u864E", "\u514E", "\u7ADC", "\u86C7", "\u99AC", "\u7F8A", "\u733F", "\u9D8F", "\u72AC", "\u732A"],
452
- monthNames: ["1\u6708", "2\u6708", "3\u6708", "4\u6708", "5\u6708", "6\u6708", "7\u6708", "8\u6708", "9\u6708", "10\u6708", "11\u6708", "12\u6708"],
453
- weekDays: ["\u65E5", "\u6708", "\u706B", "\u6C34", "\u6728", "\u91D1", "\u571F"],
454
- leapLabel: "\u958F",
455
- yearLabel: "\u5E74",
456
- monthLabel: "\u6708",
457
- destiny: "\u547D"
458
- },
459
- ko: {
460
- heavenlyStems: ["\uAC11", "\uC744", "\uBCD1", "\uC815", "\uBB34", "\uAE30", "\uACBD", "\uC2E0", "\uC784", "\uACC4"],
461
- earthlyBranches: ["\uC790", "\uCD95", "\uC778", "\uBB18", "\uC9C4", "\uC0AC", "\uC624", "\uBBF8", "\uC2E0", "\uC720", "\uC220", "\uD574"],
462
- fiveElements: ["\uAE08", "\uBAA9", "\uC218", "\uD654", "\uD1A0"],
463
- zodiacAnimals: ["\uC950", "\uC18C", "\uD638\uB791\uC774", "\uD1A0\uB07C", "\uC6A9", "\uBC40", "\uB9D0", "\uC591", "\uC6D0\uC22D\uC774", "\uB2ED", "\uAC1C", "\uB3FC\uC9C0"],
464
- monthNames: ["1\uC6D4", "2\uC6D4", "3\uC6D4", "4\uC6D4", "5\uC6D4", "6\uC6D4", "7\uC6D4", "8\uC6D4", "9\uC6D4", "10\uC6D4", "11\uC6D4", "12\uC6D4"],
465
- weekDays: ["\uC77C", "\uC6D4", "\uD654", "\uC218", "\uBAA9", "\uAE08", "\uD1A0"],
466
- leapLabel: "\uC724",
467
- yearLabel: "\uB144",
468
- monthLabel: "\uC6D4",
469
- destiny: "\uBA85"
470
- }
471
- };
472
- function t(locale) {
473
- return translations[locale];
843
+ // src/utils/calendar-grid.ts
844
+ function dateKey(date) {
845
+ return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
474
846
  }
475
- function getZodiacAnimal(branchIndex, locale = "vi") {
476
- return translations[locale].zodiacAnimals[branchIndex % 12];
847
+ function getISOWeekNumber(date) {
848
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
849
+ const dayNum = (d.getUTCDay() + 6) % 7;
850
+ d.setUTCDate(d.getUTCDate() - dayNum + 3);
851
+ const firstThursday = new Date(Date.UTC(d.getUTCFullYear(), 0, 4));
852
+ const firstThursdayDayNum = (firstThursday.getUTCDay() + 6) % 7;
853
+ firstThursday.setUTCDate(firstThursday.getUTCDate() - firstThursdayDayNum + 3);
854
+ return 1 + Math.round((d.getTime() - firstThursday.getTime()) / 6048e5);
855
+ }
856
+ function getCalendarGrid(month, year, selectedDate, firstDayOfWeek = 0) {
857
+ const grid = [];
858
+ const firstDay = new Date(year, month - 1, 1);
859
+ const lastDay = new Date(year, month, 0);
860
+ const startingDayOfWeek = (firstDay.getDay() - firstDayOfWeek + 7) % 7;
861
+ const daysInMonth = lastDay.getDate();
862
+ const todayKey = dateKey(/* @__PURE__ */ new Date());
863
+ const selectedKey = selectedDate ? dateKey(selectedDate) : "";
864
+ const prevMonthLastDay = new Date(year, month - 1, 0).getDate();
865
+ const pushCell = (solar, d, m, y, isCurrentMonth) => {
866
+ grid.push({
867
+ solar,
868
+ lunar: LichTa.toLunar(d, m, y),
869
+ isToday: dateKey(solar) === todayKey,
870
+ isSelected: dateKey(solar) === selectedKey,
871
+ isCurrentMonth,
872
+ weekNumber: 0
873
+ // gán lại theo từng hàng ở bước cuối, xem vòng lặp bên dưới
874
+ });
875
+ };
876
+ for (let i = startingDayOfWeek - 1; i >= 0; i--) {
877
+ const d = prevMonthLastDay - i;
878
+ const m = month - 1 < 1 ? 12 : month - 1;
879
+ const y = month - 1 < 1 ? year - 1 : year;
880
+ pushCell(new Date(y, m - 1, d), d, m, y, false);
881
+ }
882
+ for (let d = 1; d <= daysInMonth; d++) {
883
+ pushCell(new Date(year, month - 1, d), d, month, year, true);
884
+ }
885
+ const remaining = 42 - grid.length;
886
+ for (let d = 1; d <= remaining; d++) {
887
+ const m = month + 1 > 12 ? 1 : month + 1;
888
+ const y = month + 1 > 12 ? year + 1 : year;
889
+ pushCell(new Date(y, m - 1, d), d, m, y, false);
890
+ }
891
+ const thursdayOffset = (4 - firstDayOfWeek + 7) % 7;
892
+ for (let row = 0; row < grid.length; row += 7) {
893
+ const weekNumber = getISOWeekNumber(grid[row + thursdayOffset].solar);
894
+ for (let i = row; i < row + 7; i++) {
895
+ grid[i].weekNumber = weekNumber;
896
+ }
897
+ }
898
+ return grid;
477
899
  }
478
900
  export {
479
901
  LichTa,
480
902
  formatLunarDate,
481
903
  formatTraditional,
904
+ getAuspiciousHourIndices,
482
905
  getAuspiciousHours,
906
+ getCalendarGrid,
483
907
  getDayCanChi,
908
+ getDayElement,
909
+ getDayElementIndex,
484
910
  getDayName,
911
+ getElementName,
912
+ getElementRelation,
913
+ getElementRelationIndex,
914
+ getHaiBranchIndex,
485
915
  getHourCanChi,
916
+ getHourElement,
917
+ getHourElementIndex,
918
+ getISOWeekNumber,
919
+ getInauspiciousHourIndices,
920
+ getInauspiciousHours,
486
921
  getMonthCanChi,
922
+ getMonthElement,
923
+ getMonthElementIndex,
487
924
  getMonthName,
925
+ getSolarTerm,
926
+ getSolarTermName,
927
+ getSolarTermsInYear,
928
+ getTruc,
929
+ getTrucIndex,
930
+ getTrucName,
931
+ getTrucQuality,
932
+ getTrucQualityIndex,
933
+ getTuHanhXungGroupIndex,
934
+ getTuHanhXungGroupMembers,
935
+ getWeekDayLabels,
936
+ getXungBranchIndex,
488
937
  getYearDetails,
489
938
  getZodiacAnimal,
939
+ getZodiacConflicts,
940
+ isHai,
941
+ isTuHanhXung,
942
+ isXung,
490
943
  jdFromDate,
491
944
  jdToDate,
492
945
  t