@nextera.one/tps-standard 0.5.3 → 0.5.34

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.
Files changed (57) hide show
  1. package/dist/date.d.ts +54 -0
  2. package/dist/date.js +174 -0
  3. package/dist/date.js.map +1 -0
  4. package/dist/drivers/gregorian.d.ts +3 -5
  5. package/dist/drivers/gregorian.js +26 -19
  6. package/dist/drivers/gregorian.js.map +1 -1
  7. package/dist/drivers/hijri.d.ts +1 -16
  8. package/dist/drivers/hijri.js +9 -102
  9. package/dist/drivers/hijri.js.map +1 -1
  10. package/dist/drivers/holocene.d.ts +6 -3
  11. package/dist/drivers/holocene.js +7 -20
  12. package/dist/drivers/holocene.js.map +1 -1
  13. package/dist/drivers/julian.d.ts +3 -10
  14. package/dist/drivers/julian.js +11 -71
  15. package/dist/drivers/julian.js.map +1 -1
  16. package/dist/drivers/persian.d.ts +1 -6
  17. package/dist/drivers/persian.js +17 -92
  18. package/dist/drivers/persian.js.map +1 -1
  19. package/dist/drivers/tps.d.ts +11 -28
  20. package/dist/drivers/tps.js +8 -58
  21. package/dist/drivers/tps.js.map +1 -1
  22. package/dist/drivers/unix.d.ts +5 -6
  23. package/dist/drivers/unix.js +10 -32
  24. package/dist/drivers/unix.js.map +1 -1
  25. package/dist/index.d.ts +6 -477
  26. package/dist/index.js +33 -978
  27. package/dist/index.js.map +1 -1
  28. package/dist/types.d.ts +85 -0
  29. package/dist/types.js +30 -0
  30. package/dist/types.js.map +1 -0
  31. package/dist/uid.d.ts +48 -0
  32. package/dist/uid.js +225 -0
  33. package/dist/uid.js.map +1 -0
  34. package/dist/utils/calendar.d.ts +55 -0
  35. package/dist/utils/calendar.js +136 -0
  36. package/dist/utils/calendar.js.map +1 -0
  37. package/dist/utils/env.d.ts +12 -0
  38. package/dist/utils/env.js +79 -0
  39. package/dist/utils/env.js.map +1 -0
  40. package/dist/utils/tps-string.d.ts +12 -0
  41. package/dist/utils/tps-string.js +164 -0
  42. package/dist/utils/tps-string.js.map +1 -0
  43. package/package.json +1 -1
  44. package/src/date.ts +243 -0
  45. package/src/drivers/gregorian.ts +29 -27
  46. package/src/drivers/hijri.ts +13 -113
  47. package/src/drivers/holocene.ts +11 -12
  48. package/src/drivers/julian.ts +18 -72
  49. package/src/drivers/persian.ts +25 -92
  50. package/src/drivers/tps.ts +16 -55
  51. package/src/drivers/unix.ts +12 -33
  52. package/src/index.ts +18 -1446
  53. package/src/types.ts +107 -0
  54. package/src/uid.ts +308 -0
  55. package/src/utils/calendar.ts +161 -0
  56. package/src/utils/env.ts +88 -0
  57. package/src/utils/tps-string.ts +166 -0
@@ -1,17 +1,9 @@
1
- import {
2
- CalendarDriver,
3
- TPSComponents,
4
- TimeOrder,
5
- TPS,
6
- CalendarMetadata,
7
- } from "../index";
1
+ import { CalendarDriver, CalendarMetadata, TPSComponents } from "../types";
2
+ import { buildTimePart } from "../utils/tps-string";
8
3
 
9
4
  /**
10
5
  * Gregorian calendar driver.
11
- * This mirrors the built-in logic that used to live in `TPS.fromDate`/`toDate`
12
- * and provides implementations for the full `CalendarDriver` interface.
13
- * The driver also implements the optional helpers, enabling unit tests to
14
- * exercise `parseDate`, `format`, `validate`, and `getMetadata`.
6
+ * Supports robust validation and canonical Date conversions.
15
7
  */
16
8
  export class GregorianDriver implements CalendarDriver {
17
9
  readonly code: string = "greg";
@@ -54,16 +46,13 @@ export class GregorianDriver implements CalendarDriver {
54
46
 
55
47
  getFromDate(date: Date): string {
56
48
  const comp = this.getComponentsFromDate(date) as TPSComponents;
57
- // buildTimePart understands the `order` field if the caller has set it
58
- return TPS.buildTimePart(comp);
49
+ return buildTimePart(comp);
59
50
  }
60
51
 
61
52
  // --- optional helpers --------------------------------------------------
62
53
 
63
54
  parseDate(input: string, format?: string): Partial<TPSComponents> {
64
- // Accept ISO-like formats: "YYYY-MM-DD" and optionally time portion
65
55
  const s = input.trim();
66
- // simple regex - not exhaustive
67
56
  const m = s.match(
68
57
  /^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?)?$/,
69
58
  );
@@ -95,7 +84,6 @@ export class GregorianDriver implements CalendarDriver {
95
84
  }
96
85
 
97
86
  format(components: Partial<TPSComponents>, format?: string): string {
98
- // For simplicity we ignore `format` and always produce ISO-ish string
99
87
  const y =
100
88
  components.year !== undefined
101
89
  ? String(components.year).padStart(4, "0")
@@ -136,24 +124,38 @@ export class GregorianDriver implements CalendarDriver {
136
124
  return out;
137
125
  }
138
126
 
127
+ private isLeap(y: number): boolean {
128
+ return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0;
129
+ }
130
+
139
131
  validate(input: string | Partial<TPSComponents>): boolean {
140
132
  if (typeof input === "string") {
141
- // basic ISO date with optional time and fractional seconds
142
133
  return /^\d{4}-\d{2}-\d{2}(?:[ T]\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?)?$/.test(
143
134
  input.trim(),
144
135
  );
145
136
  }
146
137
  if (typeof input === "object") {
147
- return (
148
- input.year !== undefined &&
149
- input.month !== undefined &&
150
- input.day !== undefined &&
151
- input.year >= 0 &&
152
- input.month >= 1 &&
153
- input.month <= 12 &&
154
- input.day >= 1 &&
155
- input.day <= 31
156
- );
138
+ const y = input.year ?? 0;
139
+ const m = input.month ?? 1;
140
+ const d = input.day ?? 1;
141
+
142
+ if (y < 0 || m < 1 || m > 12 || d < 1) return false;
143
+
144
+ const daysInMonth = [
145
+ 31,
146
+ this.isLeap(y) ? 29 : 28,
147
+ 31,
148
+ 30,
149
+ 31,
150
+ 30,
151
+ 31,
152
+ 31,
153
+ 30,
154
+ 31,
155
+ 30,
156
+ 31,
157
+ ];
158
+ return d <= daysInMonth[m - 1];
157
159
  }
158
160
  return false;
159
161
  }
@@ -10,7 +10,9 @@
10
10
  * This uses the Tabular Islamic Calendar (civil/Type II-A) algorithm
11
11
  * based on the formulas from Meeus "Astronomical Algorithms".
12
12
  */
13
- import { CalendarDriver, CalendarMetadata, TPSComponents, TPS } from "../index";
13
+ import { CalendarDriver, CalendarMetadata, TPSComponents } from "../types";
14
+ import { buildTimePart } from "../utils/tps-string";
15
+ import { gregorianToHijri, hijriToGregorian } from "../utils/calendar";
14
16
 
15
17
  export class HijriDriver implements CalendarDriver {
16
18
  readonly code = "hij";
@@ -56,15 +58,8 @@ export class HijriDriver implements CalendarDriver {
56
58
  "as-Sabt",
57
59
  ];
58
60
 
59
- /** Leap years in a 30-year cycle (civil / Type II-A pattern) */
60
- private readonly LEAP_YEARS_IN_CYCLE = new Set([
61
- 2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29,
62
- ]);
63
-
64
- // ── CalendarDriver interface ──────────────────────────────────────────
65
-
66
61
  getComponentsFromDate(date: Date): Partial<TPSComponents> {
67
- const { hy, hm, hd } = this.gregorianToHijri(
62
+ const { hy, hm, hd } = gregorianToHijri(
68
63
  date.getUTCFullYear(),
69
64
  date.getUTCMonth() + 1,
70
65
  date.getUTCDate(),
@@ -96,7 +91,7 @@ export class HijriDriver implements CalendarDriver {
96
91
  }
97
92
  const hm = components.month ?? 1;
98
93
  const hd = components.day ?? 1;
99
- const { gy, gm, gd } = this.hijriToGregorian(hy, hm, hd);
94
+ const { gy, gm, gd } = hijriToGregorian(hy, hm, hd);
100
95
 
101
96
  return new Date(
102
97
  Date.UTC(
@@ -113,7 +108,7 @@ export class HijriDriver implements CalendarDriver {
113
108
 
114
109
  getFromDate(date: Date): string {
115
110
  const comp = this.getComponentsFromDate(date) as TPSComponents;
116
- return TPS.buildTimePart(comp);
111
+ return buildTimePart(comp);
117
112
  }
118
113
 
119
114
  parseDate(input: string, format?: string): Partial<TPSComponents> {
@@ -166,9 +161,8 @@ export class HijriDriver implements CalendarDriver {
166
161
  fullYear = components.year ?? 0;
167
162
  }
168
163
 
169
- if (format === "short") {
164
+ if (format === "short")
170
165
  return `${components.day}/${pad(components.month)}/${fullYear}`;
171
- }
172
166
  if (format === "long") {
173
167
  const mn = this.MONTH_NAMES[(components.month ?? 1) - 1];
174
168
  return `${components.day} ${mn} ${fullYear}`;
@@ -192,7 +186,6 @@ export class HijriDriver implements CalendarDriver {
192
186
  comp = input;
193
187
  }
194
188
  const { year, month, day } = comp;
195
- // Reconstruct full year for leap check
196
189
  let fullYear: number;
197
190
  if (comp.millennium !== undefined) {
198
191
  fullYear =
@@ -205,7 +198,12 @@ export class HijriDriver implements CalendarDriver {
205
198
  if (fullYear < 1) return false;
206
199
  if (!month || month < 1 || month > 12) return false;
207
200
  if (!day || day < 1) return false;
208
- const maxDays = this.daysInMonth(fullYear, month);
201
+
202
+ // leap check (cycle of 30 years)
203
+ const isLeap = new Set([2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29]).has(
204
+ ((fullYear - 1) % 30) + 1,
205
+ );
206
+ const maxDays = month === 12 && isLeap ? 30 : month % 2 === 1 ? 30 : 29;
209
207
  return day <= maxDays;
210
208
  }
211
209
 
@@ -221,102 +219,4 @@ export class HijriDriver implements CalendarDriver {
221
219
  epochYear: 1,
222
220
  };
223
221
  }
224
-
225
- // ── Internal helpers ──────────────────────────────────────────────────
226
-
227
- private isLeapYear(year: number): boolean {
228
- return this.LEAP_YEARS_IN_CYCLE.has(((year - 1) % 30) + 1);
229
- }
230
-
231
- private daysInMonth(year: number, month: number): number {
232
- if (month === 12 && this.isLeapYear(year)) return 30;
233
- return month % 2 === 1 ? 30 : 29;
234
- }
235
-
236
- // ── Gregorian ↔ Hijri (Tabular algorithm from Meeus) ──────────────────
237
-
238
- /**
239
- * Convert Gregorian to Hijri (Tabular Islamic Calendar).
240
- * Algorithm from "Astronomical Algorithms" by Jean Meeus.
241
- */
242
- private gregorianToHijri(
243
- gy: number,
244
- gm: number,
245
- gd: number,
246
- ): { hy: number; hm: number; hd: number } {
247
- // Step 1: Gregorian → JDN
248
- const jdn = this.gregorianToJdn(gy, gm, gd);
249
- // Step 2: JDN → Hijri
250
- // L = JDN − 1948440 + 10632
251
- const L = jdn - 1948440 + 10632;
252
- // N = floor((L − 1) / 10631)
253
- const N = Math.floor((L - 1) / 10631);
254
- // L = L − 10631 × N + 354
255
- const L2 = L - 10631 * N + 354;
256
- // J = floor((10985 − L2) / 5316) × floor((50×L2) / 17719) + floor(L2 / 5670) × floor((43×L2) / 15238)
257
- const J =
258
- Math.floor((10985 - L2) / 5316) * Math.floor((50 * L2) / 17719) +
259
- Math.floor(L2 / 5670) * Math.floor((43 * L2) / 15238);
260
- // L3 = L2 − floor((30 − J) / 15) × floor((17719 × J) / 50) − floor(J / 16) × floor((15238 × J) / 43) + 29
261
- const L3 =
262
- L2 -
263
- Math.floor((30 - J) / 15) * Math.floor((17719 * J) / 50) -
264
- Math.floor(J / 16) * Math.floor((15238 * J) / 43) +
265
- 29;
266
- const hm = Math.floor((24 * L3) / 709);
267
- const hd = L3 - Math.floor((709 * hm) / 24);
268
- const hy = 30 * N + J - 30;
269
- return { hy, hm, hd };
270
- }
271
-
272
- /**
273
- * Convert Hijri to Gregorian.
274
- */
275
- private hijriToGregorian(
276
- hy: number,
277
- hm: number,
278
- hd: number,
279
- ): { gy: number; gm: number; gd: number } {
280
- // Hijri → JDN
281
- const jdn =
282
- Math.floor((11 * hy + 3) / 30) +
283
- 354 * hy +
284
- 30 * hm -
285
- Math.floor((hm - 1) / 2) +
286
- hd +
287
- 1948440 -
288
- 385;
289
- // JDN → Gregorian
290
- return this.jdnToGregorian(jdn);
291
- }
292
-
293
- // ── JDN helpers ───────────────────────────────────────────────────────
294
-
295
- private gregorianToJdn(gy: number, gm: number, gd: number): number {
296
- const a = Math.floor((14 - gm) / 12);
297
- const y = gy + 4800 - a;
298
- const m = gm + 12 * a - 3;
299
- return (
300
- gd +
301
- Math.floor((153 * m + 2) / 5) +
302
- 365 * y +
303
- Math.floor(y / 4) -
304
- Math.floor(y / 100) +
305
- Math.floor(y / 400) -
306
- 32045
307
- );
308
- }
309
-
310
- private jdnToGregorian(jdn: number): { gy: number; gm: number; gd: number } {
311
- const a = jdn + 32044;
312
- const b = Math.floor((4 * a + 3) / 146097);
313
- const c = a - Math.floor((146097 * b) / 4);
314
- const d = Math.floor((4 * c + 3) / 1461);
315
- const e = c - Math.floor((1461 * d) / 4);
316
- const m = Math.floor((5 * e + 2) / 153);
317
- const gd = e - Math.floor((153 * m + 2) / 5) + 1;
318
- const gm = m + 3 - 12 * Math.floor(m / 10);
319
- const gy = 100 * b + d - 4800 + Math.floor(m / 10);
320
- return { gy, gm, gd };
321
- }
322
222
  }
@@ -9,9 +9,13 @@
9
9
  *
10
10
  * This is a thin wrapper around GregorianDriver with a year offset.
11
11
  */
12
- import { CalendarDriver, CalendarMetadata, TPSComponents, TPS } from "../index";
12
+ import { CalendarDriver, CalendarMetadata, TPSComponents } from "../types";
13
+ import { buildTimePart } from "../utils/tps-string";
13
14
  import { GregorianDriver } from "./gregorian";
14
15
 
16
+ /**
17
+ * Holocene (Human Era) Calendar Driver
18
+ */
15
19
  export class HoloceneDriver implements CalendarDriver {
16
20
  readonly code = "holo";
17
21
  readonly name = "Holocene (Human Era)";
@@ -19,8 +23,6 @@ export class HoloceneDriver implements CalendarDriver {
19
23
  private readonly gregorian = new GregorianDriver();
20
24
  private readonly YEAR_OFFSET = 10000;
21
25
 
22
- // ── CalendarDriver interface ──────────────────────────────────────────
23
-
24
26
  getComponentsFromDate(date: Date): Partial<TPSComponents> {
25
27
  const greg = this.gregorian.getComponentsFromDate(date);
26
28
  const fullYear = date.getUTCFullYear() + this.YEAR_OFFSET;
@@ -57,21 +59,20 @@ export class HoloceneDriver implements CalendarDriver {
57
59
 
58
60
  getFromDate(date: Date): string {
59
61
  const comp = this.getComponentsFromDate(date) as TPSComponents;
60
- return TPS.buildTimePart(comp);
62
+ return buildTimePart(comp);
61
63
  }
62
64
 
63
- parseDate(input: string, format?: string): Partial<TPSComponents> {
64
- // Accept ISO-like: "12026-01-09" (Holocene year)
65
+ parseDate(input: string, _format?: string): Partial<TPSComponents> {
65
66
  const m = input
66
67
  .trim()
67
68
  .match(
68
69
  /^(\d{4,5})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?)?$/,
69
70
  );
70
- if (!m) {
71
+ if (!m)
71
72
  throw new Error(
72
73
  `HoloceneDriver.parseDate: unsupported format "${input}"`,
73
74
  );
74
- }
75
+
75
76
  const result: Partial<TPSComponents> = {
76
77
  calendar: this.code,
77
78
  year: parseInt(m[1], 10),
@@ -86,9 +87,8 @@ export class HoloceneDriver implements CalendarDriver {
86
87
  return result;
87
88
  }
88
89
 
89
- format(components: Partial<TPSComponents>, format?: string): string {
90
+ format(components: Partial<TPSComponents>, _format?: string): string {
90
91
  const pad = (n?: number, w = 2) => String(n ?? 0).padStart(w, "0");
91
- // Reconstruct full Holocene year from components
92
92
  let holoYear: number;
93
93
  if (components.millennium !== undefined) {
94
94
  const m = components.millennium ?? 0;
@@ -117,7 +117,6 @@ export class HoloceneDriver implements CalendarDriver {
117
117
  );
118
118
  }
119
119
  if (typeof input === "object") {
120
- // Delegate day/month validation to Gregorian (same structure)
121
120
  return this.gregorian.validate({
122
121
  year: input.year,
123
122
  month: input.month,
@@ -146,7 +145,7 @@ export class HoloceneDriver implements CalendarDriver {
146
145
  ],
147
146
  isLunar: false,
148
147
  monthsPerYear: 12,
149
- epochYear: -10000, // 10001 BCE
148
+ epochYear: -10000,
150
149
  };
151
150
  }
152
151
  }
@@ -9,7 +9,14 @@
9
9
  *
10
10
  * Conversion uses Julian Day Number algorithms.
11
11
  */
12
- import { CalendarDriver, CalendarMetadata, TPSComponents, TPS } from "../index";
12
+ import { CalendarDriver, CalendarMetadata, TPSComponents } from "../types";
13
+ import { buildTimePart } from "../utils/tps-string";
14
+ import {
15
+ gregorianToJdn,
16
+ jdnToGregorian,
17
+ julianToJdn,
18
+ jdnToJulian,
19
+ } from "../utils/calendar";
13
20
 
14
21
  export class JulianDriver implements CalendarDriver {
15
22
  readonly code = "jul";
@@ -49,15 +56,13 @@ export class JulianDriver implements CalendarDriver {
49
56
  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
50
57
  ];
51
58
 
52
- // ── CalendarDriver interface ──────────────────────────────────────────
53
-
54
59
  getComponentsFromDate(date: Date): Partial<TPSComponents> {
55
- const jdn = this.gregorianToJdn(
60
+ const jdn = gregorianToJdn(
56
61
  date.getUTCFullYear(),
57
62
  date.getUTCMonth() + 1,
58
63
  date.getUTCDate(),
59
64
  );
60
- const { jy, jm, jd } = this.jdnToJulian(jdn);
65
+ const { jy, jm, jd } = jdnToJulian(jdn);
61
66
 
62
67
  return {
63
68
  calendar: this.code,
@@ -85,8 +90,8 @@ export class JulianDriver implements CalendarDriver {
85
90
  }
86
91
  const jm = components.month ?? 1;
87
92
  const jd = components.day ?? 1;
88
- const jdn = this.julianToJdn(fullYear, jm, jd);
89
- const { gy, gm, gd } = this.jdnToGregorian(jdn);
93
+ const jdn = julianToJdn(fullYear, jm, jd);
94
+ const { gy, gm, gd } = jdnToGregorian(jdn);
90
95
 
91
96
  return new Date(
92
97
  Date.UTC(
@@ -103,17 +108,17 @@ export class JulianDriver implements CalendarDriver {
103
108
 
104
109
  getFromDate(date: Date): string {
105
110
  const comp = this.getComponentsFromDate(date) as TPSComponents;
106
- return TPS.buildTimePart(comp);
111
+ return buildTimePart(comp);
107
112
  }
108
113
 
109
- parseDate(input: string, format?: string): Partial<TPSComponents> {
114
+ parseDate(input: string, _format?: string): Partial<TPSComponents> {
110
115
  const trimmed = input.trim();
111
116
  const m = trimmed.match(
112
117
  /^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?)?$/,
113
118
  );
114
- if (!m) {
119
+ if (!m)
115
120
  throw new Error(`JulianDriver.parseDate: unsupported format "${input}"`);
116
- }
121
+
117
122
  const fullYear = parseInt(m[1], 10);
118
123
  const result: Partial<TPSComponents> = {
119
124
  calendar: this.code,
@@ -131,7 +136,7 @@ export class JulianDriver implements CalendarDriver {
131
136
  return result;
132
137
  }
133
138
 
134
- format(components: Partial<TPSComponents>, format?: string): string {
139
+ format(components: Partial<TPSComponents>, _format?: string): string {
135
140
  const pad = (n?: number, w = 2) => String(n ?? 0).padStart(w, "0");
136
141
  let fullYear: number;
137
142
  if (components.millennium !== undefined) {
@@ -164,7 +169,6 @@ export class JulianDriver implements CalendarDriver {
164
169
  );
165
170
  }
166
171
  if (typeof input === "object") {
167
- // Reconstruct full year for leap check
168
172
  let fullYear: number;
169
173
  if (input.millennium !== undefined) {
170
174
  fullYear =
@@ -178,7 +182,7 @@ export class JulianDriver implements CalendarDriver {
178
182
  if (month === undefined || day === undefined) return false;
179
183
  if (month < 1 || month > 12 || day < 1) return false;
180
184
  let maxDay = this.DAYS_IN_MONTH[month - 1];
181
- if (month === 2 && this.isLeapYear(fullYear)) maxDay = 29;
185
+ if (month === 2 && fullYear % 4 === 0) maxDay = 29;
182
186
  return day <= maxDay;
183
187
  }
184
188
  return false;
@@ -194,62 +198,4 @@ export class JulianDriver implements CalendarDriver {
194
198
  epochYear: 1,
195
199
  };
196
200
  }
197
-
198
- // ── Internal helpers ──────────────────────────────────────────────────
199
-
200
- /** Julian leap year: every 4 years, no century exception */
201
- private isLeapYear(year: number): boolean {
202
- return year % 4 === 0;
203
- }
204
-
205
- // ── JDN algorithms ────────────────────────────────────────────────────
206
-
207
- private julianToJdn(jy: number, jm: number, jd: number): number {
208
- const a = Math.floor((14 - jm) / 12);
209
- const y = jy + 4800 - a;
210
- const m = jm + 12 * a - 3;
211
- return (
212
- jd + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - 32083
213
- );
214
- }
215
-
216
- private jdnToJulian(jdn: number): { jy: number; jm: number; jd: number } {
217
- const c = jdn + 32082;
218
- const d = Math.floor((4 * c + 3) / 1461);
219
- const e = c - Math.floor((1461 * d) / 4);
220
- const m = Math.floor((5 * e + 2) / 153);
221
- const jd = e - Math.floor((153 * m + 2) / 5) + 1;
222
- const jm = m + 3 - 12 * Math.floor(m / 10);
223
- const jy = d - 4800 + Math.floor(m / 10);
224
- return { jy, jm, jd };
225
- }
226
-
227
- /** Gregorian → JDN (for converting incoming Gregorian Date) */
228
- private gregorianToJdn(gy: number, gm: number, gd: number): number {
229
- const a = Math.floor((14 - gm) / 12);
230
- const y = gy + 4800 - a;
231
- const m = gm + 12 * a - 3;
232
- return (
233
- gd +
234
- Math.floor((153 * m + 2) / 5) +
235
- 365 * y +
236
- Math.floor(y / 4) -
237
- Math.floor(y / 100) +
238
- Math.floor(y / 400) -
239
- 32045
240
- );
241
- }
242
-
243
- private jdnToGregorian(jdn: number): { gy: number; gm: number; gd: number } {
244
- const a = jdn + 32044;
245
- const b = Math.floor((4 * a + 3) / 146097);
246
- const c = a - Math.floor((146097 * b) / 4);
247
- const d = Math.floor((4 * c + 3) / 1461);
248
- const e = c - Math.floor((1461 * d) / 4);
249
- const m = Math.floor((5 * e + 2) / 153);
250
- const gd = e - Math.floor((153 * m + 2) / 5) + 1;
251
- const gm = m + 3 - 12 * Math.floor(m / 10);
252
- const gy = 100 * b + d - 4800 + Math.floor(m / 10);
253
- return { gy, gm, gd };
254
- }
255
201
  }