@thyrith/momentkh 3.0.0 → 3.0.2
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 +134 -114
- package/dist/momentkh.d.ts +65 -36
- package/dist/momentkh.d.ts.map +1 -1
- package/dist/momentkh.js +152 -112
- package/momentkh.js +1117 -11
- package/momentkh.ts +169 -125
- package/package.json +3 -2
package/momentkh.ts
CHANGED
|
@@ -24,20 +24,20 @@ export enum MoonPhase {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export enum MonthIndex {
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
Migasir = 0, // មិគសិរ
|
|
28
|
+
Boss = 1, // បុស្ស
|
|
29
29
|
Meak = 2, // មាឃ
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
Phalkun = 3, // ផល្គុន
|
|
31
|
+
Cheit = 4, // ចេត្រ
|
|
32
|
+
Pisakh = 5, // ពិសាខ
|
|
33
33
|
Jesth = 6, // ជេស្ឋ
|
|
34
|
-
|
|
34
|
+
Asadh = 7, // អាសាឍ
|
|
35
35
|
Srap = 8, // ស្រាពណ៍
|
|
36
|
-
|
|
36
|
+
Phatrabot = 9, // ភទ្របទ
|
|
37
37
|
Assoch = 10, // អស្សុជ
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
Kadeuk = 11, // កត្ដិក
|
|
39
|
+
Pathamasadh = 12, // បឋមាសាឍ
|
|
40
|
+
Tutiyasadh = 13 // ទុតិយាសាឍ
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export enum AnimalYear {
|
|
@@ -55,17 +55,17 @@ export enum AnimalYear {
|
|
|
55
55
|
Kor = 11 // កុរ - Pig
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
export enum
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
58
|
+
export enum Sak {
|
|
59
|
+
SamridhiSak = 0, // សំរឹទ្ធិស័ក
|
|
60
|
+
AekSak = 1, // ឯកស័ក
|
|
61
|
+
ToSak = 2, // ទោស័ក
|
|
62
|
+
TreiSak = 3, // ត្រីស័ក
|
|
63
|
+
ChattvaSak = 4, // ចត្វាស័ក
|
|
64
|
+
PanchaSak = 5, // បញ្ចស័ក
|
|
65
|
+
ChhaSak = 6, // ឆស័ក
|
|
66
|
+
SappaSak = 7, // សប្តស័ក
|
|
67
|
+
AtthaSak = 8, // អដ្ឋស័ក
|
|
68
|
+
NappaSak = 9 // នព្វស័ក
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
export enum DayOfWeek {
|
|
@@ -94,12 +94,12 @@ export interface KhmerDateInfo {
|
|
|
94
94
|
moonPhaseName: string; // String name: "កើត" or "រោច"
|
|
95
95
|
monthIndex: MonthIndex; // Enum: MonthIndex (0-13)
|
|
96
96
|
monthName: string; // String name of the month
|
|
97
|
-
beYear: number; // Buddhist
|
|
97
|
+
beYear: number; // Buddhist Sak
|
|
98
98
|
jsYear: number; // Jolak Sakaraj year
|
|
99
99
|
animalYear: AnimalYear; // Enum: AnimalYear (0-11)
|
|
100
100
|
animalYearName: string; // String name of animal year
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
sak: Sak; // Enum: Sak (0-9)
|
|
102
|
+
sakName: string; // String name of Sak
|
|
103
103
|
dayOfWeek: DayOfWeek; // Enum: DayOfWeek (0-6)
|
|
104
104
|
dayOfWeekName: string; // String name of day of week
|
|
105
105
|
}
|
|
@@ -159,10 +159,18 @@ export interface Constants {
|
|
|
159
159
|
LunarMonths: Record<string, number>;
|
|
160
160
|
LunarMonthNames: string[];
|
|
161
161
|
SolarMonthNames: string[];
|
|
162
|
+
SolarMonthAbbreviationNames: string[];
|
|
163
|
+
LunarMonthAbbreviationNames: string[];
|
|
162
164
|
AnimalYearNames: string[];
|
|
163
|
-
|
|
165
|
+
AnimalYearEmojis: string[];
|
|
166
|
+
SakNames: string[];
|
|
164
167
|
WeekdayNames: string[];
|
|
165
|
-
|
|
168
|
+
WeekdayNamesShort: string[];
|
|
169
|
+
MoonPhaseNames: string[];
|
|
170
|
+
MoonPhaseShort: string[];
|
|
171
|
+
MoonDaySymbols: string[];
|
|
172
|
+
KhmerNumerals: Record<string, string>;
|
|
173
|
+
khNewYearMoments: Record<string, string>;
|
|
166
174
|
}
|
|
167
175
|
|
|
168
176
|
// ============================================================================
|
|
@@ -187,12 +195,28 @@ const SolarMonthNames: string[] = [
|
|
|
187
195
|
'កក្កដា', 'សីហា', 'កញ្ញា', 'តុលា', 'វិច្ឆិកា', 'ធ្នូ'
|
|
188
196
|
];
|
|
189
197
|
|
|
198
|
+
const SolarMonthAbbreviationNames: string[] = [
|
|
199
|
+
'មក', 'កម', 'មន', 'មស', 'ឧស', 'មថ',
|
|
200
|
+
'កដ', 'សហ', 'កញ', 'តល', 'វក', 'ធន'
|
|
201
|
+
];
|
|
202
|
+
|
|
203
|
+
const LunarMonthAbbreviationNames: string[] = [
|
|
204
|
+
'មិ', 'បុ', 'មា', 'ផល', 'ចេ', 'ពិ',
|
|
205
|
+
'ជេ', 'អា', 'ស្រ', 'ភ', 'អ', 'ក',
|
|
206
|
+
'បឋ', 'ទុតិ'
|
|
207
|
+
];
|
|
208
|
+
|
|
190
209
|
const AnimalYearNames: string[] = [
|
|
191
210
|
'ជូត', 'ឆ្លូវ', 'ខាល', 'ថោះ', 'រោង', 'ម្សាញ់',
|
|
192
211
|
'មមី', 'មមែ', 'វក', 'រកា', 'ច', 'កុរ'
|
|
193
212
|
];
|
|
194
213
|
|
|
195
|
-
const
|
|
214
|
+
const AnimalYearEmojis: string[] = [
|
|
215
|
+
'🐀', '🐂', '🐅', '🐇', '🐉', '🐍',
|
|
216
|
+
'🐎', '🐐', '🐒', '🐓', '🐕', '🐖'
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
const SakNames: string[] = [
|
|
196
220
|
'សំរឹទ្ធិស័ក', 'ឯកស័ក', 'ទោស័ក', 'ត្រីស័ក', 'ចត្វាស័ក',
|
|
197
221
|
'បញ្ចស័ក', 'ឆស័ក', 'សប្តស័ក', 'អដ្ឋស័ក', 'នព្វស័ក'
|
|
198
222
|
];
|
|
@@ -203,8 +227,8 @@ const WeekdayNames: string[] = [
|
|
|
203
227
|
|
|
204
228
|
const WeekdayNamesShort: string[] = ['អា', 'ច', 'អ', 'ព', 'ព្រ', 'សុ', 'ស'];
|
|
205
229
|
|
|
206
|
-
const
|
|
207
|
-
const
|
|
230
|
+
const MoonPhaseNames: string[] = ['កើត', 'រោច'];
|
|
231
|
+
const MoonPhaseShort: string[] = ['ក', 'រ'];
|
|
208
232
|
|
|
209
233
|
const MoonDaySymbols: string[] = [
|
|
210
234
|
'᧡', '᧢', '᧣', '᧤', '᧥', '᧦', '᧧', '᧨', '᧩', '᧪',
|
|
@@ -531,7 +555,7 @@ function getNumberOfDaysInKhmerMonth(monthIndex: MonthIndex | number, beYear: nu
|
|
|
531
555
|
if (idx === MonthIndex.Jesth && leapType === 2) { // ជេស្ឋ with leap day
|
|
532
556
|
return 30;
|
|
533
557
|
}
|
|
534
|
-
if (idx === MonthIndex.
|
|
558
|
+
if (idx === MonthIndex.Pathamasadh || idx === MonthIndex.Tutiyasadh) { // បឋមាសាឍ, ទុតិយាសាឍ
|
|
535
559
|
return leapType === 1 ? 30 : 0;
|
|
536
560
|
}
|
|
537
561
|
// Alternating pattern: even months = 29 days, odd months = 30 days
|
|
@@ -551,11 +575,11 @@ function nextMonthOf(monthIndex: MonthIndex | number, beYear: number): MonthInde
|
|
|
551
575
|
const idx = typeof monthIndex === 'number' ? monthIndex : monthIndex as number;
|
|
552
576
|
|
|
553
577
|
if (idx === MonthIndex.Jesth && leapType === 1) { // ជេស្ឋ in leap month year
|
|
554
|
-
return MonthIndex.
|
|
578
|
+
return MonthIndex.Pathamasadh; // បឋមាសាឍ
|
|
555
579
|
}
|
|
556
|
-
if (idx === MonthIndex.
|
|
557
|
-
if (idx === MonthIndex.
|
|
558
|
-
if (idx === MonthIndex.
|
|
580
|
+
if (idx === MonthIndex.Kadeuk) return MonthIndex.Migasir; // កត្ដិក -> មិគសិរ
|
|
581
|
+
if (idx === MonthIndex.Pathamasadh) return MonthIndex.Tutiyasadh; // បឋមាសាឍ -> ទុតិយាសាឍ
|
|
582
|
+
if (idx === MonthIndex.Tutiyasadh) return MonthIndex.Srap; // ទុតិយាសាឍ -> ស្រាពណ៍
|
|
559
583
|
|
|
560
584
|
return (idx + 1) as MonthIndex;
|
|
561
585
|
}
|
|
@@ -564,10 +588,10 @@ function previousMonthOf(monthIndex: MonthIndex | number, beYear: number): Month
|
|
|
564
588
|
const leapType = getLeapType(beYear);
|
|
565
589
|
const idx = typeof monthIndex === 'number' ? monthIndex : monthIndex as number;
|
|
566
590
|
|
|
567
|
-
if (idx === MonthIndex.
|
|
568
|
-
if (idx === MonthIndex.Srap && leapType === 1) return MonthIndex.
|
|
569
|
-
if (idx === MonthIndex.
|
|
570
|
-
if (idx === MonthIndex.
|
|
591
|
+
if (idx === MonthIndex.Migasir) return MonthIndex.Kadeuk; // មិគសិរ -> កត្ដិក
|
|
592
|
+
if (idx === MonthIndex.Srap && leapType === 1) return MonthIndex.Tutiyasadh; // ស្រាពណ៍ -> ទុតិយាសាឍ (leap)
|
|
593
|
+
if (idx === MonthIndex.Tutiyasadh) return MonthIndex.Pathamasadh; // ទុតិយាសាឍ -> បឋមាសាឍ
|
|
594
|
+
if (idx === MonthIndex.Pathamasadh) return MonthIndex.Jesth; // បឋមាសាឍ -> ជេស្ឋ
|
|
571
595
|
|
|
572
596
|
return (idx - 1) as MonthIndex;
|
|
573
597
|
}
|
|
@@ -784,7 +808,7 @@ class KhmerDate {
|
|
|
784
808
|
const newDay = KhmerDate.fromDayNumber(newDayNum);
|
|
785
809
|
|
|
786
810
|
let newBeYear = result.beYear;
|
|
787
|
-
if (result.monthIndex === MonthIndex.
|
|
811
|
+
if (result.monthIndex === MonthIndex.Pisakh) { // ពិសាខ
|
|
788
812
|
if (result.moonPhase === MoonPhase.Waxing && newDay.moonPhase === MoonPhase.Waning) {
|
|
789
813
|
newBeYear++;
|
|
790
814
|
}
|
|
@@ -795,7 +819,7 @@ class KhmerDate {
|
|
|
795
819
|
} else {
|
|
796
820
|
remaining -= (daysLeftInMonth + 1);
|
|
797
821
|
const nextMonth = nextMonthOf(result.monthIndex, result.beYear);
|
|
798
|
-
const newBeYear = (result.monthIndex === MonthIndex.
|
|
822
|
+
const newBeYear = (result.monthIndex === MonthIndex.Cheit) ? result.beYear + 1 : result.beYear;
|
|
799
823
|
result = new KhmerDate(1, MoonPhase.Waxing, nextMonth, newBeYear); // Start at 1កើត
|
|
800
824
|
}
|
|
801
825
|
}
|
|
@@ -817,7 +841,7 @@ class KhmerDate {
|
|
|
817
841
|
const newDay = KhmerDate.fromDayNumber(newDayNum);
|
|
818
842
|
|
|
819
843
|
let newBeYear = result.beYear;
|
|
820
|
-
if (result.monthIndex === MonthIndex.
|
|
844
|
+
if (result.monthIndex === MonthIndex.Pisakh) { // ពិសាខ
|
|
821
845
|
if (result.moonPhase === MoonPhase.Waning && newDay.moonPhase === MoonPhase.Waxing) {
|
|
822
846
|
newBeYear--;
|
|
823
847
|
}
|
|
@@ -828,7 +852,7 @@ class KhmerDate {
|
|
|
828
852
|
} else {
|
|
829
853
|
remaining -= (currentDayNum + 1);
|
|
830
854
|
const prevMonth = previousMonthOf(result.monthIndex, result.beYear);
|
|
831
|
-
const newBeYear = (result.monthIndex === MonthIndex.
|
|
855
|
+
const newBeYear = (result.monthIndex === MonthIndex.Pisakh) ? result.beYear - 1 : result.beYear;
|
|
832
856
|
const daysInPrevMonth = getNumberOfDaysInKhmerMonth(prevMonth, newBeYear);
|
|
833
857
|
const newDay = KhmerDate.fromDayNumber(daysInPrevMonth - 1);
|
|
834
858
|
result = new KhmerDate(newDay.day, newDay.moonPhase, prevMonth, newBeYear);
|
|
@@ -839,7 +863,7 @@ class KhmerDate {
|
|
|
839
863
|
}
|
|
840
864
|
|
|
841
865
|
toString(): string {
|
|
842
|
-
return `${this.day}${
|
|
866
|
+
return `${this.day}${MoonPhaseNames[this.moonPhase]} ខែ${LunarMonthNames[this.monthIndex]} ព.ស.${this.beYear}`;
|
|
843
867
|
}
|
|
844
868
|
}
|
|
845
869
|
|
|
@@ -857,7 +881,7 @@ function getMaybeBEYear(year: number, month: number): number {
|
|
|
857
881
|
}
|
|
858
882
|
}
|
|
859
883
|
|
|
860
|
-
// Cache for
|
|
884
|
+
// Cache for Pisakha Bochea dates by year
|
|
861
885
|
const visakhaBocheaCache: Record<number, number> = {};
|
|
862
886
|
|
|
863
887
|
// Cache for New Year Full Info
|
|
@@ -868,7 +892,7 @@ const newYearInfoCache: Record<number, NewYearFullInfo> = {};
|
|
|
868
892
|
* BE year increases on ១រោច ខែពិសាខ (1st waning day of Pisakh = dayNumber 15 of month 5)
|
|
869
893
|
* Returns timestamp in milliseconds at midnight of that day
|
|
870
894
|
*/
|
|
871
|
-
function
|
|
895
|
+
function getPisakhaBochea(year: number, isSearching: boolean = false): number {
|
|
872
896
|
if (visakhaBocheaCache[year]) {
|
|
873
897
|
return visakhaBocheaCache[year];
|
|
874
898
|
}
|
|
@@ -879,7 +903,7 @@ function getVisakhaBochea(year: number, isSearching: boolean = false): number {
|
|
|
879
903
|
for (let searchDay = 1; searchDay <= daysInMonth; searchDay++) {
|
|
880
904
|
// Avoid infinite recursion by using simplified BE year during search
|
|
881
905
|
const result = gregorianToKhmerInternal(year, searchMonth, searchDay, 12, 0, 0, true);
|
|
882
|
-
if (result.khmer.monthIndex === MonthIndex.
|
|
906
|
+
if (result.khmer.monthIndex === MonthIndex.Pisakh && result._khmerDateObj.getDayNumber() === 15) {
|
|
883
907
|
// Found 1រោច Pisakh - return timestamp at midnight (start of BE year change day)
|
|
884
908
|
// BE year changes at 00:00 on this day
|
|
885
909
|
const timestamp = new Date(year, searchMonth - 1, searchDay, 0, 0, 0, 0).getTime();
|
|
@@ -982,7 +1006,7 @@ function gregorianToKhmerInternal(
|
|
|
982
1006
|
} else {
|
|
983
1007
|
// Normal mode: compare against exact BE year transition datetime (1រោច Pisakh at 00:00)
|
|
984
1008
|
const inputTimestamp = new Date(year, month - 1, day, hour, minute, second).getTime();
|
|
985
|
-
const beYearTransitionTimestamp =
|
|
1009
|
+
const beYearTransitionTimestamp = getPisakhaBochea(year);
|
|
986
1010
|
|
|
987
1011
|
if (inputTimestamp >= beYearTransitionTimestamp) {
|
|
988
1012
|
// On or after 1រោច Pisakh (new BE year)
|
|
@@ -998,15 +1022,15 @@ function gregorianToKhmerInternal(
|
|
|
998
1022
|
let animalYearIndex = ((beYear + 4) % 12 + 12) % 12;
|
|
999
1023
|
|
|
1000
1024
|
// Adjust Era and Animal Year based on Khmer New Year logic
|
|
1001
|
-
// They should change at New Year, not wait for
|
|
1025
|
+
// They should change at New Year, not wait for Pisakha Bochea (which changes BE)
|
|
1002
1026
|
if (!isSearching) {
|
|
1003
1027
|
const newYearInfo = getNewYearFullInfo(year);
|
|
1004
1028
|
const inputTimestamp = new Date(year, month - 1, day, hour, minute, second).getTime();
|
|
1005
|
-
const visakhaBocheaTimestamp =
|
|
1029
|
+
const visakhaBocheaTimestamp = getPisakhaBochea(year);
|
|
1006
1030
|
|
|
1007
1031
|
// Animal Year changes at Moha Songkran (exact New Year time)
|
|
1008
|
-
// Only apply manual increment if we are in the gap between New Year and
|
|
1009
|
-
// (After
|
|
1032
|
+
// Only apply manual increment if we are in the gap between New Year and Pisakha Bochea
|
|
1033
|
+
// (After Pisakha Bochea, the BE year increments, so the formula based on BE automatically gives the new Animal Year)
|
|
1010
1034
|
if (inputTimestamp >= newYearInfo.newYearMoment.getTime() && inputTimestamp <= visakhaBocheaTimestamp) {
|
|
1011
1035
|
animalYearIndex = (animalYearIndex + 1) % 12;
|
|
1012
1036
|
}
|
|
@@ -1017,7 +1041,7 @@ function gregorianToKhmerInternal(
|
|
|
1017
1041
|
}
|
|
1018
1042
|
}
|
|
1019
1043
|
|
|
1020
|
-
const
|
|
1044
|
+
const sakIndex = ((jsYear % 10) + 10) % 10;
|
|
1021
1045
|
const dayOfWeek = getDayOfWeek(year, month, day);
|
|
1022
1046
|
|
|
1023
1047
|
const khmerDate = new KhmerDate(khmerDayInfo.day, khmerDayInfo.moonPhase, khmerMonth as MonthIndex, beYear);
|
|
@@ -1027,15 +1051,15 @@ function gregorianToKhmerInternal(
|
|
|
1027
1051
|
khmer: {
|
|
1028
1052
|
day: khmerDayInfo.day,
|
|
1029
1053
|
moonPhase: khmerDayInfo.moonPhase,
|
|
1030
|
-
moonPhaseName:
|
|
1054
|
+
moonPhaseName: MoonPhaseNames[khmerDayInfo.moonPhase],
|
|
1031
1055
|
monthIndex: khmerMonth as MonthIndex,
|
|
1032
1056
|
monthName: LunarMonthNames[khmerMonth],
|
|
1033
1057
|
beYear: beYear,
|
|
1034
1058
|
jsYear: jsYear,
|
|
1035
1059
|
animalYear: animalYearIndex as AnimalYear,
|
|
1036
1060
|
animalYearName: AnimalYearNames[animalYearIndex],
|
|
1037
|
-
|
|
1038
|
-
|
|
1061
|
+
sak: sakIndex as Sak,
|
|
1062
|
+
sakName: SakNames[sakIndex],
|
|
1039
1063
|
dayOfWeek: dayOfWeek as DayOfWeek,
|
|
1040
1064
|
dayOfWeekName: WeekdayNames[dayOfWeek]
|
|
1041
1065
|
},
|
|
@@ -1068,7 +1092,7 @@ function khmerToGregorian(day: number, moonPhase: MoonPhase | number, monthIndex
|
|
|
1068
1092
|
for (let gDay = 1; gDay <= daysInMonth; gDay++) {
|
|
1069
1093
|
// For BE year transition day (1រោច Pisakh) and the day before (15កើត Pisakh),
|
|
1070
1094
|
// check multiple times during the day because BE year can change during this period
|
|
1071
|
-
const isAroundBEYearChange = monthIndexNum === MonthIndex.
|
|
1095
|
+
const isAroundBEYearChange = monthIndexNum === MonthIndex.Pisakh &&
|
|
1072
1096
|
((day === 15 && moonPhaseNum === MoonPhase.Waxing) || (day === 1 && moonPhaseNum === MoonPhase.Waning));
|
|
1073
1097
|
const timesToCheck = isAroundBEYearChange
|
|
1074
1098
|
? [0, 6, 12, 18, 23] // Check at different hours
|
|
@@ -1225,13 +1249,13 @@ function getKhmerNewYear(ceYear: number): NewYearInfo {
|
|
|
1225
1249
|
// Formatting Functions
|
|
1226
1250
|
// ============================================================================
|
|
1227
1251
|
|
|
1228
|
-
function
|
|
1252
|
+
function formatKhmer(khmerData: KhmerConversionResult, formatString?: string): string {
|
|
1229
1253
|
if (!formatString) {
|
|
1230
1254
|
// Default format
|
|
1231
1255
|
const { khmer } = khmerData;
|
|
1232
1256
|
const moonDay = `${khmer.day}${khmer.moonPhaseName}`;
|
|
1233
1257
|
return toKhmerNumeral(
|
|
1234
|
-
`ថ្ងៃ${khmer.dayOfWeekName} ${moonDay} ខែ${khmer.monthName} ឆ្នាំ${khmer.animalYearName} ${khmer.
|
|
1258
|
+
`ថ្ងៃ${khmer.dayOfWeekName} ${moonDay} ខែ${khmer.monthName} ឆ្នាំ${khmer.animalYearName} ${khmer.sakName} ពុទ្ធសករាជ ${khmer.beYear}`
|
|
1235
1259
|
);
|
|
1236
1260
|
}
|
|
1237
1261
|
|
|
@@ -1239,24 +1263,38 @@ function format(khmerData: KhmerConversionResult, formatString?: string): string
|
|
|
1239
1263
|
const formatRules: Record<string, () => string | number> = {
|
|
1240
1264
|
'W': () => khmerData.khmer.dayOfWeekName,
|
|
1241
1265
|
'w': () => WeekdayNamesShort[khmerData.gregorian.dayOfWeek],
|
|
1242
|
-
'd': () => khmerData.khmer.day,
|
|
1243
|
-
'D': () => (khmerData.khmer.day < 10 ? '0' : '') + khmerData.khmer.day,
|
|
1244
|
-
'
|
|
1266
|
+
'd': () => toKhmerNumeral(khmerData.khmer.day),
|
|
1267
|
+
'D': () => toKhmerNumeral((khmerData.khmer.day < 10 ? '0' : '') + khmerData.khmer.day),
|
|
1268
|
+
'dr': () => khmerData.khmer.day,
|
|
1269
|
+
'Dr': () => (khmerData.khmer.day < 10 ? '0' : '') + khmerData.khmer.day,
|
|
1270
|
+
'n': () => MoonPhaseShort[khmerData.khmer.moonPhase],
|
|
1245
1271
|
'N': () => khmerData.khmer.moonPhaseName,
|
|
1246
1272
|
'o': () => MoonDaySymbols[khmerData._khmerDateObj.getDayNumber()],
|
|
1247
1273
|
'm': () => khmerData.khmer.monthName,
|
|
1248
1274
|
'M': () => SolarMonthNames[khmerData.gregorian.month - 1],
|
|
1249
1275
|
'a': () => khmerData.khmer.animalYearName,
|
|
1250
|
-
'
|
|
1251
|
-
'
|
|
1252
|
-
'
|
|
1253
|
-
'
|
|
1276
|
+
'as': () => AnimalYearEmojis[khmerData.khmer.animalYear],
|
|
1277
|
+
'e': () => khmerData.khmer.sakName,
|
|
1278
|
+
'b': () => toKhmerNumeral(khmerData.khmer.beYear),
|
|
1279
|
+
'br': () => khmerData.khmer.beYear,
|
|
1280
|
+
'c': () => toKhmerNumeral(khmerData.gregorian.year),
|
|
1281
|
+
'cr': () => khmerData.gregorian.year,
|
|
1282
|
+
'j': () => toKhmerNumeral(khmerData.khmer.jsYear),
|
|
1283
|
+
'jr': () => khmerData.khmer.jsYear,
|
|
1284
|
+
'Ms': () => SolarMonthAbbreviationNames[khmerData.gregorian.month - 1],
|
|
1285
|
+
'ms': () => LunarMonthAbbreviationNames[khmerData.khmer.monthIndex]
|
|
1254
1286
|
};
|
|
1255
1287
|
|
|
1256
|
-
|
|
1257
|
-
const
|
|
1258
|
-
|
|
1259
|
-
|
|
1288
|
+
// Sort keys by length descending to ensure longer tokens (like 'Ms', 'ms') are matched before shorter ones (like 'M', 'm')
|
|
1289
|
+
const sortedKeys = Object.keys(formatRules).sort((a, b) => b.length - a.length);
|
|
1290
|
+
const regex = new RegExp(`\\[([^\\]]+)\\]|(${sortedKeys.join('|')})`, 'g');
|
|
1291
|
+
|
|
1292
|
+
const result = formatString.replace(regex, (match, escaped, token) => {
|
|
1293
|
+
if (escaped) {
|
|
1294
|
+
return escaped;
|
|
1295
|
+
}
|
|
1296
|
+
const value = formatRules[token]();
|
|
1297
|
+
return String(value);
|
|
1260
1298
|
});
|
|
1261
1299
|
|
|
1262
1300
|
return result;
|
|
@@ -1274,64 +1312,70 @@ function gregorianToKhmer(year: number, month: number, day: number, hour: number
|
|
|
1274
1312
|
// Public API
|
|
1275
1313
|
// ============================================================================
|
|
1276
1314
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
//
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1315
|
+
// Conversion functions
|
|
1316
|
+
export function fromGregorian(year: number, month: number, day: number, hour: number = 0, minute: number = 0, second: number = 0): KhmerConversionResult {
|
|
1317
|
+
return gregorianToKhmer(year, month, day, hour, minute, second);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
export function fromKhmer(day: number, moonPhase: MoonPhase | number, monthIndex: MonthIndex | number, beYear: number): GregorianDate {
|
|
1321
|
+
return khmerToGregorian(day, moonPhase, monthIndex, beYear);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// New Year function
|
|
1325
|
+
export function getNewYear(ceYear: number): NewYearInfo {
|
|
1326
|
+
return getKhmerNewYear(ceYear);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// Format function
|
|
1330
|
+
export function format(khmerData: KhmerConversionResult, formatString?: string): string {
|
|
1331
|
+
return formatKhmer(khmerData, formatString);
|
|
1332
|
+
}
|
|
1333
|
+
// Utility for creating date from Date object
|
|
1334
|
+
export function fromDate(date: Date): KhmerConversionResult {
|
|
1335
|
+
// Validate Date object
|
|
1336
|
+
validateDateObject(date);
|
|
1337
|
+
return gregorianToKhmer(
|
|
1338
|
+
date.getFullYear(),
|
|
1339
|
+
date.getMonth() + 1,
|
|
1340
|
+
date.getDate(),
|
|
1341
|
+
date.getHours(),
|
|
1342
|
+
date.getMinutes(),
|
|
1343
|
+
date.getSeconds()
|
|
1344
|
+
);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
// Convert Khmer to Date object
|
|
1348
|
+
export function toDate(day: number, moonPhase: MoonPhase | number, monthIndex: MonthIndex | number, beYear: number): Date {
|
|
1349
|
+
const greg = khmerToGregorian(day, moonPhase, monthIndex, beYear);
|
|
1350
|
+
return new Date(greg.year, greg.month - 1, greg.day);
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
// Constants export
|
|
1354
|
+
export const constants = {
|
|
1355
|
+
LunarMonths,
|
|
1356
|
+
LunarMonthNames,
|
|
1357
|
+
SolarMonthNames,
|
|
1358
|
+
SolarMonthAbbreviationNames,
|
|
1359
|
+
LunarMonthAbbreviationNames,
|
|
1360
|
+
AnimalYearNames,
|
|
1361
|
+
AnimalYearEmojis,
|
|
1362
|
+
SakNames,
|
|
1363
|
+
WeekdayNames,
|
|
1364
|
+
MoonPhaseNames
|
|
1365
|
+
};
|
|
1366
|
+
|
|
1367
|
+
// Default export - aggregate all exports for convenience
|
|
1368
|
+
export default {
|
|
1369
|
+
fromGregorian,
|
|
1370
|
+
fromKhmer,
|
|
1371
|
+
getNewYear,
|
|
1372
|
+
format,
|
|
1373
|
+
fromDate,
|
|
1374
|
+
toDate,
|
|
1375
|
+
constants,
|
|
1329
1376
|
MoonPhase,
|
|
1330
1377
|
MonthIndex,
|
|
1331
1378
|
AnimalYear,
|
|
1332
|
-
|
|
1379
|
+
Sak,
|
|
1333
1380
|
DayOfWeek
|
|
1334
1381
|
};
|
|
1335
|
-
|
|
1336
|
-
// Default export
|
|
1337
|
-
export default momentkh;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thyrith/momentkh",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Working on khmer calendar by implementting moment js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "component",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"LICENSE"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"build": "tsc",
|
|
19
|
+
"build": "tsc && node build-browser.js",
|
|
20
|
+
"build:dist": "tsc",
|
|
20
21
|
"test": "npm run test:validation && npm run test:gregorian && npm run test:khmer && npm run test:newyear && npm run test:verify-conversion && npm run test:verify-newyear && npm run test:verify-roundtrip",
|
|
21
22
|
"test:validation": "node test/validation.test.js",
|
|
22
23
|
"test:gregorian": "node test/gregorian-to-khmer.test.js",
|