parse-hebrew-date
v0.2.0
Published
Parse messy real-world Hebrew date strings — transliterated ("Chof Gimmel Shvat"), Rosh Chodesh shorthand, noisy free text — into structured day/month/year components.
Downloads
410
Maintainers
Readme
parse-hebrew-date
Turn the messy Hebrew dates people actually type — "Chof Gimmel Shvat", "ר״ח אדר", "Chof Hey Nissan (Isru Chag Pesach) ~ April 21" — into structured day / month / year components.
npm install parse-hebrew-dateMIT, and no runtime dependencies.
import { parseHebrewDate } from 'parse-hebrew-date';
parseHebrewDate('Chof Gimmel Shvat');
// { day: 23, month: 'Shvat', input: 'Chof Gimmel Shvat', strategy: 'transliterated' }
parseHebrewDate('כ״ג בשבט תשפ״ג');
// { day: 23, month: 'Shvat', year: 5783, input: 'כ״ג בשבט תשפ״ג', strategy: 'gematriya' }
parseHebrewDate('not a date');
// nullWhy this exists
Hebrew dates in real datasets — genealogy sheets, shul yahrzeit lists, family calendars — are rarely clean Hebrew script. They are phonetic English typed by whoever kept the list, mixed with abbreviations, parenthetical notes and a Gregorian date stapled on with a tilde.
Libraries like @hebcal/core handle everything downstream of a clean date — conversion, holidays, candle-lighting — and handle it far better than this package ever would. What is missing is the layer underneath: turning what somebody actually typed into a date at all.
| Layer | Handled |
| --- | --- |
| "כ״ג בשבט תשפ״ג" — clean gematria, nikud, implied thousands digit | ✅ |
| "Chof Gimmel Shvat" — transliterated phonetic English | ✅ |
| "ר״ח אדר" / "Rosh Chodesh Nissan" — Rosh Chodesh shorthand | ✅ |
| "מנחם אב", "Adar Sheini" — compound and qualified month names | ✅ |
| "… (Isru Chag Pesach) ~ April 21" — notes, separators, stray years | ✅ |
| Gregorian conversion, holidays, zmanim | ❌ — use @hebcal/core |
The output is deliberately plain data, not a date object. Feed it to @hebcal/core or anything else once you know which Hebrew year you are projecting it onto.
What it parses
| Input | Output |
| --- | --- |
| Chof Gimmel Shvat | 23 Shvat |
| Tes Vov Shvat | 15 Shvat |
| Chai Elul | 18 Elul |
| Yud Beis Menachem Av | 12 Av |
| Alef Adar Sheini | 1 Adar II |
| 23 Shvat / 15th Shvat | 23 Shvat / 15 Shvat |
| כ״ג בשבט תשפ״ג | 23 Shvat 5783 |
| כ״ז בְּתַמּוּז תשע״ג | 27 Tamuz 5773 |
| כ"ג בשבט תשפ"ג (ASCII quotes) | 23 Shvat 5783 |
| ט״ו בשבט | 15 Shvat |
| חי אלול | 18 Elul |
| ה׳ מנחם אב תשנ״ח | 5 Av 5758 |
| ר״ח אדר | 1 Adar |
| ר״ח אדר ב | 1 Adar II |
| Rosh Chodesh Nissan | 1 Nisan |
| Chof Hey Nissan (Isru Chag Pesach) | 25 Nisan, note Isru Chag Pesach |
| Chof Gimmel Shvat 5758 | 23 Shvat 5758 |
| ח' שבט ~ January 23 | 8 Shvat |
| January 23 ~ ח' שבט | 8 Shvat |
| garbage | null |
Handled along the way: mixed case, hyphenated numerals, nikud, geresh/gershayim typed as ASCII ' and ", the ב prefix on a month name, the many spellings of one month (Shvat / Shevat / Shevet, Cheshvan / Heshvan / Marcheshvan), extra whitespace, and the backslash-escaped \~ that CSV exports leave behind.
API
parseHebrewDate(input: string): HebrewDateParts | null
Returns null for anything it cannot read. It never throws, including on null, undefined or a non-string — safe to map straight over a spreadsheet column.
parseHebrewDateOrThrow(input: string): HebrewDateParts
The same, but throws HebrewDateParseError (which carries the offending .input) instead of returning null.
HebrewDateParts
interface HebrewDateParts {
day: number; // 1–30
month: HebrewMonthName; // canonical name
year?: number; // Hebrew year, only when the input carried one
note?: string; // text found in parentheses
input: string; // the original string, untouched
strategy: ParseStrategy; // which layer read it
}strategy is 'gematriya' (delegated to @hebcal/hdate), 'hebrew-script', 'transliterated' or 'rosh-chodesh'. It is useful for triaging an import: a column that comes back entirely 'gematriya' is clean data, one full of 'transliterated' is not.
HEBREW_MONTHS
The fourteen canonical month names, in calendar order from Tishrei:
Tishrei, Cheshvan, Kislev, Tevet, Shvat, Adar, Adar I, Adar II, Nisan, Iyyar, Sivan, Tamuz, Av, Elul.
Notes on behaviour
- Adar. An unqualified Adar stays
'Adar'unless the input also carries a Hebrew year, in which case it becomes'Adar II'in a leap year — the Adar that Purim falls in — and'Adar'otherwise. Named outright,'Adar I'/'Adar II'are always honoured as written, in either spelling (אדר א/אדר ראשון,Adar Sheini), and in a common year too. - Years. Only Hebrew years are reported. A plain-digit year is read in the range 5700–5999; a Hebrew-script year in 5400–5999 (1640–2239 CE). A trailing Gregorian year is dropped rather than reported.
- Days are validated. A day outside 1–30 makes the whole parse fail rather than returning an impossible date.
- No calendar maths. This package extracts components. It does not convert to Gregorian, resolve a recurrence, or tell you whether 30 Cheshvan exists in a given year — use
@hebcal/corefor that. A date that cannot exist comes back exactly as written:ל׳ אלול תשפ״גparses to30 Elul 5783rather than being silently rolled forward to1 Tishrei 5784. Validating against a real calendar is the caller's job, and needs to stay visible.
Requirements
Node >= 20, and nothing else — zero runtime dependencies. Ships ESM and CommonJS builds with TypeScript declarations for both.
Versions up to and including 0.1.1 depended on @hebcal/hdate for gematria and clean-date parsing. That library is GPL-2.0, which put a copyleft obligation on everyone installing this MIT package, so those few primitives — a gematria table, the Metonic leap-year rule, and a strict clean-date reader — are implemented directly in src/gematria.ts as of 0.2.0. See the changelog; the rewrite also fixed four dating bugs.
Credit
The shape of this package, and the decision to keep it separate from the calendar libraries, both owe a lot to hebcal by Michael J. Radwin and contributors — still the right tool for everything downstream of this one.
License
MIT © 2026 Shmuel Holzman.
Maintained by Holzman AI & Automations. Extracted from Luach, a family Hebrew-calendar app, where it was written to survive a real family spreadsheet.
