@hebcal/core 4.5.1 → 5.0.0-rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/hdate.mjs DELETED
@@ -1,1909 +0,0 @@
1
- /*! @hebcal/core v4.5.1 */
2
- const GERESH = '׳';
3
- const GERSHAYIM = '״';
4
-
5
- const heb2num = {
6
- 'א': 1,
7
- 'ב': 2,
8
- 'ג': 3,
9
- 'ד': 4,
10
- 'ה': 5,
11
- 'ו': 6,
12
- 'ז': 7,
13
- 'ח': 8,
14
- 'ט': 9,
15
- 'י': 10,
16
- 'כ': 20,
17
- 'ל': 30,
18
- 'מ': 40,
19
- 'נ': 50,
20
- 'ס': 60,
21
- 'ע': 70,
22
- 'פ': 80,
23
- 'צ': 90,
24
- 'ק': 100,
25
- 'ר': 200,
26
- 'ש': 300,
27
- 'ת': 400,
28
- };
29
- const num2heb = {};
30
- Object.keys(heb2num).forEach((key) => {
31
- const val = heb2num[key];
32
- num2heb[val] = key;
33
- });
34
-
35
- /**
36
- * @private
37
- * @param {number} num
38
- * @return {number[]}
39
- */
40
- function num2digits(num) {
41
- const digits = [];
42
- while (num > 0) {
43
- if (num === 15 || num === 16) {
44
- digits.push(9);
45
- digits.push(num - 9);
46
- break;
47
- }
48
- let incr = 100;
49
- let i;
50
- for (i = 400; i > num; i -= incr) {
51
- if (i === incr) {
52
- incr = incr / 10;
53
- }
54
- }
55
- digits.push(i);
56
- num -= i;
57
- }
58
- return digits;
59
- }
60
-
61
- /**
62
- * Converts a numerical value to a string of Hebrew letters.
63
- *
64
- * When specifying years of the Hebrew calendar in the present millennium,
65
- * we omit the thousands (which is presently 5 [ה]).
66
- * @example
67
- * gematriya(5774) // 'תשע״ד' - cropped to 774
68
- * gematriya(25) // 'כ״ה'
69
- * gematriya(60) // 'ס׳'
70
- * gematriya(3761) // 'ג׳תשס״א'
71
- * gematriya(1123) // 'א׳קכ״ג'
72
- * @param {number} number
73
- * @return {string}
74
- */
75
- function gematriya(number) {
76
- const num = parseInt(number, 10);
77
- if (!num) {
78
- throw new TypeError(`invalid parameter to gematriya ${number}`);
79
- }
80
- let str = '';
81
- const thousands = Math.floor(num / 1000);
82
- if (thousands > 0 && thousands !== 5) {
83
- const tdigits = num2digits(thousands);
84
- for (const tdig of tdigits) {
85
- str += num2heb[tdig];
86
- }
87
- str += GERESH;
88
- }
89
- const digits = num2digits(num % 1000);
90
- if (digits.length == 1) {
91
- return str + num2heb[digits[0]] + GERESH;
92
- }
93
- for (let i = 0; i < digits.length; i++) {
94
- if (i + 1 === digits.length) {
95
- str += GERSHAYIM;
96
- }
97
- str += num2heb[digits[i]];
98
- }
99
- return str;
100
- }
101
-
102
- /**
103
- * Converts a string of Hebrew letters to a numerical value.
104
- *
105
- * Only considers the value of Hebrew letters `א` through `ת`.
106
- * Ignores final Hebrew letters such as `ך` (kaf sofit) or `ם` (mem sofit)
107
- * and vowels (nekudot).
108
- *
109
- * @param {string} str
110
- * @return {number}
111
- */
112
- function gematriyaStrToNum(str) {
113
- let num = 0;
114
- const gereshIdx = str.indexOf(GERESH);
115
- if (gereshIdx !== -1 && gereshIdx !== str.length - 1) {
116
- const thousands = str.substring(0, gereshIdx);
117
- num += gematriyaStrToNum(thousands) * 1000;
118
- str = str.substring(gereshIdx);
119
- }
120
- for (const ch of str) {
121
- const n = heb2num[ch];
122
- if (typeof n === 'number') {
123
- num += n;
124
- }
125
- }
126
- return num;
127
- }
128
-
129
- /*
130
- * More minimal greg routines
131
- */
132
-
133
- /** @private */
134
- const lengths = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
135
- /** @private */
136
- const monthLengths = [
137
- lengths,
138
- lengths.slice(),
139
- ];
140
- monthLengths[1][2] = 29;
141
-
142
- /**
143
- * @private
144
- * @param {number} x
145
- * @param {number} y
146
- * @return {number}
147
- */
148
- function mod(x, y) {
149
- return x - y * Math.floor(x / y);
150
- }
151
-
152
- /**
153
- * @private
154
- * @param {number} x
155
- * @param {number} y
156
- * @return {number}
157
- */
158
- function quotient(x, y) {
159
- return Math.floor(x / y);
160
- }
161
-
162
- /**
163
- * Returns true if the Gregorian year is a leap year
164
- * @private
165
- * @param {number} year Gregorian year
166
- * @return {boolean}
167
- */
168
- function isLeapYear$1(year) {
169
- return !(year % 4) && (!!(year % 100) || !(year % 400));
170
- }
171
-
172
- /**
173
- * Number of days in the Gregorian month for given year
174
- * @private
175
- * @param {number} month Gregorian month (1=January, 12=December)
176
- * @param {number} year Gregorian year
177
- * @return {number}
178
- */
179
- function daysInMonth$1(month, year) {
180
- // 1 based months
181
- return monthLengths[+isLeapYear$1(year)][month];
182
- }
183
-
184
- /**
185
- * Returns true if the object is a Javascript Date
186
- * @private
187
- * @param {Object} obj
188
- * @return {boolean}
189
- */
190
- function isDate(obj) {
191
- return typeof obj === 'object' && Date.prototype === obj.__proto__;
192
- }
193
-
194
- /*
195
- const ABS_14SEP1752 = 639797;
196
- const ABS_2SEP1752 = 639785;
197
- */
198
-
199
- /**
200
- * Converts Gregorian date to absolute R.D. (Rata Die) days
201
- * @private
202
- * @param {Date} date Gregorian date
203
- * @return {number}
204
- */
205
- function greg2abs(date) {
206
- if (!isDate(date)) {
207
- throw new TypeError(`Argument not a Date: ${date}`);
208
- }
209
- const abs = toFixed(date.getFullYear(), date.getMonth() + 1, date.getDate());
210
- /*
211
- if (abs < ABS_14SEP1752 && abs > ABS_2SEP1752) {
212
- throw new RangeError(`Invalid Date: ${date}`);
213
- }
214
- */
215
- return abs;
216
- }
217
-
218
- /**
219
- * @private
220
- * @param {number} abs - R.D. number of days
221
- * @return {number}
222
- */
223
- function yearFromFixed(abs) {
224
- const l0 = abs - 1;
225
- const n400 = quotient(l0, 146097);
226
- const d1 = mod(l0, 146097);
227
- const n100 = quotient(d1, 36524);
228
- const d2 = mod(d1, 36524);
229
- const n4 = quotient(d2, 1461);
230
- const d3 = mod(d2, 1461);
231
- const n1 = quotient(d3, 365);
232
- const year = 400 * n400 + 100 * n100 + 4 * n4 + n1;
233
- return n100 != 4 && n1 != 4 ? year + 1 : year;
234
- }
235
-
236
- /**
237
- * @private
238
- * @param {number} year
239
- * @param {number} month (1-12)
240
- * @param {number} day (1-31)
241
- * @return {number}
242
- */
243
- function toFixed(year, month, day) {
244
- const py = year - 1;
245
- return 365 * py +
246
- quotient(py, 4) -
247
- quotient(py, 100) +
248
- quotient(py, 400) +
249
- quotient((367 * month - 362), 12) +
250
- (month <= 2 ? 0 : (isLeapYear$1(year) ? -1 : -2)) +
251
- day;
252
- }
253
-
254
- /**
255
- * Converts from Rata Die (R.D. number) to Gregorian date.
256
- * See the footnote on page 384 of ``Calendrical Calculations, Part II:
257
- * Three Historical Calendars'' by E. M. Reingold, N. Dershowitz, and S. M.
258
- * Clamen, Software--Practice and Experience, Volume 23, Number 4
259
- * (April, 1993), pages 383-404 for an explanation.
260
- * @private
261
- * @param {number} abs - R.D. number of days
262
- * @return {Date}
263
- */
264
- function abs2greg(abs) {
265
- if (typeof abs !== 'number') {
266
- throw new TypeError(`Argument not a Number: ${abs}`);
267
- }
268
- abs = Math.trunc(abs);
269
- /*
270
- if (abs < ABS_14SEP1752 && abs > ABS_2SEP1752) {
271
- throw new RangeError(`Invalid Date: ${abs}`);
272
- }
273
- */
274
- const year = yearFromFixed(abs);
275
- const priorDays = abs - toFixed(year, 1, 1);
276
- const correction = abs < toFixed(year, 3, 1) ? 0 : (isLeapYear$1(year) ? 1 : 2);
277
- const month = quotient((12 * (priorDays + correction) + 373), 367);
278
- const day = abs - toFixed(year, month, 1) + 1;
279
- const dt = new Date(year, month - 1, day);
280
- if (year < 100 && year >= 0) {
281
- dt.setFullYear(year);
282
- }
283
- return dt;
284
- }
285
-
286
- /*
287
- Hebcal - A Jewish Calendar Generator
288
- Copyright (c) 1994-2020 Danny Sadinoff
289
- Portions copyright Eyal Schachter and Michael J. Radwin
290
-
291
- https://github.com/hebcal/hebcal-es6
292
-
293
- This program is free software; you can redistribute it and/or
294
- modify it under the terms of the GNU General Public License
295
- as published by the Free Software Foundation; either version 2
296
- of the License, or (at your option) any later version.
297
-
298
- This program is distributed in the hope that it will be useful,
299
- but WITHOUT ANY WARRANTY; without even the implied warranty of
300
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
301
- GNU General Public License for more details.
302
-
303
- You should have received a copy of the GNU General Public License
304
- along with this program. If not, see <http://www.gnu.org/licenses/>.
305
- */
306
-
307
-
308
- /**
309
- * Gregorian date helper functions.
310
- */
311
- const greg = {
312
- /**
313
- * Long names of the Gregorian months (1='January', 12='December')
314
- * @readonly
315
- * @type {string[]}
316
- */
317
- monthNames: [
318
- '',
319
- 'January',
320
- 'February',
321
- 'March',
322
- 'April',
323
- 'May',
324
- 'June',
325
- 'July',
326
- 'August',
327
- 'September',
328
- 'October',
329
- 'November',
330
- 'December',
331
- ],
332
-
333
- /**
334
- * Returns true if the Gregorian year is a leap year
335
- * @function
336
- * @param {number} year Gregorian year
337
- * @return {boolean}
338
- */
339
- isLeapYear: isLeapYear$1,
340
-
341
- /**
342
- * Number of days in the Gregorian month for given year
343
- * @function
344
- * @param {number} month Gregorian month (1=January, 12=December)
345
- * @param {number} year Gregorian year
346
- * @return {number}
347
- */
348
- daysInMonth: daysInMonth$1,
349
-
350
- /**
351
- * Returns true if the object is a Javascript Date
352
- * @function
353
- * @param {Object} obj
354
- * @return {boolean}
355
- */
356
- isDate: isDate,
357
-
358
- /**
359
- * Returns number of days since January 1 of that year
360
- * @deprecated
361
- * @param {Date} date Gregorian date
362
- * @return {number}
363
- */
364
- dayOfYear: function(date) {
365
- if (!isDate(date)) {
366
- throw new TypeError(`Argument not a Date: ${date}`);
367
- }
368
- const month = date.getMonth();
369
- let doy = date.getDate() + 31 * month;
370
- if (month > 1) {
371
- // FEB
372
- doy -= Math.floor((4 * (month + 1) + 23) / 10);
373
- if (isLeapYear$1(date.getFullYear())) {
374
- doy++;
375
- }
376
- }
377
- return doy;
378
- },
379
-
380
- /**
381
- * Converts Gregorian date to absolute R.D. (Rata Die) days
382
- * @function
383
- * @param {Date} date Gregorian date
384
- * @return {number}
385
- */
386
- greg2abs: greg2abs,
387
-
388
- /**
389
- * Converts from Rata Die (R.D. number) to Gregorian date.
390
- * See the footnote on page 384 of ``Calendrical Calculations, Part II:
391
- * Three Historical Calendars'' by E. M. Reingold, N. Dershowitz, and S. M.
392
- * Clamen, Software--Practice and Experience, Volume 23, Number 4
393
- * (April, 1993), pages 383-404 for an explanation.
394
- * @function
395
- * @param {number} theDate - R.D. number of days
396
- * @return {Date}
397
- */
398
- abs2greg: abs2greg,
399
- };
400
-
401
- const noopLocale = {
402
- headers: {'plural-forms': 'nplurals=2; plural=(n!=1);'},
403
- contexts: {'': {}},
404
- };
405
- const alias = {
406
- 'h': 'he',
407
- 'a': 'ashkenazi',
408
- 's': 'en',
409
- '': 'en',
410
- };
411
-
412
- /** @private */
413
- const locales = Object.create(null);
414
- /** @private */
415
- let activeLocale = null;
416
- /** @private */
417
- let activeName = null;
418
-
419
- /**
420
- * A locale in Hebcal is used for translations/transliterations of
421
- * holidays. `@hebcal/core` supports four locales by default
422
- * * `en` - default, Sephardic transliterations (e.g. "Shabbat")
423
- * * `ashkenazi` - Ashkenazi transliterations (e.g. "Shabbos")
424
- * * `he` - Hebrew (e.g. "שַׁבָּת")
425
- * * `he-x-NoNikud` - Hebrew without nikud (e.g. "שבת")
426
- */
427
- class Locale {
428
- /**
429
- * Returns translation only if `locale` offers a non-empty translation for `id`.
430
- * Otherwise, returns `undefined`.
431
- * @param {string} id Message ID to translate
432
- * @param {string} [locale] Optional locale name (i.e: `'he'`, `'fr'`). Defaults to active locale.
433
- * @return {string}
434
- */
435
- static lookupTranslation(id, locale) {
436
- const locale0 = locale?.toLowerCase();
437
- const loc = (typeof locale == 'string' && locales[locale0]) || activeLocale;
438
- const array = loc[id];
439
- if (array && array.length && array[0].length) {
440
- return array[0];
441
- }
442
- return undefined;
443
- }
444
-
445
- /**
446
- * By default, if no translation was found, returns `id`.
447
- * @param {string} id Message ID to translate
448
- * @param {string} [locale] Optional locale name (i.e: `'he'`, `'fr'`). Defaults to active locale.
449
- * @return {string}
450
- */
451
- static gettext(id, locale) {
452
- const text = this.lookupTranslation(id, locale);
453
- if (typeof text == 'undefined') {
454
- return id;
455
- }
456
- return text;
457
- }
458
-
459
- /**
460
- * Register locale translations.
461
- * @param {string} locale Locale name (i.e.: `'he'`, `'fr'`)
462
- * @param {LocaleData} data parsed data from a `.po` file.
463
- */
464
- static addLocale(locale, data) {
465
- if (typeof locale !== 'string') {
466
- throw new TypeError(`Invalid locale name: ${locale}`);
467
- }
468
- if (typeof data.contexts !== 'object' || typeof data.contexts[''] !== 'object') {
469
- throw new TypeError(`Locale '${locale}' invalid compact format`);
470
- }
471
- locales[locale.toLowerCase()] = data.contexts[''];
472
- }
473
-
474
- /**
475
- * Adds a translation to `locale`, replacing any previous translation.
476
- * @param {string} locale Locale name (i.e: `'he'`, `'fr'`).
477
- * @param {string} id Message ID to translate
478
- * @param {string} translation Translation text
479
- */
480
- static addTranslation(locale, id, translation) {
481
- if (typeof locale !== 'string') {
482
- throw new TypeError(`Invalid locale name: ${locale}`);
483
- }
484
- const locale0 = locale.toLowerCase();
485
- const loc = locales[locale0];
486
- if (!loc) {
487
- throw new TypeError(`Unknown locale: ${locale}`);
488
- }
489
- if (typeof id !== 'string' || id.length === 0) {
490
- throw new TypeError(`Invalid id: ${id}`);
491
- }
492
- const isArray = Array.isArray(translation);
493
- if (isArray) {
494
- const t0 = translation[0];
495
- if (typeof t0 !== 'string' || t0.length === 0) {
496
- throw new TypeError(`Invalid translation array: ${translation}`);
497
- }
498
- } else if (typeof translation !== 'string') {
499
- throw new TypeError(`Invalid translation: ${translation}`);
500
- }
501
- loc[id] = isArray ? translation : [translation];
502
- }
503
- /**
504
- * Adds multiple translations to `locale`, replacing any previous translations.
505
- * @param {string} locale Locale name (i.e: `'he'`, `'fr'`).
506
- * @param {LocaleData} data parsed data from a `.po` file.
507
- */
508
- static addTranslations(locale, data) {
509
- if (typeof locale !== 'string') {
510
- throw new TypeError(`Invalid locale name: ${locale}`);
511
- }
512
- const locale0 = locale.toLowerCase();
513
- const loc = locales[locale0];
514
- if (!loc) {
515
- throw new TypeError(`Unknown locale: ${locale}`);
516
- }
517
- if (typeof data.contexts !== 'object' || typeof data.contexts[''] !== 'object') {
518
- throw new TypeError(`Locale '${locale}' invalid compact format`);
519
- }
520
- const ctx = data.contexts[''];
521
- Object.keys(ctx).forEach((id) => {
522
- loc[id] = ctx[id];
523
- });
524
- }
525
- /**
526
- * Activates a locale. Throws an error if the locale has not been previously added.
527
- * After setting the locale to be used, all strings marked for translations
528
- * will be represented by the corresponding translation in the specified locale.
529
- * @param {string} locale Locale name (i.e: `'he'`, `'fr'`)
530
- * @return {LocaleData}
531
- */
532
- static useLocale(locale) {
533
- const locale0 = locale.toLowerCase();
534
- const obj = locales[locale0];
535
- if (!obj) {
536
- throw new RangeError(`Locale '${locale}' not found`);
537
- }
538
- activeName = alias[locale0] || locale0;
539
- activeLocale = obj;
540
- return activeLocale;
541
- }
542
-
543
- /**
544
- * Returns the name of the active locale (i.e. 'he', 'ashkenazi', 'fr')
545
- * @return {string}
546
- */
547
- static getLocaleName() {
548
- return activeName;
549
- }
550
-
551
- /**
552
- * Returns the names of registered locales
553
- * @return {string[]}
554
- */
555
- static getLocaleNames() {
556
- return Object.keys(locales).sort((a, b) => a.localeCompare(b));
557
- }
558
-
559
- /**
560
- * @param {number} n
561
- * @param {string} [locale] Optional locale name (i.e: `'he'`, `'fr'`). Defaults to active locale.
562
- * @return {string}
563
- */
564
- static ordinal(n, locale) {
565
- const locale1 = locale?.toLowerCase();
566
- const locale0 = locale1 || activeName;
567
- if (!locale0) {
568
- return this.getEnOrdinal(n);
569
- }
570
- switch (locale0) {
571
- case 'en':
572
- case 's':
573
- case 'a':
574
- case 'ashkenazi':
575
- case 'ashkenazi_litvish':
576
- case 'ashkenazi_poylish':
577
- case 'ashkenazi_standard':
578
- return this.getEnOrdinal(n);
579
- case 'es':
580
- return n + 'º';
581
- case 'h':
582
- case 'he':
583
- case 'he-x-nonikud':
584
- return String(n);
585
- default:
586
- return n + '.';
587
- }
588
- }
589
-
590
- /**
591
- * @private
592
- * @param {number} n
593
- * @return {string}
594
- */
595
- static getEnOrdinal(n) {
596
- const s = ['th', 'st', 'nd', 'rd'];
597
- const v = n % 100;
598
- return n + (s[(v - 20) % 10] || s[v] || s[0]);
599
- }
600
-
601
- /**
602
- * Removes nekudot from Hebrew string
603
- * @param {string} str
604
- * @return {string}
605
- */
606
- static hebrewStripNikkud(str) {
607
- return str.replace(/[\u0590-\u05bd]/g, '').replace(/[\u05bf-\u05c7]/g, '');
608
- }
609
- }
610
-
611
- Locale.addLocale('en', noopLocale);
612
- Locale.addLocale('s', noopLocale);
613
- Locale.addLocale('', noopLocale);
614
- Locale.useLocale('en');
615
-
616
- /*
617
- * More minimal HDate
618
- */
619
-
620
- const NISAN$1 = 1;
621
- const IYYAR = 2;
622
- // const SIVAN = 3;
623
- const TAMUZ = 4;
624
- // const AV = 5;
625
- const ELUL = 6;
626
- const TISHREI = 7;
627
- const CHESHVAN$1 = 8;
628
- const KISLEV$1 = 9;
629
- const TEVET$1 = 10;
630
- // const SHVAT = 11;
631
- const ADAR_I$1 = 12;
632
- const ADAR_II$1 = 13;
633
-
634
- /**
635
- * Hebrew months of the year (NISAN=1, TISHREI=7)
636
- * @readonly
637
- * @enum {number}
638
- */
639
- const months = {
640
- /** Nissan / ניסן */
641
- NISAN: 1,
642
- /** Iyyar / אייר */
643
- IYYAR: 2,
644
- /** Sivan / סיון */
645
- SIVAN: 3,
646
- /** Tamuz (sometimes Tammuz) / תמוז */
647
- TAMUZ: 4,
648
- /** Av / אב */
649
- AV: 5,
650
- /** Elul / אלול */
651
- ELUL: 6,
652
- /** Tishrei / תִּשְׁרֵי */
653
- TISHREI: 7,
654
- /** Cheshvan / חשון */
655
- CHESHVAN: 8,
656
- /** Kislev / כסלו */
657
- KISLEV: 9,
658
- /** Tevet / טבת */
659
- TEVET: 10,
660
- /** Sh'vat / שבט */
661
- SHVAT: 11,
662
- /** Adar or Adar Rishon / אדר */
663
- ADAR_I: 12,
664
- /** Adar Sheini (only on leap years) / אדר ב׳ */
665
- ADAR_II: 13,
666
- };
667
-
668
- const monthNames0 = [
669
- '',
670
- 'Nisan',
671
- 'Iyyar',
672
- 'Sivan',
673
- 'Tamuz',
674
- 'Av',
675
- 'Elul',
676
- 'Tishrei',
677
- 'Cheshvan',
678
- 'Kislev',
679
- 'Tevet',
680
- 'Sh\'vat',
681
- ];
682
-
683
- /**
684
- * Transliterations of Hebrew month names.
685
- * Regular years are index 0 and leap years are index 1.
686
- * @private
687
- */
688
- const monthNames = [
689
- monthNames0.concat([
690
- 'Adar',
691
- 'Nisan',
692
- ]),
693
- monthNames0.concat([
694
- 'Adar I',
695
- 'Adar II',
696
- 'Nisan',
697
- ]),
698
- ];
699
-
700
- const edCache = Object.create(null);
701
-
702
- const EPOCH = -1373428;
703
- // Avg year length in the cycle (19 solar years with 235 lunar months)
704
- const AVG_HEBYEAR_DAYS = 365.24682220597794;
705
-
706
- /**
707
- * @private
708
- * @param {any} n
709
- * @param {string} name
710
- */
711
- function assertNumber(n, name) {
712
- if (typeof n !== 'number' || isNaN(n)) {
713
- throw new TypeError(`invalid parameter '${name}' not a number: ${n}`);
714
- }
715
- }
716
-
717
- /**
718
- * Converts Hebrew date to R.D. (Rata Die) fixed days.
719
- * R.D. 1 is the imaginary date Monday, January 1, 1 on the Gregorian
720
- * Calendar.
721
- * @private
722
- * @param {number} year Hebrew year
723
- * @param {number} month Hebrew month
724
- * @param {number} day Hebrew date (1-30)
725
- * @return {number}
726
- */
727
- function hebrew2abs(year, month, day) {
728
- assertNumber(year, 'year');
729
- assertNumber(month, 'month');
730
- assertNumber(day, 'day');
731
-
732
- if (year < 1) {
733
- throw new RangeError(`hebrew2abs: invalid year ${year}`);
734
- }
735
-
736
- let tempabs = day;
737
-
738
- if (month < TISHREI) {
739
- for (let m = TISHREI; m <= monthsInYear(year); m++) {
740
- tempabs += daysInMonth(m, year);
741
- }
742
- for (let m = NISAN$1; m < month; m++) {
743
- tempabs += daysInMonth(m, year);
744
- }
745
- } else {
746
- for (let m = TISHREI; m < month; m++) {
747
- tempabs += daysInMonth(m, year);
748
- }
749
- }
750
-
751
- return EPOCH + elapsedDays(year) + tempabs - 1;
752
- }
753
-
754
- /**
755
- * @private
756
- * @param {number} year
757
- * @return {number}
758
- */
759
- function newYear(year) {
760
- return EPOCH + elapsedDays(year);
761
- }
762
-
763
- /**
764
- * Converts absolute R.D. days to Hebrew date
765
- * @private
766
- * @param {number} abs absolute R.D. days
767
- * @return {SimpleHebrewDate}
768
- */
769
- function abs2hebrew(abs) {
770
- assertNumber(abs, 'abs');
771
- abs = Math.trunc(abs);
772
- if (abs <= EPOCH) {
773
- throw new RangeError(`abs2hebrew: ${abs} is before epoch`);
774
- }
775
- // first, quickly approximate year
776
- let year = Math.floor((abs - EPOCH) / AVG_HEBYEAR_DAYS);
777
- while (newYear(year) <= abs) {
778
- ++year;
779
- }
780
- --year;
781
-
782
- let month = abs < hebrew2abs(year, 1, 1) ? 7 : 1;
783
- while (abs > hebrew2abs(year, month, daysInMonth(month, year))) {
784
- ++month;
785
- }
786
-
787
- const day = 1 + abs - hebrew2abs(year, month, 1);
788
- return {yy: year, mm: month, dd: day};
789
- }
790
-
791
- /**
792
- * Returns true if Hebrew year is a leap year
793
- * @private
794
- * @param {number} year Hebrew year
795
- * @return {boolean}
796
- */
797
- function isLeapYear(year) {
798
- return (1 + year * 7) % 19 < 7;
799
- }
800
-
801
- /**
802
- * Number of months in this Hebrew year (either 12 or 13 depending on leap year)
803
- * @private
804
- * @param {number} year Hebrew year
805
- * @return {number}
806
- */
807
- function monthsInYear(year) {
808
- return 12 + isLeapYear(year); // boolean is cast to 1 or 0
809
- }
810
-
811
- /**
812
- * Number of days in Hebrew month in a given year (29 or 30)
813
- * @private
814
- * @param {number} month Hebrew month (e.g. months.TISHREI)
815
- * @param {number} year Hebrew year
816
- * @return {number}
817
- */
818
- function daysInMonth(month, year) {
819
- switch (month) {
820
- case IYYAR:
821
- case TAMUZ:
822
- case ELUL:
823
- case TEVET$1:
824
- case ADAR_II$1:
825
- return 29;
826
- }
827
- if ((month === ADAR_I$1 && !isLeapYear(year)) ||
828
- (month === CHESHVAN$1 && !longCheshvan(year)) ||
829
- (month === KISLEV$1 && shortKislev(year))) {
830
- return 29;
831
- } else {
832
- return 30;
833
- }
834
- }
835
-
836
- /**
837
- * Returns a transliterated string name of Hebrew month in year,
838
- * for example 'Elul' or 'Cheshvan'.
839
- * @private
840
- * @param {number} month Hebrew month (e.g. months.TISHREI)
841
- * @param {number} year Hebrew year
842
- * @return {string}
843
- */
844
- function getMonthName(month, year) {
845
- assertNumber(month, 'month');
846
- assertNumber(year, 'year');
847
- if (month < 1 || month > 14) {
848
- throw new TypeError(`bad month argument ${month}`);
849
- }
850
- return monthNames[+isLeapYear(year)][month];
851
- }
852
-
853
- /**
854
- * Days from sunday prior to start of Hebrew calendar to mean
855
- * conjunction of Tishrei in Hebrew YEAR
856
- * @private
857
- * @param {number} year Hebrew year
858
- * @return {number}
859
- */
860
- function elapsedDays(year) {
861
- const elapsed = edCache[year] = edCache[year] || elapsedDays0(year);
862
- return elapsed;
863
- }
864
-
865
- /**
866
- * Days from sunday prior to start of Hebrew calendar to mean
867
- * conjunction of Tishrei in Hebrew YEAR
868
- * @private
869
- * @param {number} year Hebrew year
870
- * @return {number}
871
- */
872
- function elapsedDays0(year) {
873
- const prevYear = year - 1;
874
- const mElapsed = 235 * Math.floor(prevYear / 19) + // Months in complete 19 year lunar (Metonic) cycles so far
875
- 12 * (prevYear % 19) + // Regular months in this cycle
876
- Math.floor(((prevYear % 19) * 7 + 1) / 19); // Leap months this cycle
877
-
878
- const pElapsed = 204 + 793 * (mElapsed % 1080);
879
-
880
- const hElapsed = 5 +
881
- 12 * mElapsed +
882
- 793 * Math.floor(mElapsed / 1080) +
883
- Math.floor(pElapsed / 1080);
884
-
885
- const parts = (pElapsed % 1080) + 1080 * (hElapsed % 24);
886
-
887
- const day = 1 + 29 * mElapsed + Math.floor(hElapsed / 24);
888
- const altDay = day +
889
- (parts >= 19440 ||
890
- (2 === day % 7 && parts >= 9924 && !isLeapYear(year)) ||
891
- (1 === day % 7 && parts >= 16789 && isLeapYear(prevYear)));
892
-
893
- return altDay + (altDay % 7 === 0 || altDay % 7 === 3 || altDay % 7 === 5);
894
- }
895
-
896
- /**
897
- * Number of days in the hebrew YEAR.
898
- * A common Hebrew calendar year can have a length of 353, 354 or 355 days
899
- * A leap Hebrew calendar year can have a length of 383, 384 or 385 days
900
- * @private
901
- * @param {number} year Hebrew year
902
- * @return {number}
903
- */
904
- function daysInYear(year) {
905
- return elapsedDays(year + 1) - elapsedDays(year);
906
- }
907
-
908
- /**
909
- * true if Cheshvan is long in Hebrew year
910
- * @private
911
- * @param {number} year Hebrew year
912
- * @return {boolean}
913
- */
914
- function longCheshvan(year) {
915
- return daysInYear(year) % 10 === 5;
916
- }
917
-
918
- /**
919
- * true if Kislev is short in Hebrew year
920
- * @private
921
- * @param {number} year Hebrew year
922
- * @return {boolean}
923
- */
924
- function shortKislev(year) {
925
- return daysInYear(year) % 10 === 3;
926
- }
927
-
928
- /**
929
- * @private
930
- * @param {string} msg
931
- */
932
- function throwTypeError(msg) {
933
- throw new TypeError(msg);
934
- }
935
-
936
- /*
937
- Hebcal - A Jewish Calendar Generator
938
- Copyright (c) 1994-2020 Danny Sadinoff
939
- Portions copyright Eyal Schachter and Michael J. Radwin
940
-
941
- https://github.com/hebcal/hebcal-es6
942
-
943
- This program is free software; you can redistribute it and/or
944
- modify it under the terms of the GNU General Public License
945
- as published by the Free Software Foundation; either version 2
946
- of the License, or (at your option) any later version.
947
-
948
- This program is distributed in the hope that it will be useful,
949
- but WITHOUT ANY WARRANTY; without even the implied warranty of
950
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
951
- GNU General Public License for more details.
952
-
953
- You should have received a copy of the GNU General Public License
954
- along with this program. If not, see <http://www.gnu.org/licenses/>.
955
- */
956
-
957
- const UNITS_DAY = 'day';
958
- const UNITS_WEEK = 'week';
959
- const UNITS_MONTH = 'month';
960
- const UNITS_YEAR = 'year';
961
- const UNITS_SINGLE = {d: UNITS_DAY, w: UNITS_WEEK, M: UNITS_MONTH, y: UNITS_YEAR};
962
- const UNITS_VALID = {day: UNITS_DAY, week: UNITS_WEEK, month: UNITS_MONTH, year: UNITS_YEAR};
963
-
964
- /**
965
- * A simple Hebrew date object with numeric fields `yy`, `mm`, and `dd`
966
- * @typedef {Object} SimpleHebrewDate
967
- * @property {number} yy Hebrew year
968
- * @property {number} mm Hebrew month of year (1=NISAN, 7=TISHREI)
969
- * @property {number} dd Day of month (1-30)
970
- * @private
971
- */
972
-
973
- /** Represents a Hebrew date */
974
- class HDate {
975
- /**
976
- * Create a Hebrew date. There are 3 basic forms for the `HDate()` constructor.
977
- *
978
- * 1. No parameters - represents the current Hebrew date at time of instantiation
979
- * 2. One parameter
980
- * * `Date` - represents the Hebrew date corresponding to the Gregorian date using
981
- * local time. Hours, minutes, seconds and milliseconds are ignored.
982
- * * `HDate` - clones a copy of the given Hebrew date
983
- * * `number` - Converts absolute R.D. days to Hebrew date.
984
- * R.D. 1 == the imaginary date January 1, 1 (Gregorian)
985
- * 3. Three parameters: Hebrew day, Hebrew month, Hebrew year. Hebrew day should
986
- * be a number between 1-30, Hebrew month can be a number or string, and
987
- * Hebrew year is always a number.
988
- * @example
989
- * import {HDate, months} from '@hebcal/core';
990
- *
991
- * const hd1 = new HDate();
992
- * const hd2 = new HDate(new Date(2008, 10, 13));
993
- * const hd3 = new HDate(15, 'Cheshvan', 5769);
994
- * const hd4 = new HDate(15, months.CHESHVAN, 5769);
995
- * const hd5 = new HDate(733359); // ==> 15 Cheshvan 5769
996
- * const monthName = 'אייר';
997
- * const hd6 = new HDate(5, monthName, 5773);
998
- * @param {number|Date|HDate} [day] - Day of month (1-30) if a `number`.
999
- * If a `Date` is specified, represents the Hebrew date corresponding to the
1000
- * Gregorian date using local time.
1001
- * If an `HDate` is specified, clones a copy of the given Hebrew date.
1002
- * @param {number|string} [month] - Hebrew month of year (1=NISAN, 7=TISHREI)
1003
- * @param {number} [year] - Hebrew year
1004
- */
1005
- constructor(day, month, year) {
1006
- if (arguments.length == 2 || arguments.length > 3) {
1007
- throw new TypeError('HDate constructor requires 0, 1 or 3 arguments');
1008
- }
1009
- if (arguments.length == 3) {
1010
- // Hebrew day, Hebrew month, Hebrew year
1011
- /**
1012
- * @private
1013
- * @type {number}
1014
- */
1015
- this.day = this.month = 1;
1016
- /**
1017
- * @private
1018
- * @type {number}
1019
- */
1020
- year = parseInt(year, 10);
1021
- if (isNaN(year)) {
1022
- throw new TypeError(`HDate called with bad year argument: ${year}`);
1023
- }
1024
- this.year = year;
1025
- this.setMonth(month); // will throw if we can't parse
1026
- day = parseInt(day, 10);
1027
- if (isNaN(day)) {
1028
- throw new TypeError(`HDate called with bad day argument: ${day}`);
1029
- }
1030
- this.setDate(day);
1031
- } else {
1032
- // 0 arguments
1033
- if (typeof day === 'undefined') {
1034
- day = new Date();
1035
- }
1036
- // 1 argument
1037
- const abs0 = (typeof day === 'number' && !isNaN(day)) ? day :
1038
- isDate(day) ? greg2abs(day) :
1039
- HDate.isHDate(day) ? {dd: day.day, mm: day.month, yy: day.year} :
1040
- throwTypeError(`HDate called with bad argument: ${day}`);
1041
- const isNumber = typeof abs0 === 'number';
1042
- const d = isNumber ? abs2hebrew(abs0) : abs0;
1043
- /**
1044
- * @private
1045
- * @type {number}
1046
- */
1047
- this.day = d.dd;
1048
- /**
1049
- * @private
1050
- * @type {number}
1051
- */
1052
- this.month = d.mm;
1053
- /**
1054
- * @private
1055
- * @type {number}
1056
- */
1057
- this.year = d.yy;
1058
- if (isNumber) {
1059
- /**
1060
- * @private
1061
- * @type {number}
1062
- */
1063
- this.abs0 = abs0;
1064
- }
1065
- }
1066
- }
1067
-
1068
- /**
1069
- * Gets the Hebrew year of this Hebrew date
1070
- * @return {number}
1071
- */
1072
- getFullYear() {
1073
- return this.year;
1074
- }
1075
-
1076
- /**
1077
- * Tests if this date occurs during a leap year
1078
- * @return {boolean}
1079
- */
1080
- isLeapYear() {
1081
- return isLeapYear(this.year);
1082
- }
1083
-
1084
- /**
1085
- * Gets the Hebrew month (1=NISAN, 7=TISHREI) of this Hebrew date
1086
- * @return {number}
1087
- */
1088
- getMonth() {
1089
- return this.month;
1090
- }
1091
-
1092
- /**
1093
- * The Tishrei-based month of the date. 1 is Tishrei, 7 is Nisan, 13 is Elul in a leap year
1094
- * @return {number}
1095
- */
1096
- getTishreiMonth() {
1097
- const nummonths = monthsInYear(this.getFullYear());
1098
- return (this.getMonth() + nummonths - 6) % nummonths || nummonths;
1099
- }
1100
-
1101
- /**
1102
- * Number of days in the month of this Hebrew date
1103
- * @return {number}
1104
- */
1105
- daysInMonth() {
1106
- return daysInMonth(this.getMonth(), this.getFullYear());
1107
- }
1108
-
1109
- /**
1110
- * Gets the day within the month (1-30)
1111
- * @return {number}
1112
- */
1113
- getDate() {
1114
- return this.day;
1115
- }
1116
-
1117
- /**
1118
- * Gets the day of the week. 0=Sunday, 6=Saturday
1119
- * @return {number}
1120
- */
1121
- getDay() {
1122
- return mod(this.abs(), 7);
1123
- }
1124
-
1125
- /**
1126
- * Sets the year of the date. Returns the object it was called upon.
1127
- * @private
1128
- * @deprecated
1129
- * @param {number} year
1130
- * @return {HDate}
1131
- */
1132
- setFullYear(year) {
1133
- this.year = year;
1134
- fix(this);
1135
- return this;
1136
- }
1137
-
1138
- /**
1139
- * Sets the day of the month of the date. Returns the object it was called upon
1140
- * @private
1141
- * @param {number|string} month A number, or Hebrew month name string
1142
- * @return {HDate}
1143
- */
1144
- setMonth(month) {
1145
- this.month = HDate.monthNum(month);
1146
- fix(this);
1147
- return this;
1148
- }
1149
-
1150
- /**
1151
- * @private
1152
- * @param {number} date
1153
- * @return {HDate}
1154
- */
1155
- setDate(date) {
1156
- this.day = date;
1157
- fix(this);
1158
- return this;
1159
- }
1160
-
1161
- /**
1162
- * Converts to Gregorian date
1163
- * @return {Date}
1164
- */
1165
- greg() {
1166
- return abs2greg(this.abs());
1167
- }
1168
-
1169
- /**
1170
- * Returns R.D. (Rata Die) fixed days.
1171
- * R.D. 1 == Monday, January 1, 1 (Gregorian)
1172
- * Note also that R.D. = Julian Date − 1,721,424.5
1173
- * https://en.wikipedia.org/wiki/Rata_Die#Dershowitz_and_Reingold
1174
- * @return {number}
1175
- */
1176
- abs() {
1177
- if (typeof this.abs0 !== 'number') {
1178
- this.abs0 = hebrew2abs(this.year, this.month, this.day);
1179
- }
1180
- return this.abs0;
1181
- }
1182
-
1183
- /**
1184
- * Converts Hebrew date to R.D. (Rata Die) fixed days.
1185
- * R.D. 1 is the imaginary date Monday, January 1, 1 on the Gregorian
1186
- * Calendar.
1187
- * @param {number} year Hebrew year
1188
- * @param {number} month Hebrew month
1189
- * @param {number} day Hebrew date (1-30)
1190
- * @return {number}
1191
- */
1192
- static hebrew2abs(year, month, day) {
1193
- return hebrew2abs(year, month, day);
1194
- }
1195
-
1196
- /**
1197
- * Converts absolute R.D. days to Hebrew date
1198
- * @private
1199
- * @param {number} abs absolute R.D. days
1200
- * @return {SimpleHebrewDate}
1201
- */
1202
- static abs2hebrew(abs) {
1203
- return abs2hebrew(abs);
1204
- }
1205
-
1206
- /**
1207
- * Returns a transliterated Hebrew month name, e.g. `'Elul'` or `'Cheshvan'`.
1208
- * @return {string}
1209
- */
1210
- getMonthName() {
1211
- return getMonthName(this.getMonth(), this.getFullYear());
1212
- }
1213
-
1214
- /**
1215
- * Renders this Hebrew date as a translated or transliterated string,
1216
- * including ordinal e.g. `'15th of Cheshvan, 5769'`.
1217
- * @example
1218
- * import {HDate, months} from '@hebcal/core';
1219
- *
1220
- * const hd = new HDate(15, months.CHESHVAN, 5769);
1221
- * console.log(hd.render('en')); // '15th of Cheshvan, 5769'
1222
- * console.log(hd.render('he')); // '15 חֶשְׁוָן, 5769'
1223
- * @param {string} [locale] Optional locale name (defaults to active locale).
1224
- * @param {boolean} [showYear=true] Display year (defaults to true).
1225
- * @return {string}
1226
- */
1227
- render(locale=null, showYear=true) {
1228
- const locale0 = locale || Locale.getLocaleName();
1229
- const day = this.getDate();
1230
- const monthName = Locale.gettext(this.getMonthName(), locale0);
1231
- const nth = Locale.ordinal(day, locale0);
1232
- const dayOf = HDate.getDayOfTranslation(locale0);
1233
- const dateStr = `${nth}${dayOf} ${monthName}`;
1234
- if (showYear) {
1235
- const fullYear = this.getFullYear();
1236
- return `${dateStr}, ${fullYear}`;
1237
- } else {
1238
- return dateStr;
1239
- }
1240
- }
1241
-
1242
- /**
1243
- * @private
1244
- * @param {string} locale
1245
- * @return {string}
1246
- */
1247
- static getDayOfTranslation(locale) {
1248
- switch (locale) {
1249
- case 'en':
1250
- case 's':
1251
- case 'a':
1252
- case 'ashkenazi':
1253
- return ' of';
1254
- }
1255
- const ofStr = Locale.lookupTranslation('of', locale);
1256
- if (ofStr) {
1257
- return ' ' + ofStr;
1258
- }
1259
- if (locale.startsWith('ashkenazi')) {
1260
- return ' of';
1261
- }
1262
- return '';
1263
- }
1264
-
1265
- /**
1266
- * Renders this Hebrew date in Hebrew gematriya, regardless of locale.
1267
- * @example
1268
- * import {HDate, months} from '@hebcal/core';
1269
- * const hd = new HDate(15, months.CHESHVAN, 5769);
1270
- * console.log(hd.renderGematriya()); // 'ט״ו חֶשְׁוָן תשס״ט'
1271
- * @param {boolean} [suppressNikud]
1272
- * @return {string}
1273
- */
1274
- renderGematriya(suppressNikud=false) {
1275
- const d = this.getDate();
1276
- const locale = suppressNikud ? 'he-x-NoNikud' : 'he';
1277
- const m = Locale.gettext(this.getMonthName(), locale);
1278
- const y = this.getFullYear();
1279
- return gematriya(d) + ' ' + m + ' ' + gematriya(y);
1280
- }
1281
-
1282
- /**
1283
- * Returns an `HDate` representing the a dayNumber before the current date.
1284
- * Sunday=0, Saturday=6
1285
- * @example
1286
- * new HDate(new Date('Wednesday February 19, 2014')).before(6).greg() // Sat Feb 15 2014
1287
- * @param {number} day day of week
1288
- * @return {HDate}
1289
- */
1290
- before(day) {
1291
- return onOrBefore(day, this, -1);
1292
- }
1293
-
1294
- /**
1295
- * Returns an `HDate` representing the a dayNumber on or before the current date.
1296
- * Sunday=0, Saturday=6
1297
- * @example
1298
- * new HDate(new Date('Wednesday February 19, 2014')).onOrBefore(6).greg() // Sat Feb 15 2014
1299
- * new HDate(new Date('Saturday February 22, 2014')).onOrBefore(6).greg() // Sat Feb 22 2014
1300
- * new HDate(new Date('Sunday February 23, 2014')).onOrBefore(6).greg() // Sat Feb 22 2014
1301
- * @param {number} dow day of week
1302
- * @return {HDate}
1303
- */
1304
- onOrBefore(dow) {
1305
- return onOrBefore(dow, this, 0);
1306
- }
1307
-
1308
- /**
1309
- * Returns an `HDate` representing the nearest dayNumber to the current date
1310
- * Sunday=0, Saturday=6
1311
- * @example
1312
- * new HDate(new Date('Wednesday February 19, 2014')).nearest(6).greg() // Sat Feb 22 2014
1313
- * new HDate(new Date('Tuesday February 18, 2014')).nearest(6).greg() // Sat Feb 15 2014
1314
- * @param {number} dow day of week
1315
- * @return {HDate}
1316
- */
1317
- nearest(dow) {
1318
- return onOrBefore(dow, this, 3);
1319
- }
1320
-
1321
- /**
1322
- * Returns an `HDate` representing the a dayNumber on or after the current date.
1323
- * Sunday=0, Saturday=6
1324
- * @example
1325
- * new HDate(new Date('Wednesday February 19, 2014')).onOrAfter(6).greg() // Sat Feb 22 2014
1326
- * new HDate(new Date('Saturday February 22, 2014')).onOrAfter(6).greg() // Sat Feb 22 2014
1327
- * new HDate(new Date('Sunday February 23, 2014')).onOrAfter(6).greg() // Sat Mar 01 2014
1328
- * @param {number} dow day of week
1329
- * @return {HDate}
1330
- */
1331
- onOrAfter(dow) {
1332
- return onOrBefore(dow, this, 6);
1333
- }
1334
-
1335
- /**
1336
- * Returns an `HDate` representing the a dayNumber after the current date.
1337
- * Sunday=0, Saturday=6
1338
- * @example
1339
- * new HDate(new Date('Wednesday February 19, 2014')).after(6).greg() // Sat Feb 22 2014
1340
- * new HDate(new Date('Saturday February 22, 2014')).after(6).greg() // Sat Mar 01 2014
1341
- * new HDate(new Date('Sunday February 23, 2014')).after(6).greg() // Sat Mar 01 2014
1342
- * @param {number} day day of week
1343
- * @return {HDate}
1344
- */
1345
- after(day) {
1346
- return onOrBefore(day, this, 7);
1347
- }
1348
-
1349
- /**
1350
- * Returns the next Hebrew date
1351
- * @return {HDate}
1352
- */
1353
- next() {
1354
- return new HDate(this.abs() + 1);
1355
- }
1356
-
1357
- /**
1358
- * Returns the previous Hebrew date
1359
- * @return {HDate}
1360
- */
1361
- prev() {
1362
- return new HDate(this.abs() - 1);
1363
- }
1364
-
1365
- /**
1366
- * Returns a cloned `HDate` object with a specified amount of time added
1367
- *
1368
- * Units are case insensitive, and support plural and short forms.
1369
- * Note, short forms are case sensitive.
1370
- *
1371
- * | Unit | Shorthand | Description
1372
- * | --- | --- | --- |
1373
- * | `day` | `d` | days |
1374
- * | `week` | `w` | weeks |
1375
- * | `month` | `M` | months |
1376
- * | `year` | `y` | years |
1377
- * @param {number} number
1378
- * @param {string} [units]
1379
- * @return {HDate}
1380
- */
1381
- add(number, units='d') {
1382
- number = parseInt(number, 10);
1383
- if (!number) {
1384
- return new HDate(this);
1385
- }
1386
- units = HDate.standardizeUnits(units);
1387
- if (units === UNITS_DAY) {
1388
- return new HDate(this.abs() + number);
1389
- } else if (units === UNITS_WEEK) {
1390
- return new HDate(this.abs() + (7 * number));
1391
- } else if (units === UNITS_YEAR) {
1392
- return new HDate(this.getDate(), this.getMonth(), this.getFullYear() + number);
1393
- } else if (units === UNITS_MONTH) {
1394
- let hd = new HDate(this);
1395
- const sign = number > 0 ? 1 : -1;
1396
- number = Math.abs(number);
1397
- for (let i = 0; i < number; i++) {
1398
- hd = new HDate(hd.abs() + (sign * hd.daysInMonth()));
1399
- }
1400
- return hd;
1401
- }
1402
- }
1403
-
1404
- /**
1405
- * @private
1406
- * @param {string} units
1407
- * @return {string}
1408
- */
1409
- static standardizeUnits(units) {
1410
- const full = UNITS_SINGLE[units] || String(units || '').toLowerCase().replace(/s$/, '');
1411
- return UNITS_VALID[full] || throwTypeError(`Invalid units '${units}'`);
1412
- }
1413
-
1414
- /**
1415
- * Returns a cloned `HDate` object with a specified amount of time subracted
1416
- *
1417
- * Units are case insensitive, and support plural and short forms.
1418
- * Note, short forms are case sensitive.
1419
- *
1420
- * | Unit | Shorthand | Description
1421
- * | --- | --- | --- |
1422
- * | `day` | `d` | days |
1423
- * | `week` | `w` | weeks |
1424
- * | `month` | `M` | months |
1425
- * | `year` | `y` | years |
1426
- * @example
1427
- * import {HDate, months} from '@hebcal/core';
1428
- *
1429
- * const hd1 = new HDate(15, months.CHESHVAN, 5769);
1430
- * const hd2 = hd1.add(1, 'weeks'); // 7 Kislev 5769
1431
- * const hd3 = hd1.add(-3, 'M'); // 30 Av 5768
1432
- * @param {number} number
1433
- * @param {string} [units]
1434
- * @return {HDate}
1435
- */
1436
- subtract(number, units='d') {
1437
- return this.add(number * -1, units);
1438
- }
1439
-
1440
- /**
1441
- * Returns the difference in days between the two given HDates.
1442
- *
1443
- * The result is positive if `this` date is comes chronologically
1444
- * after the `other` date, and negative
1445
- * if the order of the two dates is reversed.
1446
- *
1447
- * The result is zero if the two dates are identical.
1448
- * @example
1449
- * import {HDate, months} from '@hebcal/core';
1450
- *
1451
- * const hd1 = new HDate(25, months.KISLEV, 5770);
1452
- * const hd2 = new HDate(15, months.CHESHVAN, 5769);
1453
- * const days = hd1.deltaDays(hd2); // 394
1454
- * @param {HDate} other Hebrew date to compare
1455
- * @return {number}
1456
- */
1457
- deltaDays(other) {
1458
- if (!HDate.isHDate(other)) {
1459
- throw new TypeError(`Bad argument: ${other}`);
1460
- }
1461
- return this.abs() - other.abs();
1462
- }
1463
-
1464
- /**
1465
- * Compares this date to another date, returning `true` if the dates match.
1466
- * @param {HDate} other Hebrew date to compare
1467
- * @return {boolean}
1468
- */
1469
- isSameDate(other) {
1470
- if (HDate.isHDate(other)) {
1471
- return this.year == other.year &&
1472
- this.month == other.month &&
1473
- this.day == other.day;
1474
- }
1475
- return false;
1476
- }
1477
-
1478
- /** @return {string} */
1479
- toString() {
1480
- const day = this.getDate();
1481
- const fullYear = this.getFullYear();
1482
- const monthName = this.getMonthName();
1483
- return `${day} ${monthName} ${fullYear}`;
1484
- }
1485
-
1486
- /**
1487
- * Returns true if Hebrew year is a leap year
1488
- * @param {number} year Hebrew year
1489
- * @return {boolean}
1490
- */
1491
- static isLeapYear(year) {
1492
- return isLeapYear(year);
1493
- }
1494
-
1495
- /**
1496
- * Number of months in this Hebrew year (either 12 or 13 depending on leap year)
1497
- * @param {number} year Hebrew year
1498
- * @return {number}
1499
- */
1500
- static monthsInYear(year) {
1501
- return monthsInYear(year);
1502
- }
1503
-
1504
- /**
1505
- * Number of days in Hebrew month in a given year (29 or 30)
1506
- * @param {number} month Hebrew month (e.g. months.TISHREI)
1507
- * @param {number} year Hebrew year
1508
- * @return {number}
1509
- */
1510
- static daysInMonth(month, year) {
1511
- return daysInMonth(month, year);
1512
- }
1513
-
1514
- /**
1515
- * Returns a transliterated string name of Hebrew month in year,
1516
- * for example 'Elul' or 'Cheshvan'.
1517
- * @param {number} month Hebrew month (e.g. months.TISHREI)
1518
- * @param {number} year Hebrew year
1519
- * @return {string}
1520
- */
1521
- static getMonthName(month, year) {
1522
- return getMonthName(month, year);
1523
- }
1524
-
1525
- /**
1526
- * Returns the Hebrew month number (NISAN=1, TISHREI=7)
1527
- * @param {number|string} month A number, or Hebrew month name string
1528
- * @return {number}
1529
- */
1530
- static monthNum(month) {
1531
- if (typeof month === 'number') {
1532
- if (isNaN(month) || month > 14) {
1533
- throw new RangeError(`Invalid month number: ${month}`);
1534
- }
1535
- return month;
1536
- }
1537
- return month.charCodeAt(0) >= 48 && month.charCodeAt(0) <= 57 ? /* number */
1538
- parseInt(month, 10) :
1539
- HDate.monthFromName(month);
1540
- }
1541
-
1542
- /**
1543
- * Number of days in the hebrew YEAR
1544
- * @param {number} year Hebrew year
1545
- * @return {number}
1546
- */
1547
- static daysInYear(year) {
1548
- return daysInYear(year);
1549
- }
1550
-
1551
- /**
1552
- * true if Cheshvan is long in Hebrew year
1553
- * @param {number} year Hebrew year
1554
- * @return {boolean}
1555
- */
1556
- static longCheshvan(year) {
1557
- return longCheshvan(year);
1558
- }
1559
-
1560
- /**
1561
- * true if Kislev is short in Hebrew year
1562
- * @param {number} year Hebrew year
1563
- * @return {boolean}
1564
- */
1565
- static shortKislev(year) {
1566
- return shortKislev(year);
1567
- }
1568
-
1569
- /**
1570
- * Converts Hebrew month string name to numeric
1571
- * @param {string} monthName monthName
1572
- * @return {number}
1573
- */
1574
- static monthFromName(monthName) {
1575
- if (typeof monthName === 'number') {
1576
- if (isNaN(monthName) || monthName < 1 || monthName > 14) {
1577
- throw new RangeError(`Invalid month name: ${monthName}`);
1578
- }
1579
- return monthName;
1580
- }
1581
- let c = Locale.hebrewStripNikkud(monthName).trim().toLowerCase();
1582
- // If Hebrew month starts with a bet (for example `בתמוז`) then ignore it
1583
- if (c[0] === 'ב') {
1584
- c = c.substring(1);
1585
- }
1586
- /*
1587
- the Hebrew months are unique to their second letter
1588
- N Nisan (November?)
1589
- I Iyyar
1590
- E Elul
1591
- C Cheshvan
1592
- K Kislev
1593
- 1 1Adar
1594
- 2 2Adar
1595
- Si Sh Sivan, Shvat
1596
- Ta Ti Te Tamuz, Tishrei, Tevet
1597
- Av Ad Av, Adar
1598
-
1599
- אב אד אי אל אב אדר אייר אלול
1600
- ח חשון
1601
- ט טבת
1602
- כ כסלו
1603
- נ ניסן
1604
- ס סיון
1605
- ש שבט
1606
- תמ תש תמוז תשרי
1607
- */
1608
- switch (c[0]) {
1609
- case 'n':
1610
- case 'נ':
1611
- if (c[1] == 'o') {
1612
- break; /* this catches "november" */
1613
- }
1614
- return months.NISAN;
1615
- case 'i':
1616
- return months.IYYAR;
1617
- case 'e':
1618
- return months.ELUL;
1619
- case 'c':
1620
- case 'ח':
1621
- return months.CHESHVAN;
1622
- case 'k':
1623
- case 'כ':
1624
- return months.KISLEV;
1625
- case 's':
1626
- switch (c[1]) {
1627
- case 'i':
1628
- return months.SIVAN;
1629
- case 'h':
1630
- return months.SHVAT;
1631
- }
1632
- break;
1633
- case 't':
1634
- switch (c[1]) {
1635
- case 'a':
1636
- return months.TAMUZ;
1637
- case 'i':
1638
- return months.TISHREI;
1639
- case 'e':
1640
- return months.TEVET;
1641
- }
1642
- break;
1643
- case 'a':
1644
- switch (c[1]) {
1645
- case 'v':
1646
- return months.AV;
1647
- case 'd':
1648
- if (/(1|[^i]i|a|א)$/i.test(monthName)) {
1649
- return months.ADAR_I;
1650
- }
1651
- return months.ADAR_II; // else assume sheini
1652
- }
1653
- break;
1654
- case 'ס':
1655
- return months.SIVAN;
1656
- case 'ט':
1657
- return months.TEVET;
1658
- case 'ש':
1659
- return months.SHVAT;
1660
- case 'א':
1661
- switch (c[1]) {
1662
- case 'ב':
1663
- return months.AV;
1664
- case 'ד':
1665
- if (/(1|[^i]i|a|א)$/i.test(monthName)) {
1666
- return months.ADAR_I;
1667
- }
1668
- return months.ADAR_II; // else assume sheini
1669
- case 'י':
1670
- return months.IYYAR;
1671
- case 'ל':
1672
- return months.ELUL;
1673
- }
1674
- break;
1675
- case 'ת':
1676
- switch (c[1]) {
1677
- case 'מ':
1678
- return months.TAMUZ;
1679
- case 'ש':
1680
- return months.TISHREI;
1681
- }
1682
- break;
1683
- }
1684
- throw new RangeError(`Unable to parse month name: ${monthName}`);
1685
- }
1686
-
1687
- /**
1688
- * Note: Applying this function to d+6 gives us the DAYNAME on or after an
1689
- * absolute day d. Similarly, applying it to d+3 gives the DAYNAME nearest to
1690
- * absolute date d, applying it to d-1 gives the DAYNAME previous to absolute
1691
- * date d, and applying it to d+7 gives the DAYNAME following absolute date d.
1692
- * @param {number} dayOfWeek
1693
- * @param {number} absdate
1694
- * @return {number}
1695
- */
1696
- static dayOnOrBefore(dayOfWeek, absdate) {
1697
- return absdate - ((absdate - dayOfWeek) % 7);
1698
- }
1699
-
1700
- /**
1701
- * Tests if the object is an instance of `HDate`
1702
- * @param {any} obj
1703
- * @return {boolean}
1704
- */
1705
- static isHDate(obj) {
1706
- return obj !== null && typeof obj === 'object' &&
1707
- typeof obj.year === 'number' &&
1708
- typeof obj.month === 'number' &&
1709
- typeof obj.day === 'number' &&
1710
- typeof obj.greg === 'function' &&
1711
- typeof obj.abs === 'function';
1712
- }
1713
-
1714
- /**
1715
- * Construct a new instance of `HDate` from a Gematriya-formatted string
1716
- * @example
1717
- * HDate.fromGematriyaString('כ״ז בְּתַמּוּז תשפ״ג') // 27 Tamuz 5783
1718
- * HDate.fromGematriyaString('כ׳ סיון תש״ד') // 20 Sivan 5704
1719
- * HDate.fromGematriyaString('ה׳ אִיָיר תש״ח') // 5 Iyyar 5708
1720
- * @param {string} str
1721
- * @param {number} currentThousands
1722
- * @return {HDate}
1723
- */
1724
- static fromGematriyaString(str, currentThousands=5000) {
1725
- const parts = str.split(' ');
1726
- const day = gematriyaStrToNum(parts[0]);
1727
- const month = HDate.monthFromName(parts[1]);
1728
- let year = gematriyaStrToNum(parts[2]);
1729
- if (year < 1000) {
1730
- year += currentThousands;
1731
- }
1732
- return new HDate(day, month, year);
1733
- }
1734
- }
1735
-
1736
- /**
1737
- * @private
1738
- * @param {HDate} date
1739
- */
1740
- function fix(date) {
1741
- fixMonth(date);
1742
- fixDate(date);
1743
- }
1744
-
1745
- /**
1746
- * @private
1747
- * @param {HDate} date
1748
- */
1749
- function fixDate(date) {
1750
- if (date.day < 1) {
1751
- if (date.month == months.TISHREI) {
1752
- date.year -= 1;
1753
- }
1754
- date.day += daysInMonth(date.month, date.year);
1755
- date.month -= 1;
1756
- fix(date);
1757
- }
1758
- if (date.day > daysInMonth(date.month, date.year)) {
1759
- if (date.month === months.ELUL) {
1760
- date.year += 1;
1761
- }
1762
- date.day -= daysInMonth(date.month, date.year);
1763
- date.month += 1;
1764
- fix(date);
1765
- }
1766
- fixMonth(date);
1767
- }
1768
-
1769
- /**
1770
- * @private
1771
- * @param {HDate} date
1772
- */
1773
- function fixMonth(date) {
1774
- if (date.month === months.ADAR_II && !date.isLeapYear()) {
1775
- date.month -= 1; // to Adar I
1776
- fix(date);
1777
- } else if (date.month < 1) {
1778
- date.month += monthsInYear(date.year);
1779
- date.year -= 1;
1780
- fix(date);
1781
- } else if (date.month > monthsInYear(date.year)) {
1782
- date.month -= monthsInYear(date.year);
1783
- date.year += 1;
1784
- fix(date);
1785
- }
1786
- delete date.abs0;
1787
- }
1788
-
1789
- /**
1790
- * @private
1791
- * @param {number} day
1792
- * @param {HDate} t
1793
- * @param {number} offset
1794
- * @return {HDate}
1795
- */
1796
- function onOrBefore(day, t, offset) {
1797
- return new HDate(HDate.dayOnOrBefore(day, t.abs() + offset));
1798
- }
1799
-
1800
- const NISAN = months.NISAN;
1801
- const CHESHVAN = months.CHESHVAN;
1802
- const KISLEV = months.KISLEV;
1803
- const TEVET = months.TEVET;
1804
- const SHVAT = months.SHVAT;
1805
- const ADAR_I = months.ADAR_I;
1806
- const ADAR_II = months.ADAR_II;
1807
-
1808
- /**
1809
- * @private
1810
- * @param {number} hyear Hebrew year
1811
- * @param {Date|HDate} gdate Gregorian or Hebrew date of death
1812
- * @return {HDate} anniversary occurring in hyear
1813
- */
1814
- function getYahrzeit_(hyear, gdate) {
1815
- const orig = HDate.isHDate(gdate) ? gdate : new HDate(gdate);
1816
- let hDeath = {
1817
- yy: orig.getFullYear(),
1818
- mm: orig.getMonth(),
1819
- dd: orig.getDate(),
1820
- };
1821
- if (hyear <= hDeath.yy) {
1822
- // `Hebrew year ${hyear} occurs on or before original date in ${hDeath.yy}`
1823
- return undefined;
1824
- }
1825
-
1826
- if (hDeath.mm == CHESHVAN && hDeath.dd == 30 && !longCheshvan(hDeath.yy + 1)) {
1827
- // If it's Heshvan 30 it depends on the first anniversary;
1828
- // if that was not Heshvan 30, use the day before Kislev 1.
1829
- hDeath = abs2hebrew(hebrew2abs(hyear, KISLEV, 1) - 1);
1830
- } else if (hDeath.mm == KISLEV && hDeath.dd == 30 && shortKislev(hDeath.yy + 1)) {
1831
- // If it's Kislev 30 it depends on the first anniversary;
1832
- // if that was not Kislev 30, use the day before Teveth 1.
1833
- hDeath = abs2hebrew(hebrew2abs(hyear, TEVET, 1) - 1);
1834
- } else if (hDeath.mm == ADAR_II) {
1835
- // If it's Adar II, use the same day in last month of year (Adar or Adar II).
1836
- hDeath.mm = monthsInYear(hyear);
1837
- } else if (hDeath.mm == ADAR_I && hDeath.dd == 30 && !isLeapYear(hyear)) {
1838
- // If it's the 30th in Adar I and year is not a leap year
1839
- // (so Adar has only 29 days), use the last day in Shevat.
1840
- hDeath.dd = 30;
1841
- hDeath.mm = SHVAT;
1842
- }
1843
- // In all other cases, use the normal anniversary of the date of death.
1844
-
1845
- // advance day to rosh chodesh if needed
1846
- if (hDeath.mm == CHESHVAN && hDeath.dd == 30 && !longCheshvan(hyear)) {
1847
- hDeath.mm = KISLEV;
1848
- hDeath.dd = 1;
1849
- } else if (hDeath.mm == KISLEV && hDeath.dd == 30 && shortKislev(hyear)) {
1850
- hDeath.mm = TEVET;
1851
- hDeath.dd = 1;
1852
- }
1853
-
1854
- return new HDate(hDeath.dd, hDeath.mm, hyear);
1855
- }
1856
-
1857
- /**
1858
- * @private
1859
- * @param {number} hyear Hebrew year
1860
- * @param {Date|HDate} gdate Gregorian or Hebrew date of event
1861
- * @return {HDate} anniversary occurring in `hyear`
1862
- */
1863
- function getBirthdayOrAnniversary_(hyear, gdate) {
1864
- const orig = HDate.isHDate(gdate) ? gdate : new HDate(gdate);
1865
- const origYear = orig.getFullYear();
1866
- if (hyear === origYear) {
1867
- return orig;
1868
- } else if (hyear < origYear) {
1869
- // `Hebrew year ${hyear} occurs on or before original date in ${origYear}`
1870
- return undefined;
1871
- }
1872
- const isOrigLeap = isLeapYear(origYear);
1873
- let month = orig.getMonth();
1874
- let day = orig.getDate();
1875
-
1876
- if ((month == ADAR_I && !isOrigLeap) || (month == ADAR_II && isOrigLeap)) {
1877
- month = monthsInYear(hyear);
1878
- } else if (month == CHESHVAN && day == 30 && !longCheshvan(hyear)) {
1879
- month = KISLEV;
1880
- day = 1;
1881
- } else if (month == KISLEV && day == 30 && shortKislev(hyear)) {
1882
- month = TEVET;
1883
- day = 1;
1884
- } else if (month == ADAR_I && day == 30 && isOrigLeap && !isLeapYear(hyear)) {
1885
- month = NISAN;
1886
- day = 1;
1887
- }
1888
-
1889
- return new HDate(day, month, hyear);
1890
- }
1891
-
1892
- const version="4.5.1";
1893
-
1894
- const headers={"plural-forms":"nplurals=2; plural=(n > 1);"};const contexts={"":{Adar:["אַדָר"],"Adar I":["אַדָר א׳"],"Adar II":["אַדָר ב׳"],Av:["אָב"],Cheshvan:["חֶשְׁוָן"],Elul:["אֱלוּל"],Iyyar:["אִיָיר"],Kislev:["כִּסְלֵו"],Nisan:["נִיסָן"],"Sh'vat":["שְׁבָט"],Sivan:["סִיוָן"],Tamuz:["תַּמּוּז"],Tevet:["טֵבֵת"],Tishrei:["תִּשְׁרֵי"]}};var poHeMin = {headers:headers,contexts:contexts};
1895
-
1896
- Locale.addLocale('he', poHeMin);
1897
- Locale.addLocale('h', poHeMin);
1898
-
1899
- const heStrs = poHeMin.contexts[''];
1900
- const heNoNikud = {};
1901
- Object.keys(heStrs).forEach((key) => {
1902
- heNoNikud[key] = [Locale.hebrewStripNikkud(heStrs[key][0])];
1903
- });
1904
- Locale.addLocale('he-x-NoNikud', {
1905
- headers: poHeMin.headers,
1906
- contexts: {'': heNoNikud},
1907
- });
1908
-
1909
- export { HDate, Locale, gematriya, getBirthdayOrAnniversary_ as getBirthdayOrAnniversary, getYahrzeit_ as getYahrzeit, greg, months, version };