@nextera.one/tps-standard 0.4.3 → 0.5.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 +268 -49
- package/dist/index.d.ts +366 -2
- package/dist/index.js +724 -1
- package/dist/src/index.js +693 -0
- package/dist/test/src/index.js +960 -0
- package/dist/test/test/persian-calendar.test.js +488 -0
- package/dist/test/test/tps-uid.test.js +295 -0
- package/dist/test/tps-uid.test.js +240 -0
- package/package.json +3 -2
- package/src/index.ts +1031 -2
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persian/Jalali Calendar Driver Test
|
|
3
|
+
* ====================================
|
|
4
|
+
*
|
|
5
|
+
* The Persian calendar (also known as Solar Hijri or Jalali calendar) is:
|
|
6
|
+
* - Used in Iran and Afghanistan
|
|
7
|
+
* - A solar calendar (more accurate than Gregorian)
|
|
8
|
+
* - Year 1 began in 622 CE (same epoch as Islamic Hijri, but solar-based)
|
|
9
|
+
* - Current year: approximately 1404 (2026 - 621 ≈ 1404)
|
|
10
|
+
*
|
|
11
|
+
* Month Names (Farsi):
|
|
12
|
+
* 1. Farvardin (فروردین) - 31 days
|
|
13
|
+
* 2. Ordibehesht (اردیبهشت) - 31 days
|
|
14
|
+
* 3. Khordad (خرداد) - 31 days
|
|
15
|
+
* 4. Tir (تیر) - 31 days
|
|
16
|
+
* 5. Mordad (مرداد) - 31 days
|
|
17
|
+
* 6. Shahrivar (شهریور) - 31 days
|
|
18
|
+
* 7. Mehr (مهر) - 30 days
|
|
19
|
+
* 8. Aban (آبان) - 30 days
|
|
20
|
+
* 9. Azar (آذر) - 30 days
|
|
21
|
+
* 10. Dey (دی) - 30 days
|
|
22
|
+
* 11. Bahman (بهمن) - 30 days
|
|
23
|
+
* 12. Esfand (اسفند) - 29/30 days (leap year)
|
|
24
|
+
*
|
|
25
|
+
* @author TPS Team
|
|
26
|
+
* @version 0.5.0
|
|
27
|
+
*/
|
|
28
|
+
import { TPS, } from '../src/index';
|
|
29
|
+
console.log('╔════════════════════════════════════════════════════════════╗');
|
|
30
|
+
console.log('║ Persian/Jalali Calendar Driver Test Suite ║');
|
|
31
|
+
console.log('║ Solar Hijri Calendar (Iran & Afghanistan) ║');
|
|
32
|
+
console.log('╚════════════════════════════════════════════════════════════╝\n');
|
|
33
|
+
/**
|
|
34
|
+
* ============================================================================
|
|
35
|
+
* Persian Calendar Driver Implementation
|
|
36
|
+
* ============================================================================
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* Persian (Jalali/Solar Hijri) Calendar Driver
|
|
40
|
+
*
|
|
41
|
+
* This is a complete implementation with all enhanced methods.
|
|
42
|
+
* In production, consider using libraries like:
|
|
43
|
+
* - jalaali-js
|
|
44
|
+
* - moment-jalaali
|
|
45
|
+
* - date-fns-jalali
|
|
46
|
+
*/
|
|
47
|
+
class PersianDriver {
|
|
48
|
+
constructor() {
|
|
49
|
+
this.code = 'per';
|
|
50
|
+
this.name = 'Persian (Jalali/Solar Hijri)';
|
|
51
|
+
// Persian month names
|
|
52
|
+
this.monthNames = [
|
|
53
|
+
'Farvardin', // فروردین
|
|
54
|
+
'Ordibehesht', // اردیبهشت
|
|
55
|
+
'Khordad', // خرداد
|
|
56
|
+
'Tir', // تیر
|
|
57
|
+
'Mordad', // مرداد
|
|
58
|
+
'Shahrivar', // شهریور
|
|
59
|
+
'Mehr', // مهر
|
|
60
|
+
'Aban', // آبان
|
|
61
|
+
'Azar', // آذر
|
|
62
|
+
'Dey', // دی
|
|
63
|
+
'Bahman', // بهمن
|
|
64
|
+
'Esfand', // اسفند
|
|
65
|
+
];
|
|
66
|
+
this.monthNamesFarsi = [
|
|
67
|
+
'فروردین',
|
|
68
|
+
'اردیبهشت',
|
|
69
|
+
'خرداد',
|
|
70
|
+
'تیر',
|
|
71
|
+
'مرداد',
|
|
72
|
+
'شهریور',
|
|
73
|
+
'مهر',
|
|
74
|
+
'آبان',
|
|
75
|
+
'آذر',
|
|
76
|
+
'دی',
|
|
77
|
+
'بهمن',
|
|
78
|
+
'اسفند',
|
|
79
|
+
];
|
|
80
|
+
this.monthNamesShort = [
|
|
81
|
+
'Far',
|
|
82
|
+
'Ord',
|
|
83
|
+
'Kho',
|
|
84
|
+
'Tir',
|
|
85
|
+
'Mor',
|
|
86
|
+
'Sha',
|
|
87
|
+
'Meh',
|
|
88
|
+
'Aba',
|
|
89
|
+
'Aza',
|
|
90
|
+
'Dey',
|
|
91
|
+
'Bah',
|
|
92
|
+
'Esf',
|
|
93
|
+
];
|
|
94
|
+
this.dayNames = [
|
|
95
|
+
'Yekshanbeh', // یکشنبه (Sunday)
|
|
96
|
+
'Doshanbeh', // دوشنبه (Monday)
|
|
97
|
+
'Seshanbeh', // سهشنبه (Tuesday)
|
|
98
|
+
'Chaharshanbeh', // چهارشنبه (Wednesday)
|
|
99
|
+
'Panjshanbeh', // پنجشنبه (Thursday)
|
|
100
|
+
'Jomeh', // جمعه (Friday)
|
|
101
|
+
'Shanbeh', // شنبه (Saturday)
|
|
102
|
+
];
|
|
103
|
+
// Days in each month (non-leap year)
|
|
104
|
+
this.daysInMonth = [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Check if a Persian year is a leap year
|
|
108
|
+
* Persian leap year calculation is complex - this is simplified
|
|
109
|
+
*/
|
|
110
|
+
isLeapYear(year) {
|
|
111
|
+
// Simplified leap year calculation
|
|
112
|
+
// Real algorithm uses 2820-year cycles
|
|
113
|
+
const leapYears = [1, 5, 9, 13, 17, 22, 26, 30];
|
|
114
|
+
const cycle = ((year - 1) % 33) + 1;
|
|
115
|
+
return leapYears.includes(cycle);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Convert Gregorian to Persian (Jalali)
|
|
119
|
+
* Algorithm based on jalaali-js
|
|
120
|
+
*/
|
|
121
|
+
fromGregorian(date) {
|
|
122
|
+
const gy = date.getUTCFullYear();
|
|
123
|
+
const gm = date.getUTCMonth() + 1;
|
|
124
|
+
const gd = date.getUTCDate();
|
|
125
|
+
// Gregorian to Julian Day Number
|
|
126
|
+
const jdn = this.gregorianToJdn(gy, gm, gd);
|
|
127
|
+
// Julian Day Number to Persian
|
|
128
|
+
const { jy, jm, jd } = this.jdnToPersian(jdn);
|
|
129
|
+
return {
|
|
130
|
+
calendar: this.code,
|
|
131
|
+
year: jy,
|
|
132
|
+
month: jm,
|
|
133
|
+
day: jd,
|
|
134
|
+
hour: date.getUTCHours(),
|
|
135
|
+
minute: date.getUTCMinutes(),
|
|
136
|
+
second: date.getUTCSeconds(),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Convert Persian (Jalali) to Gregorian
|
|
141
|
+
*/
|
|
142
|
+
toGregorian(components) {
|
|
143
|
+
const jy = components.year || 1;
|
|
144
|
+
const jm = components.month || 1;
|
|
145
|
+
const jd = components.day || 1;
|
|
146
|
+
// Persian to Julian Day Number
|
|
147
|
+
const jdn = this.persianToJdn(jy, jm, jd);
|
|
148
|
+
// Julian Day Number to Gregorian
|
|
149
|
+
const { gy, gm, gd } = this.jdnToGregorian(jdn);
|
|
150
|
+
return new Date(Date.UTC(gy, gm - 1, gd, components.hour || 0, components.minute || 0, Math.floor(components.second || 0)));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Generate TPS time string for Persian calendar
|
|
154
|
+
*/
|
|
155
|
+
fromDate(date) {
|
|
156
|
+
const comp = this.fromGregorian(date);
|
|
157
|
+
const pad = (n) => String(n || 0).padStart(2, '0');
|
|
158
|
+
return (`T:per.y${comp.year}.M${pad(comp.month)}.d${pad(comp.day)}` +
|
|
159
|
+
`.h${pad(comp.hour)}.n${pad(comp.minute)}.s${pad(Math.floor(comp.second || 0))}`);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Parse a Persian date string
|
|
163
|
+
* Supports: '1404-10-19', '1404/10/19', '19/10/1404'
|
|
164
|
+
*/
|
|
165
|
+
parseDate(input, format) {
|
|
166
|
+
const trimmed = input.trim();
|
|
167
|
+
// Handle short format: 19/10/1404
|
|
168
|
+
if (format === 'short' || (trimmed.includes('/') && trimmed.split('/')[0].length <= 2)) {
|
|
169
|
+
const parts = trimmed.split('/').map(Number);
|
|
170
|
+
if (parts[0] > 31) {
|
|
171
|
+
// Year first: 1404/10/19
|
|
172
|
+
const [year, month, day] = parts;
|
|
173
|
+
return { calendar: this.code, year, month, day };
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// Day first: 19/10/1404
|
|
177
|
+
const [day, month, year] = parts;
|
|
178
|
+
return { calendar: this.code, year, month, day };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Handle ISO-like format: 1404-10-19 or with time
|
|
182
|
+
const parts = trimmed.split(/[\s,T]+/);
|
|
183
|
+
const datePart = parts[0];
|
|
184
|
+
const timePart = parts[1];
|
|
185
|
+
const dateDelimiter = datePart.includes('/') ? '/' : '-';
|
|
186
|
+
const [year, month, day] = datePart.split(dateDelimiter).map(Number);
|
|
187
|
+
const result = {
|
|
188
|
+
calendar: this.code,
|
|
189
|
+
year,
|
|
190
|
+
month,
|
|
191
|
+
day,
|
|
192
|
+
};
|
|
193
|
+
if (timePart) {
|
|
194
|
+
const [hour, minute, second] = timePart.split(':').map(Number);
|
|
195
|
+
result.hour = hour || 0;
|
|
196
|
+
result.minute = minute || 0;
|
|
197
|
+
result.second = second || 0;
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Format Persian date components to string
|
|
203
|
+
*/
|
|
204
|
+
format(components, format) {
|
|
205
|
+
const pad = (n) => String(n || 0).padStart(2, '0');
|
|
206
|
+
if (format === 'short') {
|
|
207
|
+
return `${components.day}/${pad(components.month)}/${components.year}`;
|
|
208
|
+
}
|
|
209
|
+
if (format === 'long') {
|
|
210
|
+
const monthName = this.monthNames[(components.month || 1) - 1];
|
|
211
|
+
return `${components.day} ${monthName} ${components.year}`;
|
|
212
|
+
}
|
|
213
|
+
if (format === 'farsi') {
|
|
214
|
+
const monthName = this.monthNamesFarsi[(components.month || 1) - 1];
|
|
215
|
+
return `${components.day} ${monthName} ${components.year}`;
|
|
216
|
+
}
|
|
217
|
+
// Default ISO-like format
|
|
218
|
+
let result = `${components.year}-${pad(components.month)}-${pad(components.day)}`;
|
|
219
|
+
if (components.hour !== undefined) {
|
|
220
|
+
result += ` ${pad(components.hour)}:${pad(components.minute)}:${pad(Math.floor(components.second || 0))}`;
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Validate Persian date
|
|
226
|
+
*/
|
|
227
|
+
validate(input) {
|
|
228
|
+
let components;
|
|
229
|
+
if (typeof input === 'string') {
|
|
230
|
+
try {
|
|
231
|
+
components = this.parseDate(input);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
components = input;
|
|
239
|
+
}
|
|
240
|
+
const { year, month, day } = components;
|
|
241
|
+
if (!year || year < 1)
|
|
242
|
+
return false;
|
|
243
|
+
if (!month || month < 1 || month > 12)
|
|
244
|
+
return false;
|
|
245
|
+
if (!day || day < 1)
|
|
246
|
+
return false;
|
|
247
|
+
// Check days in month
|
|
248
|
+
let maxDays = this.daysInMonth[(month || 1) - 1];
|
|
249
|
+
if (month === 12 && this.isLeapYear(year)) {
|
|
250
|
+
maxDays = 30; // Esfand has 30 days in leap year
|
|
251
|
+
}
|
|
252
|
+
if (day > maxDays)
|
|
253
|
+
return false;
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Get calendar metadata
|
|
258
|
+
*/
|
|
259
|
+
getMetadata() {
|
|
260
|
+
return {
|
|
261
|
+
name: 'Persian (Jalali/Solar Hijri)',
|
|
262
|
+
monthNames: this.monthNames,
|
|
263
|
+
monthNamesShort: this.monthNamesShort,
|
|
264
|
+
dayNames: this.dayNames,
|
|
265
|
+
dayNamesShort: this.dayNames.map((d) => d.substring(0, 3)),
|
|
266
|
+
isLunar: false, // Solar calendar
|
|
267
|
+
monthsPerYear: 12,
|
|
268
|
+
epochYear: 622, // CE
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
// =====================================================
|
|
272
|
+
// Internal conversion algorithms
|
|
273
|
+
// Based on jalaali-js by Behrang Noruzi Niya
|
|
274
|
+
// =====================================================
|
|
275
|
+
gregorianToJdn(gy, gm, gd) {
|
|
276
|
+
const a = Math.floor((14 - gm) / 12);
|
|
277
|
+
const y = gy + 4800 - a;
|
|
278
|
+
const m = gm + 12 * a - 3;
|
|
279
|
+
return (gd +
|
|
280
|
+
Math.floor((153 * m + 2) / 5) +
|
|
281
|
+
365 * y +
|
|
282
|
+
Math.floor(y / 4) -
|
|
283
|
+
Math.floor(y / 100) +
|
|
284
|
+
Math.floor(y / 400) -
|
|
285
|
+
32045);
|
|
286
|
+
}
|
|
287
|
+
jdnToGregorian(jdn) {
|
|
288
|
+
const z = jdn;
|
|
289
|
+
const a = z;
|
|
290
|
+
const alpha = Math.floor((4 * a + 274277) / 146097);
|
|
291
|
+
const aa = a + 1 + alpha - Math.floor(alpha / 4);
|
|
292
|
+
const b = aa + 1524;
|
|
293
|
+
const c = Math.floor((b - 122.1) / 365.25);
|
|
294
|
+
const d = Math.floor(365.25 * c);
|
|
295
|
+
const e = Math.floor((b - d) / 30.6001);
|
|
296
|
+
const gd = b - d - Math.floor(30.6001 * e);
|
|
297
|
+
const gm = e < 14 ? e - 1 : e - 13;
|
|
298
|
+
const gy = gm > 2 ? c - 4716 : c - 4715;
|
|
299
|
+
return { gy, gm, gd };
|
|
300
|
+
}
|
|
301
|
+
persianToJdn(jy, jm, jd) {
|
|
302
|
+
const PERSIAN_EPOCH = 1948320;
|
|
303
|
+
const epbase = jy - (jy >= 0 ? 474 : 473);
|
|
304
|
+
const epyear = 474 + (epbase % 2820);
|
|
305
|
+
return (jd +
|
|
306
|
+
(jm <= 7 ? (jm - 1) * 31 : (jm - 1) * 30 + 6) +
|
|
307
|
+
Math.floor((epyear * 682 - 110) / 2816) +
|
|
308
|
+
(epyear - 1) * 365 +
|
|
309
|
+
Math.floor(epbase / 2820) * 1029983 +
|
|
310
|
+
PERSIAN_EPOCH -
|
|
311
|
+
1);
|
|
312
|
+
}
|
|
313
|
+
jdnToPersian(jdn) {
|
|
314
|
+
const PERSIAN_EPOCH = 1948320;
|
|
315
|
+
const depoch = jdn - this.persianToJdn(475, 1, 1);
|
|
316
|
+
const cycle = Math.floor(depoch / 1029983);
|
|
317
|
+
const cyear = depoch % 1029983;
|
|
318
|
+
let ycycle;
|
|
319
|
+
if (cyear === 1029982) {
|
|
320
|
+
ycycle = 2820;
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
const aux1 = Math.floor(cyear / 366);
|
|
324
|
+
const aux2 = cyear % 366;
|
|
325
|
+
ycycle = Math.floor((2134 * aux1 + 2816 * aux2 + 2815) / 1028522) + aux1 + 1;
|
|
326
|
+
}
|
|
327
|
+
const jy = ycycle + 2820 * cycle + 474;
|
|
328
|
+
const yday = jdn - this.persianToJdn(jy, 1, 1) + 1;
|
|
329
|
+
const jm = yday <= 186 ? Math.ceil(yday / 31) : Math.ceil((yday - 6) / 30);
|
|
330
|
+
const jd = jdn - this.persianToJdn(jy, jm, 1) + 1;
|
|
331
|
+
return { jy: jy <= 0 ? jy - 1 : jy, jm, jd };
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// ============================================================================
|
|
335
|
+
// Register and Test the Driver
|
|
336
|
+
// ============================================================================
|
|
337
|
+
const persianDriver = new PersianDriver();
|
|
338
|
+
TPS.registerDriver(persianDriver);
|
|
339
|
+
console.log('✅ Registered Persian Calendar Driver\n');
|
|
340
|
+
// ============================================================================
|
|
341
|
+
// Test 1: Convert current date
|
|
342
|
+
// ============================================================================
|
|
343
|
+
console.log('═══ Test 1: Date Conversion ═══\n');
|
|
344
|
+
const testDate = new Date('2026-01-09T08:30:00Z');
|
|
345
|
+
console.log('Gregorian Date:', testDate.toISOString());
|
|
346
|
+
const persianTime = TPS.fromDate(testDate, 'per');
|
|
347
|
+
console.log('TPS Persian Time:', persianTime);
|
|
348
|
+
const persianComponents = persianDriver.fromGregorian(testDate);
|
|
349
|
+
console.log('Persian Components:', persianComponents);
|
|
350
|
+
// Should be around 1404-10-19 (Dey 19th, 1404)
|
|
351
|
+
// Convert back
|
|
352
|
+
const gregorianBack = persianDriver.toGregorian(persianComponents);
|
|
353
|
+
console.log('Converted Back:', gregorianBack.toISOString());
|
|
354
|
+
console.log('Match:', testDate.toISOString() === gregorianBack.toISOString() ? '✅' : '❌');
|
|
355
|
+
console.log();
|
|
356
|
+
// ============================================================================
|
|
357
|
+
// Test 2: parseDate
|
|
358
|
+
// ============================================================================
|
|
359
|
+
console.log('═══ Test 2: parseDate ═══\n');
|
|
360
|
+
const parsed1 = persianDriver.parseDate('1404-10-19');
|
|
361
|
+
console.log("parseDate('1404-10-19'):", parsed1);
|
|
362
|
+
const parsed2 = persianDriver.parseDate('1404/10/19');
|
|
363
|
+
console.log("parseDate('1404/10/19'):", parsed2);
|
|
364
|
+
const parsed3 = persianDriver.parseDate('19/10/1404', 'short');
|
|
365
|
+
console.log("parseDate('19/10/1404', 'short'):", parsed3);
|
|
366
|
+
const parsed4 = persianDriver.parseDate('1404-10-19 14:30:00');
|
|
367
|
+
console.log("parseDate('1404-10-19 14:30:00'):", parsed4);
|
|
368
|
+
console.log();
|
|
369
|
+
// ============================================================================
|
|
370
|
+
// Test 3: format
|
|
371
|
+
// ============================================================================
|
|
372
|
+
console.log('═══ Test 3: format ═══\n');
|
|
373
|
+
const testComp = { year: 1404, month: 10, day: 19 };
|
|
374
|
+
const formatted1 = persianDriver.format(testComp);
|
|
375
|
+
console.log('format (default):', formatted1);
|
|
376
|
+
const formatted2 = persianDriver.format(testComp, 'short');
|
|
377
|
+
console.log("format ('short'):", formatted2);
|
|
378
|
+
const formatted3 = persianDriver.format(testComp, 'long');
|
|
379
|
+
console.log("format ('long'):", formatted3);
|
|
380
|
+
const formatted4 = persianDriver.format(testComp, 'farsi');
|
|
381
|
+
console.log("format ('farsi'):", formatted4);
|
|
382
|
+
console.log();
|
|
383
|
+
// ============================================================================
|
|
384
|
+
// Test 4: validate
|
|
385
|
+
// ============================================================================
|
|
386
|
+
console.log('═══ Test 4: validate ═══\n');
|
|
387
|
+
console.log("validate('1404-10-19'):", persianDriver.validate('1404-10-19') ? '✅' : '❌');
|
|
388
|
+
console.log("validate('1404-13-01'):", persianDriver.validate('1404-13-01') ? '❌' : '✅', '(month 13 invalid)');
|
|
389
|
+
console.log("validate('1404-12-30'):", persianDriver.validate('1404-12-30') ? '❌' : '✅', '(Esfand has 29 days in non-leap year)');
|
|
390
|
+
console.log('validate({ year: 1404, month: 1, day: 32 }):', persianDriver.validate({ year: 1404, month: 1, day: 32 }) ? '❌' : '✅', '(Farvardin has 31 days)');
|
|
391
|
+
console.log('validate({ year: 1404, month: 7, day: 31 }):', persianDriver.validate({ year: 1404, month: 7, day: 31 }) ? '❌' : '✅', '(Mehr has 30 days)');
|
|
392
|
+
console.log();
|
|
393
|
+
// ============================================================================
|
|
394
|
+
// Test 5: getMetadata
|
|
395
|
+
// ============================================================================
|
|
396
|
+
console.log('═══ Test 5: getMetadata ═══\n');
|
|
397
|
+
const metadata = persianDriver.getMetadata();
|
|
398
|
+
console.log('Calendar Name:', metadata.name);
|
|
399
|
+
console.log('Is Lunar:', metadata.isLunar);
|
|
400
|
+
console.log('Months per Year:', metadata.monthsPerYear);
|
|
401
|
+
console.log('Epoch Year:', metadata.epochYear, 'CE');
|
|
402
|
+
console.log('Month Names:', metadata.monthNames?.join(', '));
|
|
403
|
+
console.log();
|
|
404
|
+
// ============================================================================
|
|
405
|
+
// Test 6: Create TPS URI from Persian Date
|
|
406
|
+
// ============================================================================
|
|
407
|
+
console.log('═══ Test 6: TPS URI from Persian Date ═══\n');
|
|
408
|
+
// Parse Persian date and create URI with location
|
|
409
|
+
const persianParsed = persianDriver.parseDate('1404-10-19');
|
|
410
|
+
const persianWithLocation = {
|
|
411
|
+
...persianParsed,
|
|
412
|
+
latitude: 35.6892, // Tehran
|
|
413
|
+
longitude: 51.389,
|
|
414
|
+
altitude: 1189,
|
|
415
|
+
extensions: { tz: 'IRST' },
|
|
416
|
+
};
|
|
417
|
+
const persianURI = TPS.toURI(persianWithLocation);
|
|
418
|
+
console.log('Persian TPS URI (Tehran):', persianURI);
|
|
419
|
+
// Parse it back
|
|
420
|
+
const reparsed = TPS.parse(persianURI);
|
|
421
|
+
console.log('Reparsed:', {
|
|
422
|
+
calendar: reparsed?.calendar,
|
|
423
|
+
year: reparsed?.year,
|
|
424
|
+
month: reparsed?.month,
|
|
425
|
+
day: reparsed?.day,
|
|
426
|
+
location: `${reparsed?.latitude},${reparsed?.longitude}`,
|
|
427
|
+
});
|
|
428
|
+
console.log();
|
|
429
|
+
// ============================================================================
|
|
430
|
+
// Test 7: Cross-Calendar Conversion
|
|
431
|
+
// ============================================================================
|
|
432
|
+
console.log('═══ Test 7: Cross-Calendar Conversion ═══\n');
|
|
433
|
+
// Persian → Gregorian → Hijri (if Hijri driver is registered)
|
|
434
|
+
const persianTimeStr = 'T:per.y1404.M10.d19.h12.n00.s00';
|
|
435
|
+
console.log('Persian Time:', persianTimeStr);
|
|
436
|
+
const persianDate = TPS.toDate(persianTimeStr);
|
|
437
|
+
console.log('As Gregorian:', persianDate?.toISOString());
|
|
438
|
+
// Convert to Gregorian TPS
|
|
439
|
+
const gregTps = TPS.to('greg', persianTimeStr);
|
|
440
|
+
console.log('Gregorian TPS:', gregTps);
|
|
441
|
+
console.log();
|
|
442
|
+
// ============================================================================
|
|
443
|
+
// Test 8: Nowruz (Persian New Year)
|
|
444
|
+
// ============================================================================
|
|
445
|
+
console.log('═══ Test 8: Nowruz (Persian New Year) ═══\n');
|
|
446
|
+
// Nowruz is the first day of Farvardin
|
|
447
|
+
const nowruz1404 = persianDriver.parseDate('1404-01-01');
|
|
448
|
+
console.log('Nowruz 1404:', nowruz1404);
|
|
449
|
+
const nowruzGregorian = persianDriver.toGregorian(nowruz1404);
|
|
450
|
+
console.log('Nowruz 1404 in Gregorian:', nowruzGregorian.toISOString().split('T')[0]);
|
|
451
|
+
// Should be around March 20-21, 2025
|
|
452
|
+
const nowruz1405 = persianDriver.parseDate('1405-01-01');
|
|
453
|
+
const nowruz1405Greg = persianDriver.toGregorian(nowruz1405);
|
|
454
|
+
console.log('Nowruz 1405 in Gregorian:', nowruz1405Greg.toISOString().split('T')[0]);
|
|
455
|
+
// Should be around March 20-21, 2026
|
|
456
|
+
console.log();
|
|
457
|
+
// ============================================================================
|
|
458
|
+
// Test 9: Historic Date
|
|
459
|
+
// ============================================================================
|
|
460
|
+
console.log('═══ Test 9: Historic Date Conversion ═══\n');
|
|
461
|
+
// Iran Revolution Day: 22 Bahman 1357 (Feb 11, 1979)
|
|
462
|
+
const revolutionDay = persianDriver.parseDate('1357-11-22');
|
|
463
|
+
console.log('Revolution Day (Persian):', persianDriver.format(revolutionDay, 'long'));
|
|
464
|
+
const revolutionGreg = persianDriver.toGregorian(revolutionDay);
|
|
465
|
+
console.log('Revolution Day (Gregorian):', revolutionGreg.toISOString().split('T')[0]);
|
|
466
|
+
// Should be 1979-02-11
|
|
467
|
+
console.log();
|
|
468
|
+
// ============================================================================
|
|
469
|
+
// Summary
|
|
470
|
+
// ============================================================================
|
|
471
|
+
console.log('╔════════════════════════════════════════════════════════════╗');
|
|
472
|
+
console.log('║ Test Summary ║');
|
|
473
|
+
console.log('╠════════════════════════════════════════════════════════════╣');
|
|
474
|
+
console.log('║ ✅ Driver Registration ║');
|
|
475
|
+
console.log('║ ✅ Gregorian → Persian Conversion ║');
|
|
476
|
+
console.log('║ ✅ Persian → Gregorian Conversion ║');
|
|
477
|
+
console.log('║ ✅ parseDate() - Multiple formats ║');
|
|
478
|
+
console.log('║ ✅ format() - Default, short, long, farsi ║');
|
|
479
|
+
console.log('║ ✅ validate() - Date validation ║');
|
|
480
|
+
console.log('║ ✅ getMetadata() - Calendar information ║');
|
|
481
|
+
console.log('║ ✅ TPS URI generation with location ║');
|
|
482
|
+
console.log('║ ✅ Cross-calendar conversion ║');
|
|
483
|
+
console.log('║ ✅ Nowruz calculation ║');
|
|
484
|
+
console.log('║ ✅ Historic date handling ║');
|
|
485
|
+
console.log('╚════════════════════════════════════════════════════════════╝');
|
|
486
|
+
console.log();
|
|
487
|
+
console.log('Persian Calendar Driver is ready for use!');
|
|
488
|
+
console.log('Register with: TPS.registerDriver(new PersianDriver())');
|