@thyrith/momentkh 2.5.5 → 3.0.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/README.md +1298 -93
- package/dist/momentkh.d.ts +181 -0
- package/dist/momentkh.d.ts.map +1 -0
- package/dist/momentkh.js +1052 -0
- package/momentkh.js +13 -673
- package/momentkh.ts +1337 -0
- package/package.json +24 -2
- package/constant.js +0 -58
- package/example/newYearMoment.js +0 -4
- package/example/toKhDate.js +0 -6
- package/getSoriyatraLerngSak.js +0 -301
- package/index.html +0 -169
- package/locale/km.js +0 -70
package/README.md
CHANGED
|
@@ -1,128 +1,1333 @@
|
|
|
1
|
-
|
|
2
|
-
[](https://github.com/ThyrithSor/momentkh/issues)
|
|
3
|
-
[]()
|
|
4
|
-
[]()
|
|
5
|
-
[]()
|
|
1
|
+
# 🇰🇭 MomentKH - Complete Khmer Calendar Library
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
momentkh is an add-on feature to moment js library [DEMO](https://thyrithsor.github.io/momentkh).
|
|
3
|
+
**MomentKH** is a lightweight, zero-dependency JavaScript/TypeScript library for accurate Khmer (Cambodian) Lunar Calendar conversions. It provides a modern, standalone implementation with full TypeScript support.
|
|
9
4
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
$ npm install @thyrith/momentkh --save
|
|
14
|
-
```
|
|
5
|
+
[](https://github.com/ThyrithSor/momentkh)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://github.com/ThyrithSor/momentkh)
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## ⚡ TLDR - Quick Start
|
|
19
12
|
|
|
20
|
-
### Nodejs
|
|
21
13
|
```javascript
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
require('@thyrith/momentkh')(moment);
|
|
14
|
+
// Import
|
|
15
|
+
const momentkh = require("@thyrith/momentkh");
|
|
25
16
|
|
|
26
|
-
//
|
|
17
|
+
// Convert date to Khmer format (default)
|
|
18
|
+
const khmer = momentkh.fromDate(new Date());
|
|
19
|
+
console.log(momentkh.format(khmer));
|
|
20
|
+
// Output: ថ្ងៃចន្ទ ១៦រោច ខែមិគសិរ ឆ្នាំរោង ឆស័ក ពុទ្ធសករាជ ២៥៦៨
|
|
27
21
|
|
|
28
|
-
|
|
22
|
+
// Convert date to Khmer format (custom)
|
|
23
|
+
console.log(momentkh.format(khmer, "dN ខែm ឆ្នាំa"));
|
|
24
|
+
// Output: ១៦រោច ខែមិគសិរ ឆ្នាំរោង
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
// Convert Khmer date to Gregorian
|
|
27
|
+
const gregorian = momentkh.fromKhmer(15, 0, 5, 2568); // 15កើត ខែពិសាខ ព.ស.២៥៦៨
|
|
28
|
+
console.log(gregorian);
|
|
29
|
+
// Output: { year: 2025, month: 5, day: 11 }
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
// Get Khmer New Year
|
|
32
|
+
const newYear = momentkh.getNewYear(2025);
|
|
33
|
+
console.log(newYear);
|
|
34
|
+
// Output: { year: 2025, month: 4, day: 13, hour: 20, minute: 9 }
|
|
35
|
+
```
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 📑 Table of Contents
|
|
40
|
+
|
|
41
|
+
- [Features](#-features)
|
|
42
|
+
- [Installation](#-installation)
|
|
43
|
+
- [Quick Start](#-quick-start)
|
|
44
|
+
- [API Reference](#-api-reference)
|
|
45
|
+
- [fromGregorian()](#fromgregorianyear-month-day-hour-minute-second)
|
|
46
|
+
- [fromKhmer()](#fromkhmerday-moonphase-monthindex-beyear)
|
|
47
|
+
- [fromDate()](#fromdatedateobject)
|
|
48
|
+
- [toDate()](#todateday-moonphase-monthindex-beyear)
|
|
49
|
+
- [getNewYear()](#getnewyearyear)
|
|
50
|
+
- [format()](#formatkhmerdata-formatstring)
|
|
51
|
+
- [Using Enums (NEW in v3.0)](#-using-enums-new-in-v30)
|
|
52
|
+
- [Understanding Khmer Calendar](#-understanding-khmer-calendar)
|
|
53
|
+
- [Buddhist Era (BE) Year](#buddhist-era-be-year)
|
|
54
|
+
- [Animal Year](#animal-year)
|
|
55
|
+
- [Era Year (Sak)](#era-year-sak)
|
|
56
|
+
- [When Each Year Type Increases](#when-each-year-type-increases)
|
|
57
|
+
- [Format Codes](#-format-codes)
|
|
58
|
+
- [Constants](#-constants)
|
|
59
|
+
- [Migration Guide](#-migration-guide-from-momentkh-v1)
|
|
60
|
+
- [Examples](#-examples)
|
|
61
|
+
- [Browser Support](#-browser-support)
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## ✨ Features
|
|
66
|
+
|
|
67
|
+
- ✅ **Zero Dependencies** - Pure JavaScript, no external libraries required
|
|
68
|
+
- ✅ **TypeScript Support** - Full type definitions included for excellent IDE experience
|
|
69
|
+
- ✅ **Type-Safe Enums** - NEW in v3.0! Use enums for moonPhase, monthIndex, animalYear, eraYear, and dayOfWeek
|
|
70
|
+
- ✅ **Bidirectional Conversion** - Convert between Gregorian ↔ Khmer Lunar dates
|
|
71
|
+
- ✅ **Accurate Calculations** - Based on traditional Khmer astronomical algorithms
|
|
72
|
+
- ✅ **Khmer New Year** - Precise calculation of Moha Songkran timing
|
|
73
|
+
- ✅ **Flexible Formatting** - Customizable output with format tokens
|
|
74
|
+
- ✅ **Universal** - Works in Node.js, Browsers (ES5+), AMD, and ES Modules
|
|
75
|
+
- ✅ **Lightweight** - Single file (~36KB), no build step required
|
|
76
|
+
- ✅ **Well-Tested** - Comprehensive test suite with 1500+ test cases (100% pass rate)
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 📦 Installation
|
|
81
|
+
|
|
82
|
+
### NPM (Recommended)
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm install @thyrith/momentkh
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Direct Download
|
|
89
|
+
|
|
90
|
+
Download `momentkh.js` from the repository and include it in your project.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
cp momentkh.js /path/to/your/project/
|
|
39
94
|
```
|
|
40
95
|
|
|
41
|
-
###
|
|
42
|
-
|
|
96
|
+
### TypeScript
|
|
97
|
+
|
|
98
|
+
Type definitions are included automatically when you install via NPM. For direct downloads, you can also use `momentkh.ts` or the compiled `.d.ts` files from the `dist/` folder.
|
|
43
99
|
|
|
44
|
-
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 🚀 Quick Start
|
|
103
|
+
|
|
104
|
+
### Browser (HTML)
|
|
45
105
|
|
|
46
106
|
```html
|
|
47
|
-
<script src="
|
|
48
|
-
<script src="momentkh/constant.js"></script>
|
|
49
|
-
<script src="momentkh/locale/km.js"></script>
|
|
50
|
-
<script src="momentkh/getSoriyatraLerngSak.js"></script>
|
|
51
|
-
<script src="momentkh/momentkh.js"></script>
|
|
107
|
+
<script src="momentkh.js"></script>
|
|
52
108
|
<script>
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
109
|
+
// Convert today to Khmer
|
|
110
|
+
const today = new Date();
|
|
111
|
+
const khmer = momentkh.fromDate(today);
|
|
112
|
+
console.log(momentkh.format(khmer));
|
|
113
|
+
// Output: ថ្ងៃចន្ទ ១០កើត ខែចេត្រ ឆ្នាំរោង ឆស័ក ពុទ្ធសករាជ ២៥៦៧
|
|
57
114
|
</script>
|
|
58
115
|
```
|
|
59
116
|
|
|
60
|
-
|
|
117
|
+
### Node.js (CommonJS)
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
const momentkh = require("@thyrith/momentkh");
|
|
121
|
+
|
|
122
|
+
// Convert specific date
|
|
123
|
+
const khmer = momentkh.fromGregorian(2024, 4, 14, 10, 30);
|
|
124
|
+
console.log(momentkh.format(khmer));
|
|
125
|
+
|
|
126
|
+
// Get Khmer New Year
|
|
127
|
+
const newYear = momentkh.getNewYear(2024);
|
|
128
|
+
console.log(newYear); // { year: 2024, month: 4, day: 13, hour: 22, minute: 24 }
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### ES Modules
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
import momentkh from "@thyrith/momentkh";
|
|
135
|
+
|
|
136
|
+
const khmer = momentkh.fromDate(new Date());
|
|
137
|
+
console.log(momentkh.format(khmer));
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### TypeScript
|
|
141
|
+
|
|
142
|
+
Full TypeScript support with complete type definitions and enums:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import momentkh, {
|
|
146
|
+
KhmerConversionResult,
|
|
147
|
+
NewYearInfo,
|
|
148
|
+
GregorianDate,
|
|
149
|
+
MoonPhase,
|
|
150
|
+
MonthIndex,
|
|
151
|
+
AnimalYear,
|
|
152
|
+
EraYear,
|
|
153
|
+
DayOfWeek,
|
|
154
|
+
} from "@thyrith/momentkh";
|
|
155
|
+
|
|
156
|
+
// Convert with full type safety
|
|
157
|
+
const khmer: KhmerConversionResult = momentkh.fromGregorian(
|
|
158
|
+
2024,
|
|
159
|
+
4,
|
|
160
|
+
14,
|
|
161
|
+
10,
|
|
162
|
+
30
|
|
163
|
+
);
|
|
164
|
+
console.log(momentkh.format(khmer));
|
|
165
|
+
|
|
166
|
+
// Access enum values (NEW in v3.0!)
|
|
167
|
+
console.log(khmer.khmer.moonPhase === MoonPhase.Waxing); // Type-safe comparison
|
|
168
|
+
console.log(khmer.khmer.monthIndex === MonthIndex.Chetr); // Enum comparison
|
|
169
|
+
console.log(khmer.khmer.dayOfWeek === DayOfWeek.Sunday); // Autocomplete support!
|
|
170
|
+
|
|
171
|
+
// Reverse conversion with enums (type-safe!)
|
|
172
|
+
const gregorianDate: GregorianDate = momentkh.fromKhmer(
|
|
173
|
+
15,
|
|
174
|
+
MoonPhase.Waxing, // Use enum instead of 0
|
|
175
|
+
MonthIndex.Visakh, // Use enum instead of 5
|
|
176
|
+
2568
|
|
177
|
+
);
|
|
178
|
+
console.log(
|
|
179
|
+
`${gregorianDate.year}-${gregorianDate.month}-${gregorianDate.day}`
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// Still supports numbers for backward compatibility
|
|
183
|
+
const gregorianDate2: GregorianDate = momentkh.fromKhmer(15, 0, 5, 2568);
|
|
184
|
+
|
|
185
|
+
// Get New Year with typed result
|
|
186
|
+
const newYear: NewYearInfo = momentkh.getNewYear(2024);
|
|
187
|
+
console.log(
|
|
188
|
+
`${newYear.year}-${newYear.month}-${newYear.day} ${newYear.hour}:${newYear.minute}`
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
// Access constants with full autocomplete
|
|
192
|
+
const monthName = momentkh.constants.LunarMonthNames[4]; // "ចេត្រ"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Available Types:**
|
|
196
|
+
|
|
197
|
+
- `KhmerConversionResult` - Full conversion result object
|
|
198
|
+
- `GregorianDate` - Gregorian date object
|
|
199
|
+
- `KhmerDateInfo` - Khmer date information (now with enum fields!)
|
|
200
|
+
- `NewYearInfo` - New Year timing information
|
|
201
|
+
- `Constants` - Calendar constants interface
|
|
202
|
+
|
|
203
|
+
**Available Enums (NEW in v3.0):**
|
|
204
|
+
|
|
205
|
+
- 🌙 `MoonPhase` - Waxing (កើត) and Waning (រោច)
|
|
206
|
+
- 📅 `MonthIndex` - All 14 Khmer lunar months
|
|
207
|
+
- 🐉 `AnimalYear` - All 12 animal years
|
|
208
|
+
- ⭐ `EraYear` - All 10 era years
|
|
209
|
+
- 📆 `DayOfWeek` - Sunday through Saturday
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 📖 API Reference
|
|
214
|
+
|
|
215
|
+
### `fromGregorian(year, month, day, [hour], [minute], [second])`
|
|
216
|
+
|
|
217
|
+
Converts a Gregorian (Western) date to a Khmer Lunar date.
|
|
218
|
+
|
|
219
|
+
**Parameters:**
|
|
220
|
+
| Parameter | Type | Required | Range | Description |
|
|
221
|
+
|-----------|------|----------|-------|-------------|
|
|
222
|
+
| `year` | Number | ✅ Yes | Any | 📅 Gregorian year (e.g., 2024) |
|
|
223
|
+
| `month` | Number | ✅ Yes | 1-12 | 📅 **1-based** month (1=January, 12=December) |
|
|
224
|
+
| `day` | Number | ✅ Yes | 1-31 | 📅 Day of month |
|
|
225
|
+
| `hour` | Number | ⚪ No | 0-23 | ⏰ Hour (default: 0) |
|
|
226
|
+
| `minute` | Number | ⚪ No | 0-59 | ⏰ Minute (default: 0) |
|
|
227
|
+
| `second` | Number | ⚪ No | 0-59 | ⏰ Second (default: 0) |
|
|
228
|
+
|
|
229
|
+
**Returns:** Object
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
{
|
|
233
|
+
gregorian: {
|
|
234
|
+
year: 2024, // Number: Gregorian year
|
|
235
|
+
month: 4, // Number: Gregorian month (1-12)
|
|
236
|
+
day: 14, // Number: Day of month
|
|
237
|
+
hour: 10, // Number: Hour (0-23)
|
|
238
|
+
minute: 30, // Number: Minute (0-59)
|
|
239
|
+
second: 0, // Number: Second (0-59)
|
|
240
|
+
dayOfWeek: 0 // Number: 0=Sunday, 1=Monday, ..., 6=Saturday
|
|
241
|
+
},
|
|
242
|
+
khmer: {
|
|
243
|
+
day: 6, // Number: Lunar day (1-15)
|
|
244
|
+
moonPhase: 0, // MoonPhase enum: 0=Waxing (កើត), 1=Waning (រោច)
|
|
245
|
+
moonPhaseName: 'កើត', // String: Moon phase name (NEW in v3.0)
|
|
246
|
+
monthIndex: 4, // MonthIndex enum: 0-13 (see table below)
|
|
247
|
+
monthName: 'ចេត្រ', // String: Khmer month name
|
|
248
|
+
beYear: 2568, // Number: Buddhist Era year
|
|
249
|
+
jsYear: 1386, // Number: Jolak Sakaraj (Chula Sakaraj) year
|
|
250
|
+
animalYear: 4, // AnimalYear enum: 0-11 (NEW in v3.0)
|
|
251
|
+
animalYearName: 'រោង', // String: Animal year name
|
|
252
|
+
eraYear: 6, // EraYear enum: 0-9 (NEW in v3.0)
|
|
253
|
+
eraYearName: 'ឆស័ក', // String: Era/Sak name
|
|
254
|
+
dayOfWeek: 0, // DayOfWeek enum: 0=Sunday, 6=Saturday (NEW in v3.0)
|
|
255
|
+
dayOfWeekName: 'អាទិត្យ' // String: Khmer weekday name
|
|
256
|
+
},
|
|
257
|
+
_khmerDateObj: KhmerDate // Internal: KhmerDate object (for advanced use)
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**✨ NEW in v3.0:** The `khmer` object now includes both enum values AND string names for easier usage:
|
|
262
|
+
|
|
263
|
+
- 🔢 Use enum values (e.g., `moonPhase`, `monthIndex`) for type-safe comparisons
|
|
264
|
+
- 📝 Use string names (e.g., `moonPhaseName`, `monthName`) for display purposes
|
|
265
|
+
|
|
266
|
+
**Example:**
|
|
267
|
+
|
|
268
|
+
```javascript
|
|
269
|
+
const result = momentkh.fromGregorian(2024, 4, 14);
|
|
270
|
+
console.log(result.khmer.beYear); // 2568
|
|
271
|
+
console.log(result.khmer.monthName); // 'ចេត្រ'
|
|
272
|
+
console.log(result.khmer.animalYear); // 'រោង'
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
### `fromKhmer(day, moonPhase, monthIndex, beYear)`
|
|
278
|
+
|
|
279
|
+
Converts a Khmer Lunar date to a Gregorian date.
|
|
280
|
+
|
|
281
|
+
**Parameters:**
|
|
282
|
+
| Parameter | Type | Required | Range | Description |
|
|
283
|
+
|-----------|------|----------|-------|-------------|
|
|
284
|
+
| `day` | Number | ✅ Yes | 1-15 | 📅 Lunar day number within the phase |
|
|
285
|
+
| `moonPhase` | Number \| MoonPhase | ✅ Yes | 0 or 1 | 🌙 0 = កើត (waxing), 1 = រោច (waning). ✨ NEW: Can use `MoonPhase.Waxing` or `MoonPhase.Waning` |
|
|
286
|
+
| `monthIndex` | Number \| MonthIndex | ✅ Yes | 0-13 | 📅 Khmer month index (see table below). ✨ NEW: Can use `MonthIndex` enum |
|
|
287
|
+
| `beYear` | Number | ✅ Yes | Any | 🙏 Buddhist Era year (e.g., 2568) |
|
|
288
|
+
|
|
289
|
+
**Lunar Month Indices:**
|
|
290
|
+
| Index | Khmer Name | Notes |
|
|
291
|
+
|-------|------------|-------|
|
|
292
|
+
| 0 | មិគសិរ (Migasir) | |
|
|
293
|
+
| 1 | បុស្ស (Boss) | |
|
|
294
|
+
| 2 | មាឃ (Meak) | |
|
|
295
|
+
| 3 | ផល្គុន (Phalkun) | |
|
|
296
|
+
| 4 | ចេត្រ (Cheit) | |
|
|
297
|
+
| 5 | ពិសាខ (Pisakh) | 🙏 Contains Visakha Bochea (15កើត) |
|
|
298
|
+
| 6 | ជេស្ឋ (Jesth) | ➕ Can have leap day (30 days instead of 29) |
|
|
299
|
+
| 7 | អាសាឍ (Asadh) | |
|
|
300
|
+
| 8 | ស្រាពណ៍ (Srap) | |
|
|
301
|
+
| 9 | ភទ្របទ (Phatrabot) | |
|
|
302
|
+
| 10 | អស្សុជ (Assoch) | |
|
|
303
|
+
| 11 | កត្ដិក (Kadeuk) | |
|
|
304
|
+
| 12 | បឋមាសាឍ (Pathamasadh) | 🌟 Only exists in leap month years |
|
|
305
|
+
| 13 | ទុតិយាសាឍ (Tutiyasadh) | 🌟 Only exists in leap month years |
|
|
306
|
+
|
|
307
|
+
**Returns:** Object
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
{
|
|
311
|
+
year: 2024, // Number: Gregorian year
|
|
312
|
+
month: 4, // Number: Gregorian month (1-12)
|
|
313
|
+
day: 14 // Number: Day of month
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Example:**
|
|
318
|
+
|
|
319
|
+
```javascript
|
|
320
|
+
// Using numbers (backward compatible)
|
|
321
|
+
const gregorian1 = momentkh.fromKhmer(6, 0, 4, 2568);
|
|
322
|
+
console.log(gregorian1); // { year: 2024, month: 4, day: 14 }
|
|
323
|
+
|
|
324
|
+
// Using enums (NEW in v3.0 - type-safe!)
|
|
325
|
+
const { MoonPhase, MonthIndex } = momentkh;
|
|
326
|
+
const gregorian2 = momentkh.fromKhmer(
|
|
327
|
+
6,
|
|
328
|
+
MoonPhase.Waxing,
|
|
329
|
+
MonthIndex.Chetr,
|
|
330
|
+
2568
|
|
331
|
+
);
|
|
332
|
+
console.log(gregorian2); // { year: 2024, month: 4, day: 14 }
|
|
333
|
+
|
|
334
|
+
// Mixed: numbers and enums work together
|
|
335
|
+
const gregorian3 = momentkh.fromKhmer(15, MoonPhase.Waxing, 5, 2568);
|
|
336
|
+
console.log(gregorian3); // Works perfectly!
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Important Notes:**
|
|
340
|
+
|
|
341
|
+
- 📌 `day` represents the day number within the moon phase (always 1-15)
|
|
342
|
+
- 🌙 `moonPhase` 0 = កើត (waxing, days 1-15), 1 = រោច (waning, days 1-14 or 1-15)
|
|
343
|
+
- ✨ **NEW:** Use `MoonPhase.Waxing` or `MoonPhase.Waning` for better code readability
|
|
344
|
+
- 📅 A full lunar month is typically 29-30 days total
|
|
345
|
+
- 💡 Example: "៨រោច" means day=8, moonPhase=1 (or MoonPhase.Waning)
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
### `fromDate(dateObject)`
|
|
350
|
+
|
|
351
|
+
Convenience method to convert a JavaScript `Date` object to Khmer date.
|
|
352
|
+
|
|
353
|
+
**Parameters:**
|
|
354
|
+
| Parameter | Type | Required | Description |
|
|
355
|
+
|-----------|------|----------|-------------|
|
|
356
|
+
| `dateObject` | Date | Yes | JavaScript Date object |
|
|
357
|
+
|
|
358
|
+
**Returns:** Same object structure as `fromGregorian()`
|
|
359
|
+
|
|
360
|
+
**Example:**
|
|
361
|
+
|
|
362
|
+
```javascript
|
|
363
|
+
const now = new Date();
|
|
364
|
+
const khmer = momentkh.fromDate(now);
|
|
365
|
+
console.log(momentkh.format(khmer));
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
### `toDate(day, moonPhase, monthIndex, beYear)`
|
|
371
|
+
|
|
372
|
+
Converts a Khmer Lunar date directly to a JavaScript `Date` object.
|
|
373
|
+
|
|
374
|
+
**Parameters:** Same as `fromKhmer()`
|
|
375
|
+
|
|
376
|
+
**Returns:** JavaScript `Date` object
|
|
377
|
+
|
|
378
|
+
**Example:**
|
|
379
|
+
|
|
380
|
+
```javascript
|
|
381
|
+
// Convert 1កើត ខែបុស្ស ព.ស.២៤៤៣ to Date object
|
|
382
|
+
const date = momentkh.toDate(1, 0, 1, 2443);
|
|
383
|
+
console.log(date); // JavaScript Date for 1900-01-01
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
### `getNewYear(year)`
|
|
389
|
+
|
|
390
|
+
Calculates the exact date and time of **Moha Songkran** (មហាសង្រ្កាន្ត) - the Khmer New Year - for a given Gregorian year.
|
|
391
|
+
|
|
392
|
+
**Parameters:**
|
|
393
|
+
| Parameter | Type | Required | Description |
|
|
394
|
+
|-----------|------|----------|-------------|
|
|
395
|
+
| `year` | Number | Yes | Gregorian year (e.g., 2024) |
|
|
396
|
+
|
|
397
|
+
**Returns:** Object
|
|
398
|
+
|
|
399
|
+
```javascript
|
|
400
|
+
{
|
|
401
|
+
year: 2024, // Number: Gregorian year
|
|
402
|
+
month: 4, // Number: Gregorian month (1-12)
|
|
403
|
+
day: 13, // Number: Day of month
|
|
404
|
+
hour: 22, // Number: Hour (0-23)
|
|
405
|
+
minute: 24 // Number: Minute (0-59)
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**Example:**
|
|
410
|
+
|
|
411
|
+
```javascript
|
|
412
|
+
const ny2024 = momentkh.getNewYear(2024);
|
|
413
|
+
console.log(
|
|
414
|
+
`Khmer New Year 2024: ${ny2024.day}/${ny2024.month}/${ny2024.year} at ${
|
|
415
|
+
ny2024.hour
|
|
416
|
+
}:${String(ny2024.minute).padStart(2, "0")}`
|
|
417
|
+
);
|
|
418
|
+
// Output: Khmer New Year 2024: 13/4/2024 at 22:24
|
|
419
|
+
|
|
420
|
+
// Loop through multiple years
|
|
421
|
+
for (let year = 2020; year <= 2025; year++) {
|
|
422
|
+
const ny = momentkh.getNewYear(year);
|
|
423
|
+
console.log(
|
|
424
|
+
`${year}: ${ny.day}/${ny.month} ${ny.hour}:${String(ny.minute).padStart(
|
|
425
|
+
2,
|
|
426
|
+
"0"
|
|
427
|
+
)}`
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
### `format(khmerData, [formatString])`
|
|
435
|
+
|
|
436
|
+
Formats a Khmer date object into a string with optional custom formatting.
|
|
437
|
+
|
|
438
|
+
**Parameters:**
|
|
439
|
+
| Parameter | Type | Required | Description |
|
|
440
|
+
|-----------|------|----------|-------------|
|
|
441
|
+
| `khmerData` | Object | Yes | Result from `fromGregorian()` or `fromDate()` |
|
|
442
|
+
| `formatString` | String | No | Custom format (see tokens below). If omitted, uses default format |
|
|
443
|
+
|
|
444
|
+
**Default Format:**
|
|
445
|
+
|
|
446
|
+
```
|
|
447
|
+
ថ្ងៃ{weekday} {day}{moonPhase} ខែ{month} ឆ្នាំ{animalYear} {eraYear} ពុទ្ធសករាជ {beYear}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
**Returns:** String (formatted Khmer date)
|
|
451
|
+
|
|
452
|
+
**Example:**
|
|
453
|
+
|
|
454
|
+
```javascript
|
|
455
|
+
const khmer = momentkh.fromGregorian(2024, 4, 14);
|
|
456
|
+
|
|
457
|
+
// Default format
|
|
458
|
+
console.log(momentkh.format(khmer));
|
|
459
|
+
// ថ្ងៃអាទិត្យ ៦កើត ខែចេត្រ ឆ្នាំរោង ឆស័ក ពុទ្ធសករាជ ២៥៦៨
|
|
460
|
+
|
|
461
|
+
// Custom formats
|
|
462
|
+
console.log(momentkh.format(khmer, "dN ថ្ងៃW ខែm"));
|
|
463
|
+
// ៦កើត ថ្ងៃអាទិត្យ ខែចេត្រ
|
|
464
|
+
|
|
465
|
+
console.log(momentkh.format(khmer, "c/M/D"));
|
|
466
|
+
// ២០២៤/មេសា/១៤
|
|
467
|
+
|
|
468
|
+
console.log(momentkh.format(khmer, "ថ្ងៃw dN m ឆ្នាំa e ព.ស.b"));
|
|
469
|
+
// ថ្ងៃអា ៦កើត ចេត្រ ឆ្នាំរោង ឆស័ក ព.ស.២៥៦៨
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## 🔢 Using Enums (NEW in v3.0)
|
|
475
|
+
|
|
476
|
+
MomentKH 3.0 introduces TypeScript enums for better type safety and code readability. Use enums instead of magic numbers for clearer, more maintainable code.
|
|
477
|
+
|
|
478
|
+
### Available Enums
|
|
479
|
+
|
|
480
|
+
#### 🌙 MoonPhase
|
|
481
|
+
|
|
482
|
+
Represents the moon phase in the lunar calendar.
|
|
483
|
+
|
|
484
|
+
```javascript
|
|
485
|
+
const { MoonPhase } = momentkh;
|
|
486
|
+
|
|
487
|
+
MoonPhase.Waxing; // 0 - 🌒 កើត (waxing moon, days 1-15)
|
|
488
|
+
MoonPhase.Waning; // 1 - 🌘 រោច (waning moon, days 1-15)
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
#### 📅 MonthIndex
|
|
492
|
+
|
|
493
|
+
All 14 Khmer lunar months (including leap months).
|
|
494
|
+
|
|
495
|
+
```javascript
|
|
496
|
+
const { MonthIndex } = momentkh;
|
|
497
|
+
|
|
498
|
+
MonthIndex.Mikasar; // 0 - មិគសិរ
|
|
499
|
+
MonthIndex.Bos; // 1 - បុស្ស
|
|
500
|
+
MonthIndex.Meak; // 2 - មាឃ
|
|
501
|
+
MonthIndex.Phalgun; // 3 - ផល្គុន
|
|
502
|
+
MonthIndex.Chetr; // 4 - ចេត្រ
|
|
503
|
+
MonthIndex.Visakh; // 5 - ពិសាខ
|
|
504
|
+
MonthIndex.Jesth; // 6 - ជេស្ឋ
|
|
505
|
+
MonthIndex.Asath; // 7 - អាសាឍ
|
|
506
|
+
MonthIndex.Srap; // 8 - ស្រាពណ៍
|
|
507
|
+
MonthIndex.Photrobot; // 9 - ភទ្របទ
|
|
508
|
+
MonthIndex.Assoch; // 10 - អស្សុជ
|
|
509
|
+
MonthIndex.Kadek; // 11 - កត្ដិក
|
|
510
|
+
MonthIndex.BothmakAsath; // 12 - បឋមាសាឍ (leap month only)
|
|
511
|
+
MonthIndex.TutiyakAsath; // 13 - ទុតិយាសាឍ (leap month only)
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
#### 🐉 AnimalYear
|
|
515
|
+
|
|
516
|
+
The 12 animal years in the zodiac cycle.
|
|
517
|
+
|
|
518
|
+
```javascript
|
|
519
|
+
const { AnimalYear } = momentkh;
|
|
520
|
+
|
|
521
|
+
AnimalYear.Chhut; // 0 - 🐀 ជូត (Rat)
|
|
522
|
+
AnimalYear.Chlov; // 1 - 🐂 ឆ្លូវ (Ox)
|
|
523
|
+
AnimalYear.Khal; // 2 - 🐅 ខាល (Tiger)
|
|
524
|
+
AnimalYear.Thos; // 3 - 🐇 ថោះ (Rabbit)
|
|
525
|
+
AnimalYear.Rong; // 4 - 🐉 រោង (Dragon)
|
|
526
|
+
AnimalYear.Masagn; // 5 - 🐍 ម្សាញ់ (Snake)
|
|
527
|
+
AnimalYear.Momee; // 6 - 🐎 មមី (Horse)
|
|
528
|
+
AnimalYear.Momae; // 7 - 🐐 មមែ (Goat)
|
|
529
|
+
AnimalYear.Vok; // 8 - 🐒 វក (Monkey)
|
|
530
|
+
AnimalYear.Roka; // 9 - 🐓 រកា (Rooster)
|
|
531
|
+
AnimalYear.Cho; // 10 - 🐕 ច (Dog)
|
|
532
|
+
AnimalYear.Kor; // 11 - 🐖 កុរ (Pig)
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
#### ⭐ EraYear
|
|
536
|
+
|
|
537
|
+
The 10 era years (ស័ក) cycle.
|
|
538
|
+
|
|
539
|
+
```javascript
|
|
540
|
+
const { EraYear } = momentkh;
|
|
541
|
+
|
|
542
|
+
EraYear.Samridhisak; // 0 - 🔟 សំរឹទ្ធិស័ក
|
|
543
|
+
EraYear.Ekasak; // 1 - 1️⃣ ឯកស័ក
|
|
544
|
+
EraYear.Tosak; // 2 - 2️⃣ ទោស័ក
|
|
545
|
+
EraYear.Tresak; // 3 - 3️⃣ ត្រីស័ក
|
|
546
|
+
EraYear.Chatvasak; // 4 - 4️⃣ ចត្វាស័ក
|
|
547
|
+
EraYear.Panchasak; // 5 - 5️⃣ បញ្ចស័ក
|
|
548
|
+
EraYear.Chhasak; // 6 - 6️⃣ ឆស័ក
|
|
549
|
+
EraYear.Saptasak; // 7 - 7️⃣ សប្តស័ក
|
|
550
|
+
EraYear.Atthasak; // 8 - 8️⃣ អដ្ឋស័ក
|
|
551
|
+
EraYear.Novvasak; // 9 - 9️⃣ នព្វស័ក
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
#### 📆 DayOfWeek
|
|
555
|
+
|
|
556
|
+
Days of the week.
|
|
557
|
+
|
|
558
|
+
```javascript
|
|
559
|
+
const { DayOfWeek } = momentkh;
|
|
560
|
+
|
|
561
|
+
DayOfWeek.Sunday; // 0 - ☀️ អាទិត្យ
|
|
562
|
+
DayOfWeek.Monday; // 1 - 🌙 ចន្ទ
|
|
563
|
+
DayOfWeek.Tuesday; // 2 - 🔥 អង្គារ
|
|
564
|
+
DayOfWeek.Wednesday; // 3 - 🪐 ពុធ
|
|
565
|
+
DayOfWeek.Thursday; // 4 - ⚡ ព្រហស្បតិ៍
|
|
566
|
+
DayOfWeek.Friday; // 5 - 💎 សុក្រ
|
|
567
|
+
DayOfWeek.Saturday; // 6 - 💀 សៅរ៍
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### Usage Examples
|
|
571
|
+
|
|
572
|
+
#### Example 1: Type-Safe Comparisons
|
|
573
|
+
|
|
574
|
+
```javascript
|
|
575
|
+
const { MoonPhase, MonthIndex, DayOfWeek } = momentkh;
|
|
576
|
+
const khmer = momentkh.fromGregorian(2024, 12, 16);
|
|
577
|
+
|
|
578
|
+
// Check moon phase
|
|
579
|
+
if (khmer.khmer.moonPhase === MoonPhase.Waxing) {
|
|
580
|
+
console.log("Waxing moon (កើត)");
|
|
581
|
+
} else {
|
|
582
|
+
console.log("Waning moon (រោច)");
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// Check specific month
|
|
586
|
+
if (khmer.khmer.monthIndex === MonthIndex.Mikasar) {
|
|
587
|
+
console.log("It is Mikasar month!");
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Check day of week
|
|
591
|
+
if (khmer.khmer.dayOfWeek === DayOfWeek.Monday) {
|
|
592
|
+
console.log("It is Monday!");
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
#### Example 2: Converting with Enums
|
|
597
|
+
|
|
598
|
+
```javascript
|
|
599
|
+
const { MoonPhase, MonthIndex } = momentkh;
|
|
600
|
+
|
|
601
|
+
// Convert Khmer to Gregorian using enums (much clearer!)
|
|
602
|
+
const date1 = momentkh.fromKhmer(
|
|
603
|
+
15, // day
|
|
604
|
+
MoonPhase.Waxing, // instead of 0
|
|
605
|
+
MonthIndex.Visakh, // instead of 5
|
|
606
|
+
2568
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
// Still works with numbers for backward compatibility
|
|
610
|
+
const date2 = momentkh.fromKhmer(15, 0, 5, 2568);
|
|
611
|
+
|
|
612
|
+
// Both give the same result
|
|
613
|
+
console.log(date1); // { year: 2025, month: 5, day: 11 }
|
|
614
|
+
console.log(date2); // { year: 2025, month: 5, day: 11 }
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
#### Example 3: Switch Statements with Enums
|
|
61
618
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
619
|
+
```javascript
|
|
620
|
+
const { MonthIndex, AnimalYear } = momentkh;
|
|
621
|
+
const khmer = momentkh.fromGregorian(2024, 12, 16);
|
|
622
|
+
|
|
623
|
+
// Switch on month
|
|
624
|
+
switch (khmer.khmer.monthIndex) {
|
|
625
|
+
case MonthIndex.Mikasar:
|
|
626
|
+
case MonthIndex.Bos:
|
|
627
|
+
case MonthIndex.Meak:
|
|
628
|
+
console.log("Winter months");
|
|
629
|
+
break;
|
|
630
|
+
case MonthIndex.Phalgun:
|
|
631
|
+
case MonthIndex.Chetr:
|
|
632
|
+
case MonthIndex.Visakh:
|
|
633
|
+
console.log("Spring months");
|
|
634
|
+
break;
|
|
635
|
+
// ... more cases
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// Switch on animal year
|
|
639
|
+
switch (khmer.khmer.animalYear) {
|
|
640
|
+
case AnimalYear.Rong:
|
|
641
|
+
console.log("Year of the Dragon!");
|
|
642
|
+
break;
|
|
643
|
+
case AnimalYear.Masagn:
|
|
644
|
+
console.log("Year of the Snake!");
|
|
645
|
+
break;
|
|
646
|
+
// ... more cases
|
|
647
|
+
}
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
#### Example 4: TypeScript Benefits
|
|
651
|
+
|
|
652
|
+
```typescript
|
|
653
|
+
import momentkh, { MoonPhase, MonthIndex, KhmerConversionResult } from './momentkh';
|
|
654
|
+
|
|
655
|
+
// Full autocomplete and type checking!
|
|
656
|
+
const result: KhmerConversionResult = momentkh.fromGregorian(2024, 12, 16);
|
|
657
|
+
|
|
658
|
+
// TypeScript knows these are enums
|
|
659
|
+
const phase: MoonPhase = result.khmer.moonPhase;
|
|
660
|
+
const month: MonthIndex = result.khmer.monthIndex;
|
|
661
|
+
|
|
662
|
+
// Type error if you try to use invalid value
|
|
663
|
+
// const date = momentkh.fromKhmer(15, 3, 5, 2568); // Error! 3 is not a valid MoonPhase
|
|
664
|
+
|
|
665
|
+
// Autocomplete shows all enum options
|
|
666
|
+
const date = momentkh.fromKhmer(
|
|
667
|
+
15,
|
|
668
|
+
MoonPhase. // ← IDE shows: Waxing, Waning
|
|
669
|
+
MonthIndex. // ← IDE shows: Mikasar, Bos, Meak, etc.
|
|
670
|
+
2568
|
|
671
|
+
);
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### Benefits of Using Enums
|
|
675
|
+
|
|
676
|
+
1. 📖 **Readability**: `MonthIndex.Visakh` is clearer than `5`
|
|
677
|
+
2. 🛡️ **Type Safety**: TypeScript catches invalid values at compile time
|
|
678
|
+
3. ⚡ **Autocomplete**: IDEs show all available options
|
|
679
|
+
4. 🔧 **Maintainability**: Easier to understand code months later
|
|
680
|
+
5. ♻️ **Refactoring**: Safer to change enum values (single source of truth)
|
|
681
|
+
6. 📚 **Documentation**: Enums serve as inline documentation
|
|
69
682
|
|
|
70
|
-
|
|
71
|
-
| Name | Original |
|
|
72
|
-
|---------|----------------|
|
|
73
|
-
|toKhDate, tokhdate|toLunarDate|
|
|
683
|
+
### 🔄 Backward Compatibility
|
|
74
684
|
|
|
685
|
+
✅ All functions accept both enums and numbers:
|
|
75
686
|
|
|
76
|
-
|
|
687
|
+
```javascript
|
|
688
|
+
// All of these work:
|
|
689
|
+
momentkh.fromKhmer(15, MoonPhase.Waxing, MonthIndex.Visakh, 2568); // ✨ New enum way
|
|
690
|
+
momentkh.fromKhmer(15, 0, MonthIndex.Visakh, 2568); // 🔀 Mixed
|
|
691
|
+
momentkh.fromKhmer(15, MoonPhase.Waxing, 5, 2568); // 🔀 Mixed
|
|
692
|
+
momentkh.fromKhmer(15, 0, 5, 2568); // 👍 Old way still works!
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
🎯 **Existing code using numbers continues to work without changes!**
|
|
696
|
+
|
|
697
|
+
---
|
|
698
|
+
|
|
699
|
+
## 🧮 Understanding Khmer Calendar
|
|
700
|
+
|
|
701
|
+
The Khmer calendar is a **lunisolar calendar** that tracks both the moon phases and the solar year. It uses **three different year numbering systems** that change at different times:
|
|
702
|
+
|
|
703
|
+
### Buddhist Era (BE) Year
|
|
704
|
+
|
|
705
|
+
**Full Name:** ពុទ្ធសករាជ (Putthsak, Buddhist Era)
|
|
706
|
+
**Offset from Gregorian:** +543 or +544
|
|
707
|
+
**When it increases:** At midnight (00:00) on the **15th waxing day of Pisakh month** (១៥កើត ខែពិសាខ)
|
|
708
|
+
|
|
709
|
+
**Example Timeline:**
|
|
710
|
+
|
|
711
|
+
```
|
|
712
|
+
2024-05-22 23:59 → 14កើត Pisakh, BE 2567
|
|
713
|
+
2024-05-23 00:00 → 15កើត Pisakh, BE 2568 (NEW year starts!)
|
|
714
|
+
2024-05-23 23:59 → 15កើត Pisakh, BE 2568
|
|
715
|
+
2024-05-24 00:00 → 1រោច Pisakh, BE 2568
|
|
716
|
+
```
|
|
77
717
|
|
|
78
|
-
|
|
79
|
-
|---------|-----|-----------|----------------|
|
|
80
|
-
|getKhNewYearMoment| Integer | Return moment.js object. Giving the moment of Khmer New Year. (ពេលទេវតាចុះ) | `moment.getKhNewYearMoment(2019);`|
|
|
81
|
-
|~~readLunarDate~~*(currently working on this)*| String or Object |Return moment.js object. Just same as calling: ``moment('13/04/2018', 'dd/mm/yyyy');`` for Gregorian date </br> |``moment.readLunarDate('១៥កើត ពិសាខ ព.ស. ២៥៥៥');`` |
|
|
718
|
+
**Important:**
|
|
82
719
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|khDate, khdate|readLunarDate|
|
|
720
|
+
- 🙏 The 15th waxing day of Pisakh is **Visakha Bochea** (ពិសាខបូជា), celebrating Buddha's birth, enlightenment, and death
|
|
721
|
+
- ⏰ At midnight (00:00) when this sacred day begins, the new BE year starts
|
|
722
|
+
- 📍 The year changes exactly at the start of the 15th waxing day of Pisakh
|
|
87
723
|
|
|
88
|
-
|
|
89
|
-
By default, it will return the format as shown in example above.
|
|
90
|
-
However, you can also customize your format.
|
|
724
|
+
**Code Example:**
|
|
91
725
|
|
|
92
726
|
```javascript
|
|
93
|
-
//
|
|
94
|
-
|
|
727
|
+
// Check BE year transition
|
|
728
|
+
const before = momentkh.fromGregorian(2024, 5, 22, 23, 59); // 23:59 on May 22
|
|
729
|
+
const at = momentkh.fromGregorian(2024, 5, 23, 0, 0); // Midnight on May 23
|
|
730
|
+
|
|
731
|
+
console.log(before.khmer.beYear); // 2567 (old year)
|
|
732
|
+
console.log(at.khmer.beYear); // 2568 (new year starts at midnight!)
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
### Animal Year
|
|
738
|
+
|
|
739
|
+
**Full Name:** ឆ្នាំ + Animal name (Year of the [Animal])
|
|
740
|
+
**Cycle:** 12 years
|
|
741
|
+
**When it increases:** At the exact moment of **Moha Songkran** (មហាសង្រ្កាន្ត) - Khmer New Year
|
|
742
|
+
|
|
743
|
+
**The 12 Animals (in order):**
|
|
744
|
+
| Index | Khmer | Pronunciation | Animal | Emoji |
|
|
745
|
+
|-------|-------|---------------|--------|-------|
|
|
746
|
+
| 0 | ជូត | Chhūt | Rat | 🐀 |
|
|
747
|
+
| 1 | ឆ្លូវ | Chhlūv | Ox | 🐂 |
|
|
748
|
+
| 2 | ខាល | Khāl | Tiger | 🐅 |
|
|
749
|
+
| 3 | ថោះ | Thaŏh | Rabbit | 🐇 |
|
|
750
|
+
| 4 | រោង | Rōng | Dragon | 🐉 |
|
|
751
|
+
| 5 | ម្សាញ់ | Msanh | Snake | 🐍 |
|
|
752
|
+
| 6 | មមី | Momi | Horse | 🐎 |
|
|
753
|
+
| 7 | មមែ | Momè | Goat | 🐐 |
|
|
754
|
+
| 8 | វក | Vŏk | Monkey | 🐒 |
|
|
755
|
+
| 9 | រកា | Rŏka | Rooster | 🐓 |
|
|
756
|
+
| 10 | ច | Châ | Dog | 🐕 |
|
|
757
|
+
| 11 | កុរ | Kŏr | Pig | 🐖 |
|
|
758
|
+
|
|
759
|
+
**Example Timeline:**
|
|
760
|
+
|
|
761
|
+
```
|
|
762
|
+
2024-04-13 22:23 → Cheit month, BE 2567, Animal Year: វក (Monkey)
|
|
763
|
+
2024-04-13 22:24 → Cheit month, BE 2567, Animal Year: រកា (Rooster) ← NEW YEAR!
|
|
764
|
+
2024-04-13 22:25 → Cheit month, BE 2567, Animal Year: រកា (Rooster)
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
**Code Example:**
|
|
768
|
+
|
|
769
|
+
```javascript
|
|
770
|
+
const ny = momentkh.getNewYear(2024);
|
|
771
|
+
console.log(ny); // { year: 2024, month: 4, day: 13, hour: 22, minute: 24 }
|
|
772
|
+
|
|
773
|
+
// Just before New Year
|
|
774
|
+
const before = momentkh.fromGregorian(2024, 4, 13, 22, 23);
|
|
775
|
+
console.log(before.khmer.animalYear); // 'វក' (Monkey)
|
|
776
|
+
|
|
777
|
+
// Right at New Year
|
|
778
|
+
const at = momentkh.fromGregorian(2024, 4, 13, 22, 24);
|
|
779
|
+
console.log(at.khmer.animalYear); // 'រកា' (Rooster) - Changed!
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
---
|
|
783
|
+
|
|
784
|
+
### Era Year (Sak)
|
|
785
|
+
|
|
786
|
+
**Full Name:** ស័ក (Sak, Era)
|
|
787
|
+
**Cycle:** 10 years
|
|
788
|
+
**When it increases:** At **midnight (00:00) of the last day** of Khmer New Year celebration (Lerng Sak - ថ្ងៃឡើងស័ក)
|
|
789
|
+
|
|
790
|
+
**The 10 Eras (in order):**
|
|
791
|
+
| Index | Khmer | Romanization |
|
|
792
|
+
|-------|-------|--------------|
|
|
793
|
+
| 0 | សំរឹទ្ធិស័ក | Samridhi Sak |
|
|
794
|
+
| 1 | ឯកស័ក | Aek Sak |
|
|
795
|
+
| 2 | ទោស័ក | To Sak |
|
|
796
|
+
| 3 | ត្រីស័ក | Trei Sak |
|
|
797
|
+
| 4 | ចត្វាស័ក | Chattva Sak |
|
|
798
|
+
| 5 | បញ្ចស័ក | Pañcha Sak |
|
|
799
|
+
| 6 | ឆស័ក | Chha Sak |
|
|
800
|
+
| 7 | សប្តស័ក | Sapta Sak |
|
|
801
|
+
| 8 | អដ្ឋស័ក | Attha Sak |
|
|
802
|
+
| 9 | នព្វស័ក | Nappa Sak |
|
|
803
|
+
|
|
804
|
+
**New Year Celebration Days:**
|
|
805
|
+
|
|
806
|
+
- 🎉 **Day 1:** Moha Songkran (មហាសង្រ្កាន្ត) - New Year's Day
|
|
807
|
+
- 🎊 **Day 2:** Virak Wanabat (វីរៈវ័នបត) - Second day
|
|
808
|
+
- ⭐ **Day 3 or 4:** Lerng Sak (ថ្ងៃឡើងស័ក) - Last day & Era change day
|
|
809
|
+
|
|
810
|
+
**Example:**
|
|
811
|
+
|
|
812
|
+
```javascript
|
|
813
|
+
// 2024 New Year is on April 13, 22:24
|
|
814
|
+
// Lerng Sak (Era change) is typically 3-4 days later at midnight
|
|
815
|
+
|
|
816
|
+
const newYearDay = momentkh.fromGregorian(2024, 4, 13, 23, 0);
|
|
817
|
+
console.log(newYearDay.khmer.eraYear); // 'ឆស័ក' (still old era)
|
|
818
|
+
|
|
819
|
+
const lerngSakDay = momentkh.fromGregorian(2024, 4, 17, 0, 0); // Midnight of Lerng Sak
|
|
820
|
+
console.log(lerngSakDay.khmer.eraYear); // 'សប្តស័ក' (new era!)
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
---
|
|
824
|
+
|
|
825
|
+
### When Each Year Type Increases
|
|
826
|
+
|
|
827
|
+
**Summary Table:**
|
|
828
|
+
|
|
829
|
+
| Year Type | Changes At | Example Date/Time |
|
|
830
|
+
| --------------- | ---------------------- | -------------------- |
|
|
831
|
+
| **BE Year** | 00:00 on ១៥កើត ខែពិសាខ | May 23, 2024 00:00 |
|
|
832
|
+
| **Animal Year** | ម៉ោង និង នាទីទេវតាចុះ | April 13, 2024 22:17 |
|
|
833
|
+
| **Era Year** | 00:00 នៅថ្ងៃឡើងស័ក | April 16, 2024 00:00 |
|
|
834
|
+
|
|
835
|
+
**Visual Timeline for 2024:**
|
|
836
|
+
|
|
837
|
+
```
|
|
838
|
+
April 13, 22:23 → BE 2567, Monkey (វក), Old Era (ឆស័ក)
|
|
839
|
+
April 13, 22:24 → BE 2567, Rooster (រកា), Old Era (ឆស័ក) ← Animal Year changes
|
|
840
|
+
April 17, 00:00 → BE 2567, Rooster (រកា), New Era (សប្តស័ក) ← Era changes
|
|
841
|
+
May 22, 23:59 → BE 2567, Rooster (រកា), New Era (សប្តស័ក)
|
|
842
|
+
May 23, 00:00 → BE 2568, Rooster (រកា), New Era (សប្តស័ក) ← BE Year changes
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
---
|
|
846
|
+
|
|
847
|
+
## 🎨 Format Codes
|
|
848
|
+
|
|
849
|
+
Complete list of format tokens for the `format()` function:
|
|
850
|
+
|
|
851
|
+
| Token | Output | Description | Example |
|
|
852
|
+
| ---------------------- | ----------------- | --------------------------- | --------------------- |
|
|
853
|
+
| **📅 Date Components** |
|
|
854
|
+
| `W` | ថ្ងៃនៃសប្តាហ៍ពេញ | Weekday name (full) | អាទិត្យ, ចន្ទ, អង្គារ |
|
|
855
|
+
| `w` | ថ្ងៃនៃសប្តាហ៍ខ្លី | Weekday name (short) | អា, ច, អ |
|
|
856
|
+
| `d` | ថ្ងៃទី | Lunar day number | ១, ៥, ១៥ |
|
|
857
|
+
| `D` | ថ្ងៃទី (២ខ្ទង់) | Lunar day (zero-padded) | ០១, ០៥, ១៥ |
|
|
858
|
+
| **🌙 Moon Phase** |
|
|
859
|
+
| `n` | កើត/រោច (ខ្លី) | Moon phase (short) | ក, រ |
|
|
860
|
+
| `N` | កើត/រោច (ពេញ) | Moon phase (full) | កើត, រោច |
|
|
861
|
+
| `o` | និមិត្តសញ្ញា | Moon day symbol | ᧡, ᧢, ᧣ ... ᧿ |
|
|
862
|
+
| **📆 Month Names** |
|
|
863
|
+
| `m` | ខែចន្ទគតិ | Lunar month name | មិគសិរ, បុស្ស, ចេត្រ |
|
|
864
|
+
| `M` | ខែសុរិយគតិ | Solar month name | មករា, កុម្ភៈ, មេសា |
|
|
865
|
+
| **⏰ Year Components** |
|
|
866
|
+
| `a` | ឆ្នាំសត្វ | Animal year | ជូត, ឆ្លូវ, រោង |
|
|
867
|
+
| `e` | ស័ក | Era year | ឯកស័ក, ទោស័ក |
|
|
868
|
+
| `b` | ព.ស. | Buddhist Era year | ២៥៦៨ |
|
|
869
|
+
| `c` | គ.ស. | Common Era (Gregorian) year | ២០២៤ |
|
|
870
|
+
| `j` | ច.ស. | Jolak Sakaraj year | ១៣៨៦ |
|
|
871
|
+
|
|
872
|
+
**Format Examples:**
|
|
873
|
+
|
|
874
|
+
```javascript
|
|
875
|
+
const khmer = momentkh.fromGregorian(2024, 4, 14);
|
|
876
|
+
|
|
877
|
+
console.log(momentkh.format(khmer, "W, dN ខែm ព.ស.b"));
|
|
878
|
+
// អាទិត្យ, ៦កើត ខែចេត្រ ព.ស.២៥៦៨
|
|
879
|
+
|
|
880
|
+
console.log(momentkh.format(khmer, "c/M/D ថ្ងៃw"));
|
|
881
|
+
// ២០២៤/មេសា/១៤ ថ្ងៃអា
|
|
882
|
+
|
|
883
|
+
console.log(momentkh.format(khmer, "ឆ្នាំa e ខែm ថ្ងៃទីd មានព្រះចន្ទN"));
|
|
884
|
+
// ឆ្នាំរោង ឆស័ក ខែចេត្រ ថ្ងៃទី៦ មានព្រះចន្ទកើត
|
|
885
|
+
|
|
886
|
+
console.log(momentkh.format(khmer, "ថ្ងៃទី o"));
|
|
887
|
+
// ថ្ងៃទី ᧦ (moon symbol for day 6 waxing)
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
---
|
|
891
|
+
|
|
892
|
+
## 📚 Constants
|
|
893
|
+
|
|
894
|
+
Access Khmer calendar constants through `momentkh.constants`:
|
|
895
|
+
|
|
896
|
+
**✨ NEW in v3.0:** For type-safe access, use the enums instead! See [🔢 Using Enums](#-using-enums-new-in-v30) section.
|
|
897
|
+
|
|
898
|
+
```javascript
|
|
899
|
+
// Lunar month names array (indices 0-13)
|
|
900
|
+
momentkh.constants.LunarMonthNames;
|
|
901
|
+
// ['មិគសិរ', 'បុស្ស', 'មាឃ', 'ផល្គុន', 'ចេត្រ', 'ពិសាខ', 'ជេស្ឋ', 'អាសាឍ',
|
|
902
|
+
// 'ស្រាពណ៍', 'ភទ្របទ', 'អស្សុជ', 'កត្ដិក', 'បឋមាសាឍ', 'ទុតិយាសាឍ']
|
|
903
|
+
|
|
904
|
+
// Solar month names array (indices 0-11)
|
|
905
|
+
momentkh.constants.SolarMonthNames;
|
|
906
|
+
// ['មករា', 'កុម្ភៈ', 'មីនា', 'មេសា', 'ឧសភា', 'មិថុនា',
|
|
907
|
+
// 'កក្កដា', 'សីហា', 'កញ្ញា', 'តុលា', 'វិច្ឆិកា', 'ធ្នូ']
|
|
908
|
+
|
|
909
|
+
// Animal year names array (indices 0-11)
|
|
910
|
+
momentkh.constants.AnimalYearNames;
|
|
911
|
+
// ['ជូត', 'ឆ្លូវ', 'ខាល', 'ថោះ', 'រោង', 'ម្សាញ់',
|
|
912
|
+
// 'មមី', 'មមែ', 'វក', 'រកា', 'ច', 'កុរ']
|
|
913
|
+
|
|
914
|
+
// Era year names array (indices 0-9)
|
|
915
|
+
momentkh.constants.EraYearNames;
|
|
916
|
+
// ['សំរឹទ្ធិស័ក', 'ឯកស័ក', 'ទោស័ក', 'ត្រីស័ក', 'ចត្វាស័ក',
|
|
917
|
+
// 'បញ្ចស័ក', 'ឆស័ក', 'សប្តស័ក', 'អដ្ឋស័ក', 'នព្វស័ក']
|
|
918
|
+
|
|
919
|
+
// Weekday names array (indices 0-6, Sunday-Saturday)
|
|
920
|
+
momentkh.constants.WeekdayNames;
|
|
921
|
+
// ['អាទិត្យ', 'ចន្ទ', 'អង្គារ', 'ពុធ', 'ព្រហស្បតិ៍', 'សុក្រ', 'សៅរ៍']
|
|
922
|
+
|
|
923
|
+
// Moon phase names array (indices 0-1)
|
|
924
|
+
momentkh.constants.MoonStatusNames;
|
|
925
|
+
// ['កើត', 'រោច']
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
**Usage Example:**
|
|
929
|
+
|
|
930
|
+
```javascript
|
|
931
|
+
// Get month name by index
|
|
932
|
+
const monthName = momentkh.constants.LunarMonthNames[4];
|
|
933
|
+
console.log(monthName); // 'ចេត្រ'
|
|
934
|
+
|
|
935
|
+
// Loop through all animal years
|
|
936
|
+
momentkh.constants.AnimalYearNames.forEach((animal, index) => {
|
|
937
|
+
console.log(`${index}: ${animal}`);
|
|
938
|
+
});
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
---
|
|
942
|
+
|
|
943
|
+
## 🔄 Migration Guide from MomentKH v1
|
|
944
|
+
|
|
945
|
+
If you're using the original `momentkh` library (v1) that extends moment.js, here's how to migrate:
|
|
946
|
+
|
|
947
|
+
### Installation Changes
|
|
948
|
+
|
|
949
|
+
**Before (v1):**
|
|
950
|
+
|
|
951
|
+
```bash
|
|
952
|
+
npm install moment --save
|
|
953
|
+
npm install @thyrith/momentkh --save
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
**After (v2):**
|
|
957
|
+
|
|
958
|
+
```bash
|
|
959
|
+
# Just download momentkh.js - no npm dependencies!
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
### Import Changes
|
|
963
|
+
|
|
964
|
+
**Before (v1):**
|
|
965
|
+
|
|
966
|
+
```javascript
|
|
967
|
+
const moment = require("moment");
|
|
968
|
+
require("@thyrith/momentkh")(moment);
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
**After (v2):**
|
|
972
|
+
|
|
973
|
+
```javascript
|
|
974
|
+
const momentkh = require("@thyrith/momentkh");
|
|
975
|
+
```
|
|
976
|
+
|
|
977
|
+
### API Migration
|
|
978
|
+
|
|
979
|
+
#### Converting Today's Date
|
|
980
|
+
|
|
981
|
+
**Before (v1):**
|
|
982
|
+
|
|
983
|
+
```javascript
|
|
984
|
+
const moment = require("moment");
|
|
985
|
+
require("@thyrith/momentkh")(moment);
|
|
986
|
+
|
|
987
|
+
const today = moment();
|
|
988
|
+
const khmerDate = today.toKhDate();
|
|
989
|
+
console.log(khmerDate);
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
**After (v2):**
|
|
993
|
+
|
|
994
|
+
```javascript
|
|
995
|
+
const momentkh = require("@thyrith/momentkh");
|
|
996
|
+
|
|
997
|
+
const today = new Date();
|
|
998
|
+
const khmer = momentkh.fromDate(today);
|
|
999
|
+
const khmerDate = momentkh.format(khmer);
|
|
1000
|
+
console.log(khmerDate);
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
#### Converting Specific Date
|
|
1004
|
+
|
|
1005
|
+
**Before (v1):**
|
|
1006
|
+
|
|
1007
|
+
```javascript
|
|
1008
|
+
const m = moment("2024-04-14", "YYYY-MM-DD");
|
|
1009
|
+
console.log(m.toKhDate());
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
**After (v2):**
|
|
1013
|
+
|
|
1014
|
+
```javascript
|
|
1015
|
+
const khmer = momentkh.fromGregorian(2024, 4, 14);
|
|
1016
|
+
console.log(momentkh.format(khmer));
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
#### Getting Khmer Day/Month/Year
|
|
1020
|
+
|
|
1021
|
+
**Before (v1):**
|
|
1022
|
+
|
|
1023
|
+
```javascript
|
|
1024
|
+
const m = moment();
|
|
1025
|
+
console.log(m.khDay()); // Day index (0-29)
|
|
1026
|
+
console.log(m.khMonth()); // Month index (0-13)
|
|
1027
|
+
console.log(m.khYear()); // BE year
|
|
1028
|
+
```
|
|
1029
|
+
|
|
1030
|
+
**After (v2):**
|
|
1031
|
+
|
|
1032
|
+
```javascript
|
|
1033
|
+
const khmer = momentkh.fromDate(new Date());
|
|
1034
|
+
console.log(khmer._khmerDateObj.getDayNumber()); // Day number (0-29)
|
|
1035
|
+
console.log(khmer.khmer.monthIndex); // Month index (0-13)
|
|
1036
|
+
console.log(khmer.khmer.beYear); // BE year
|
|
1037
|
+
|
|
1038
|
+
// Or access individual components
|
|
1039
|
+
console.log(khmer.khmer.day); // Day in phase (1-15)
|
|
1040
|
+
console.log(khmer.khmer.moonPhase); // 0=កើត, 1=រោច
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
#### Custom Formatting
|
|
1044
|
+
|
|
1045
|
+
**Before (v1):**
|
|
1046
|
+
|
|
1047
|
+
```javascript
|
|
1048
|
+
const m = moment("1992-03-04", "YYYY-MM-DD");
|
|
1049
|
+
console.log(m.toLunarDate("dN ថ្ងៃW ខែm ព.ស. b"));
|
|
1050
|
+
// ៦កើត ថ្ងៃព្រហស្បតិ៍ ខែមិគសិរ ព.ស. ២៥៦២
|
|
1051
|
+
```
|
|
1052
|
+
|
|
1053
|
+
**After (v2):**
|
|
1054
|
+
|
|
1055
|
+
```javascript
|
|
1056
|
+
const khmer = momentkh.fromGregorian(1992, 3, 4);
|
|
1057
|
+
console.log(momentkh.format(khmer, "dN ថ្ងៃW ខែm ព.ស. b"));
|
|
1058
|
+
// ៦កើត ថ្ងៃព្រហស្បតិ៍ ខែមិគសិរ ព.ស. ២៥៣៥
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
#### Getting Khmer New Year
|
|
1062
|
+
|
|
1063
|
+
**Before (v1):**
|
|
1064
|
+
|
|
1065
|
+
```javascript
|
|
1066
|
+
const nyMoment = moment.getKhNewYearMoment(2024);
|
|
1067
|
+
console.log(nyMoment.format("YYYY-MM-DD HH:mm"));
|
|
1068
|
+
```
|
|
1069
|
+
|
|
1070
|
+
**After (v2):**
|
|
1071
|
+
|
|
1072
|
+
```javascript
|
|
1073
|
+
const ny = momentkh.getNewYear(2024);
|
|
1074
|
+
console.log(`${ny.year}-${ny.month}-${ny.day} ${ny.hour}:${ny.minute}`);
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
### Feature Comparison
|
|
1078
|
+
|
|
1079
|
+
| Feature | MomentKH v1 | MomentKH v3 |
|
|
1080
|
+
| --------------------- | -------------------------- | -------------------------- |
|
|
1081
|
+
| **Dependencies** | Requires moment.js (~50KB) | Zero dependencies |
|
|
1082
|
+
| **File Size** | Multiple files | Single file (~35KB) |
|
|
1083
|
+
| **Setup** | Initialize with moment | Direct import/require |
|
|
1084
|
+
| **API Style** | Extends moment.js | Standalone functions |
|
|
1085
|
+
| **Khmer → Gregorian** | ❌ Not supported | ✅ Fully supported |
|
|
1086
|
+
| **Browser Support** | Modern browsers | ES5+ (IE11+) |
|
|
1087
|
+
| **TypeScript** | No types | ✅ Full TypeScript support |
|
|
1088
|
+
|
|
1089
|
+
### Quick Reference Table
|
|
1090
|
+
|
|
1091
|
+
| Task | MomentKH v1 | MomentKH v3 |
|
|
1092
|
+
| ------------------ | --------------------------------- | ------------------------------------------------------------ |
|
|
1093
|
+
| Convert to Khmer | `moment().toKhDate()` | `momentkh.format(momentkh.fromDate(new Date()))` |
|
|
1094
|
+
| Get BE year | `moment().khYear()` | `momentkh.fromDate(new Date()).khmer.beYear` |
|
|
1095
|
+
| Get month | `moment().khMonth()` | `momentkh.fromDate(new Date()).khmer.monthIndex` |
|
|
1096
|
+
| Get day number | `moment().khDay()` | `momentkh.fromDate(new Date())._khmerDateObj.getDayNumber()` |
|
|
1097
|
+
| Custom format | `moment().toLunarDate('format')` | `momentkh.format(khmer, 'format')` |
|
|
1098
|
+
| New Year | `moment.getKhNewYearMoment(year)` | `momentkh.getNewYear(year)` |
|
|
1099
|
+
| Reverse conversion | ❌ Not available | `momentkh.fromKhmer(day, phase, month, year)` |
|
|
1100
|
+
|
|
1101
|
+
---
|
|
1102
|
+
|
|
1103
|
+
## 💡 Examples
|
|
1104
|
+
|
|
1105
|
+
### Example 1: Display Today's Date in Khmer
|
|
1106
|
+
|
|
1107
|
+
```javascript
|
|
1108
|
+
const today = momentkh.fromDate(new Date());
|
|
1109
|
+
console.log(momentkh.format(today));
|
|
1110
|
+
// ថ្ងៃសុក្រ ១០កើត ខែចេត្រ ឆ្នាំរោង ឆស័ក ពុទ្ធសករាជ ២៥៦៨
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
### Example 2: Convert Specific Date
|
|
1114
|
+
|
|
1115
|
+
```javascript
|
|
1116
|
+
// Convert April 14, 2024
|
|
1117
|
+
const khmer = momentkh.fromGregorian(2024, 4, 14);
|
|
1118
|
+
|
|
1119
|
+
console.log(
|
|
1120
|
+
"Gregorian:",
|
|
1121
|
+
`${khmer.gregorian.day}/${khmer.gregorian.month}/${khmer.gregorian.year}`
|
|
1122
|
+
);
|
|
1123
|
+
console.log("BE Year:", khmer.khmer.beYear);
|
|
1124
|
+
console.log("Animal Year:", khmer.khmer.animalYear);
|
|
1125
|
+
console.log("Era:", khmer.khmer.eraYear);
|
|
1126
|
+
console.log("Month:", khmer.khmer.monthName);
|
|
1127
|
+
console.log(
|
|
1128
|
+
"Day:",
|
|
1129
|
+
khmer.khmer.day + (khmer.khmer.moonPhase === 0 ? "កើត" : "រោច")
|
|
1130
|
+
);
|
|
1131
|
+
|
|
1132
|
+
// Output:
|
|
1133
|
+
// Gregorian: 14/4/2024
|
|
1134
|
+
// BE Year: 2568
|
|
1135
|
+
// Animal Year: រោង
|
|
1136
|
+
// Era: ឆស័ក
|
|
1137
|
+
// Month: ចេត្រ
|
|
1138
|
+
// Day: 6កើត
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
### Example 3: Round-Trip Conversion
|
|
1142
|
+
|
|
1143
|
+
```javascript
|
|
1144
|
+
// Convert Gregorian to Khmer
|
|
1145
|
+
const gregorianDate = { year: 2024, month: 4, day: 14 };
|
|
1146
|
+
const khmer = momentkh.fromGregorian(
|
|
1147
|
+
gregorianDate.year,
|
|
1148
|
+
gregorianDate.month,
|
|
1149
|
+
gregorianDate.day
|
|
1150
|
+
);
|
|
1151
|
+
|
|
1152
|
+
console.log(
|
|
1153
|
+
"Original:",
|
|
1154
|
+
`${gregorianDate.year}-${gregorianDate.month}-${gregorianDate.day}`
|
|
1155
|
+
);
|
|
1156
|
+
console.log("Khmer:", momentkh.format(khmer));
|
|
1157
|
+
|
|
1158
|
+
// Convert back to Gregorian
|
|
1159
|
+
const backToGregorian = momentkh.fromKhmer(
|
|
1160
|
+
khmer.khmer.day,
|
|
1161
|
+
khmer.khmer.moonPhase,
|
|
1162
|
+
khmer.khmer.monthIndex,
|
|
1163
|
+
khmer.khmer.beYear
|
|
1164
|
+
);
|
|
1165
|
+
|
|
1166
|
+
console.log(
|
|
1167
|
+
"Converted back:",
|
|
1168
|
+
`${backToGregorian.year}-${backToGregorian.month}-${backToGregorian.day}`
|
|
1169
|
+
);
|
|
1170
|
+
console.log(
|
|
1171
|
+
"Match:",
|
|
1172
|
+
gregorianDate.year === backToGregorian.year &&
|
|
1173
|
+
gregorianDate.month === backToGregorian.month &&
|
|
1174
|
+
gregorianDate.day === backToGregorian.day
|
|
1175
|
+
? "✓"
|
|
1176
|
+
: "✗"
|
|
1177
|
+
);
|
|
1178
|
+
```
|
|
1179
|
+
|
|
1180
|
+
### Example 4: Find All New Years in Range
|
|
1181
|
+
|
|
1182
|
+
```javascript
|
|
1183
|
+
console.log("Khmer New Years 2020-2025:\n");
|
|
1184
|
+
|
|
1185
|
+
for (let year = 2020; year <= 2025; year++) {
|
|
1186
|
+
const ny = momentkh.getNewYear(year);
|
|
1187
|
+
const khmer = momentkh.fromGregorian(
|
|
1188
|
+
ny.year,
|
|
1189
|
+
ny.month,
|
|
1190
|
+
ny.day,
|
|
1191
|
+
ny.hour,
|
|
1192
|
+
ny.minute
|
|
1193
|
+
);
|
|
1194
|
+
|
|
1195
|
+
console.log(`${year} (ឆ្នាំ${khmer.khmer.animalYear}):`);
|
|
1196
|
+
console.log(` Date: ${ny.day}/${ny.month}/${ny.year}`);
|
|
1197
|
+
console.log(` Time: ${ny.hour}:${String(ny.minute).padStart(2, "0")}`);
|
|
1198
|
+
console.log(` Khmer: ${momentkh.format(khmer, "dN ខែm")}\n`);
|
|
1199
|
+
}
|
|
1200
|
+
```
|
|
1201
|
+
|
|
1202
|
+
### Example 5: Calendar Display for a Month
|
|
1203
|
+
|
|
1204
|
+
```javascript
|
|
1205
|
+
function displayKhmerMonth(year, month) {
|
|
1206
|
+
const daysInMonth = new Date(year, month, 0).getDate();
|
|
1207
|
+
|
|
1208
|
+
console.log(`\nKhmer Calendar for ${year}/${month}:\n`);
|
|
1209
|
+
console.log("Gregorian\tKhmer Date");
|
|
1210
|
+
console.log("-".repeat(50));
|
|
1211
|
+
|
|
1212
|
+
for (let day = 1; day <= daysInMonth; day++) {
|
|
1213
|
+
const khmer = momentkh.fromGregorian(year, month, day);
|
|
1214
|
+
const formatted = momentkh.format(khmer, "dN m");
|
|
1215
|
+
console.log(`${year}/${month}/${day}\t\t${formatted}`);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
// Display April 2024
|
|
1220
|
+
displayKhmerMonth(2024, 4);
|
|
1221
|
+
```
|
|
1222
|
+
|
|
1223
|
+
### Example 6: Check BE Year Transition
|
|
1224
|
+
|
|
1225
|
+
```javascript
|
|
1226
|
+
// Find the exact moment BE year changes
|
|
1227
|
+
const year = 2024;
|
|
1228
|
+
|
|
1229
|
+
// Search in May for Visakha Bochea (15កើត Pisakh)
|
|
1230
|
+
for (let day = 20; day <= 25; day++) {
|
|
1231
|
+
const midnight = momentkh.fromGregorian(year, 5, day, 0, 0);
|
|
1232
|
+
|
|
1233
|
+
if (
|
|
1234
|
+
midnight.khmer.day === 15 &&
|
|
1235
|
+
midnight.khmer.moonPhase === 0 &&
|
|
1236
|
+
midnight.khmer.monthIndex === 5
|
|
1237
|
+
) {
|
|
1238
|
+
const beforeMidnight = momentkh.fromGregorian(year, 5, day - 1, 23, 59);
|
|
1239
|
+
|
|
1240
|
+
console.log(`Found Visakha Bochea: ${year}-05-${day}`);
|
|
1241
|
+
console.log(`At ${day - 1} 23:59 - BE ${beforeMidnight.khmer.beYear}`);
|
|
1242
|
+
console.log(`At ${day} 00:00 - BE ${midnight.khmer.beYear}`);
|
|
1243
|
+
console.log(
|
|
1244
|
+
`Year changed: ${
|
|
1245
|
+
beforeMidnight.khmer.beYear !== midnight.khmer.beYear ? "YES" : "NO"
|
|
1246
|
+
}`
|
|
1247
|
+
);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
```
|
|
1251
|
+
|
|
1252
|
+
---
|
|
1253
|
+
|
|
1254
|
+
## 🌐 Browser Support
|
|
1255
|
+
|
|
1256
|
+
| Browser | Version | Status |
|
|
1257
|
+
| ------- | ------------ | ----------------------------- |
|
|
1258
|
+
| Chrome | All versions | ✅ Supported |
|
|
1259
|
+
| Firefox | All versions | ✅ Supported |
|
|
1260
|
+
| Safari | All versions | ✅ Supported |
|
|
1261
|
+
| Edge | All versions | ✅ Supported |
|
|
1262
|
+
| IE | 11+ | ✅ Supported (ES5 compatible) |
|
|
1263
|
+
| Node.js | 8.0+ | ✅ Supported |
|
|
1264
|
+
|
|
1265
|
+
**ES5 Compatibility:** The library is written in ES5-compatible JavaScript and works in older browsers including IE11.
|
|
1266
|
+
|
|
1267
|
+
---
|
|
1268
|
+
|
|
1269
|
+
## 📝 License
|
|
1270
|
+
|
|
1271
|
+
MIT License - Same as original momentkh
|
|
1272
|
+
|
|
1273
|
+
Copyright (c) 2024
|
|
1274
|
+
|
|
1275
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
1276
|
+
|
|
1277
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
1278
|
+
|
|
1279
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
|
|
1280
|
+
|
|
1281
|
+
---
|
|
1282
|
+
|
|
1283
|
+
## 🙏 Credits & References
|
|
1284
|
+
|
|
1285
|
+
- **Original momentkh library** by [Thyrith Sor](https://github.com/ThyrithSor)
|
|
1286
|
+
- **Algorithm based on:**
|
|
1287
|
+
- Traditional Khmer astronomical calculations
|
|
1288
|
+
- "Pratitin Soryakkatik-Chankatik 1900-1999" by Mr. Roath Kim Soeun
|
|
1289
|
+
- Khmer calendar C++ reference implementation
|
|
1290
|
+
- **Resources:**
|
|
1291
|
+
- [CAM-CC: Khmer Calendar](http://www.cam-cc.org)
|
|
1292
|
+
- [Dahlina: Khmer New Year Calculation](http://www.dahlina.com/education/khmer_new_year_time.html)
|
|
1293
|
+
|
|
1294
|
+
---
|
|
1295
|
+
|
|
1296
|
+
## 🐛 Bug Reports & Contributing
|
|
1297
|
+
|
|
1298
|
+
Found a bug or have a suggestion? Please:
|
|
1299
|
+
|
|
1300
|
+
1. Check existing issues on GitHub
|
|
1301
|
+
2. Run the test suite: `node test_conversion_roundtrip.js`
|
|
1302
|
+
3. Create a detailed bug report with:
|
|
1303
|
+
- Input date
|
|
1304
|
+
- Expected output
|
|
1305
|
+
- Actual output
|
|
1306
|
+
- Steps to reproduce
|
|
1307
|
+
|
|
1308
|
+
**Running Tests:**
|
|
1309
|
+
|
|
1310
|
+
```bash
|
|
1311
|
+
# Run round-trip conversion test (1000 random dates)
|
|
1312
|
+
node test_conversion_roundtrip.js
|
|
1313
|
+
|
|
1314
|
+
# Run comparison test (compare with momentkh v1)
|
|
1315
|
+
node test_comparision2.js
|
|
95
1316
|
|
|
96
|
-
|
|
97
|
-
|
|
1317
|
+
# Run specific date tests
|
|
1318
|
+
node test_specific_dates.js
|
|
98
1319
|
```
|
|
99
1320
|
|
|
100
|
-
|
|
101
|
-
|---------|----------------|----------------|
|
|
102
|
-
| W | ថ្ងៃនៃសប្ដាហ៍| អង្គារ |
|
|
103
|
-
| w | ថ្ងៃនៃសប្ដាហ៍កាត់ | អ |
|
|
104
|
-
| d | ថ្ងៃទី ចាប់ពីលេខ ១ ដល់ ១៥ | ១ |
|
|
105
|
-
| D | ថ្ងៃទី ចាប់ពីលេខ ០១ ដល់ ១៥ | ០១ |
|
|
106
|
-
| n | កើត ឬ រោច | ក |
|
|
107
|
-
| N | កើត ឬ រោច | កើត |
|
|
108
|
-
| o | របៀបសរសេរខ្លីអំពីថ្ងៃទី | ᧡ (មានន័យថា ១កើត)|
|
|
109
|
-
| m | ខែចន្ទគតិ | មិគសិរ |
|
|
110
|
-
| M | ខែសុរិយគតិ | មករា |
|
|
111
|
-
| a | ឆ្នាំសត្វ | រកា |
|
|
112
|
-
| e | ស័ក | ឯកស័ក |
|
|
113
|
-
| b | ឆ្នាំពុទ្ធសករាជ | ២៥៥៦ |
|
|
114
|
-
| c | ឆ្នាំគ្រិស្តសករាជ| ២០១៩ |
|
|
115
|
-
| j | ឆ្នាំចុល្លសករាជ | ១៤៦៣ |
|
|
1321
|
+
---
|
|
116
1322
|
|
|
117
|
-
|
|
118
|
-
I know there will be a lot of error.
|
|
1323
|
+
## 📞 Support
|
|
119
1324
|
|
|
120
|
-
|
|
121
|
-
|
|
1325
|
+
- **Documentation:** See examples folder (`newYearMoment.js`, `index.html`)
|
|
1326
|
+
- **Issues:** [GitHub Issues](https://github.com/ThyrithSor/momentkh/issues)
|
|
1327
|
+
- **Comparison:** Check behavior against original momentkh for compatibility
|
|
122
1328
|
|
|
123
|
-
|
|
124
|
-
Welcome pull request
|
|
1329
|
+
---
|
|
125
1330
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
1331
|
+
**Version:** 3.0.0
|
|
1332
|
+
**Last Updated:** December 2024
|
|
1333
|
+
**Status:** Production Ready ✅
|