@coreify/tarikh 1.0.1 → 1.1.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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Coreify
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Coreify
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -4,37 +4,55 @@
4
4
  [![downloads](https://img.shields.io/npm/dm/@coreify/tarikh)](https://www.npmjs.com/package/@coreify/tarikh)
5
5
  [![license](https://img.shields.io/npm/l/@coreify/tarikh)](https://github.com/coreify/tarikh/blob/main/package/LICENSE)
6
6
 
7
- The first JavaScript date library with full Bangla calendar support.
8
-
9
- Built for Bangla dates, Bengali calendar conversion, and culturally correct formatting.
7
+ > The first JavaScript date library with Bangla and Hijri calendar support.
8
+ > Built for Bangla dates, Bengali calendar conversion, and culturally correct formatting.
9
+
10
+ | Main export | What it does |
11
+ | --------------------------------- | -------------------------------------------------------- |
12
+ | `format()` | Standard, Bangla, Hijri, and hybrid date formatting |
13
+ | `toBanglaCalendar()` | Convert Gregorian dates into the Bangla calendar |
14
+ | `toHijriCalendar()` | Convert Gregorian dates into the Hijri calendar |
15
+ | `setDefaults()` / `getDefaults()` | Configure reusable package-wide defaults |
16
+ | `parseDateDetailed()` | Parse with structured success/failure metadata |
17
+ | `fromNow()` | Render relative time like today, yesterday, and tomorrow |
18
+ | `HIJRI_TIME_ZONES` | Canonical supported Hijri time zones |
10
19
 
11
20
  ## At a Glance
12
21
 
22
+ | Snapshot | Example |
23
+ | -------------------- | ----------------------------------------------------------------------------- |
24
+ | Bangla spoken format | `format("2026-04-14", { mode: "bangla", locale: "bn-BD", format: "spoken" })` |
25
+ | Rendered output | `পহেলা বৈশাখ ১৪৩৩ বঙ্গাব্দ` |
26
+
13
27
  ```ts
14
28
  format("2026-04-14", {
15
29
  mode: "bangla",
16
30
  locale: "bn-BD",
17
31
  format: "spoken"
18
32
  });
19
- // → "পহেলা বৈশাখ ১৪৩৩"
33
+ // → "পহেলা বৈশাখ ১৪৩৩ বঙ্গাব্দ"
20
34
  ```
21
35
 
22
36
  ## Demo
23
37
 
24
- External demo: [tarikh.js.org](https://tarikh.js.org)
38
+ | Demo | Link |
39
+ | --------- | -------------------------------------- |
40
+ | Live demo | [tarikh.js.org](https://tarikh.js.org) |
25
41
 
26
42
  ## Why this exists
27
43
 
28
- JavaScript's `Intl.DateTimeFormat` and libraries like Day.js / date-fns don't solve these problems:
29
-
30
- - **Bangla calendar** Convert Gregorian dates to Bengali calendar (বৈশাখ, চৈত্র, etc.)
31
- - **Bangla digits** Render `৩১ মার্চ ২০২৬` instead of `31 March 2026`
32
- - **Hybrid formatting** Mix English and Bangla in a single date string
33
- - **Weekday and time formatting** Render weekday, hour, minute, and second output
34
- - **Natural relative time** Use `yesterday`, `tomorrow`, `গতকাল`, `আগামীকাল`, etc.
35
- - **Cultural correctness** Bangladeshi locale-aware formatting out of the box
44
+ | Why this exists | Summary |
45
+ | -------------------- | -------------------------------------------------------------------------- |
46
+ | Bangla calendar | Convert Gregorian dates to Bengali calendar values like বৈশাখ and চৈত্র |
47
+ | Hijri calendar | Render Islamic calendar dates alongside Bangla and Gregorian output |
48
+ | Bangla digits | Render `৩১শে মার্চ ২০২৬ খ্রিস্টাব্দ` instead of `31st March 2026` |
49
+ | Hybrid formatting | Mix English and Bangla in a single date string |
50
+ | Weekday/time | Render weekday, hour, minute, and second output |
51
+ | Relative time | Use `yesterday`, `tomorrow`, `গতকাল`, `আগামীকাল`, etc. |
52
+ | Global defaults | Reuse locale, mode, month, Hijri timezone, and Hijri backend across an app |
53
+ | Cultural correctness | Bangladeshi locale-aware formatting out of the box |
36
54
 
37
- `@coreify/tarikh` is a zero-dependency, tree-shakeable, SSR-safe toolkit purpose-built for Bangladesh.
55
+ > `@coreify/tarikh` is a zero-dependency, tree-shakeable, SSR-safe toolkit purpose-built for Bangladesh.
38
56
 
39
57
  ## Installation
40
58
 
@@ -46,20 +64,44 @@ npm install @coreify/tarikh
46
64
 
47
65
  ```ts
48
66
  import {
67
+ HIJRI_TIME_ZONES,
49
68
  format,
50
69
  fromNow,
51
- toBanglaCalendar
70
+ getDefaults,
71
+ parseDateDetailed,
72
+ setDefaults,
73
+ toBanglaCalendar,
74
+ toHijriCalendar
52
75
  } from "@coreify/tarikh";
53
76
 
77
+ const [defaultHijriZone, utcHijriZone] = HIJRI_TIME_ZONES;
78
+
54
79
  // Preferred entry points:
55
- format(new Date(), { mode: "standard" });
56
- format(new Date(), { mode: "bangla" });
57
- format(new Date(), { mode: "hybrid" });
80
+ format("2026-03-31", { mode: "standard" });
81
+ format("2026-03-31", { mode: "bangla" });
82
+ format("2026-03-31", { mode: "hijri" });
83
+ format("2026-03-31", { mode: "hybrid" });
84
+
85
+ setDefaults({ locale: "bn-BD", mode: "standard", month: "long" });
86
+ getDefaults();
87
+ // → { locale: "bn-BD", mode: "standard", month: "long", timeZone: "Asia/Dhaka", hijriSystem: "islamic-umalqura" }
58
88
 
59
89
  // Token-based output still works.
60
- format(new Date(), { pattern: "DD MMM YYYY" });
90
+ format("2026-03-31", { pattern: "DD MMM YYYY" });
61
91
  // → "31 Mar 2026"
62
92
 
93
+ format(new Date(2026, 2, 31, 15, 4, 9), {
94
+ mode: "standard",
95
+ preset: "dateTime"
96
+ });
97
+ // → "31st Mar 2026, 15:04"
98
+
99
+ format(new Date(2026, 2, 31, 15, 4, 9), {
100
+ mode: "standard",
101
+ preset: "isoLike"
102
+ });
103
+ // → "2026-03-31 15:04:09"
104
+
63
105
  // Structured Bangla calendar conversion
64
106
  // `monthIndex` stays numeric; `bn-BD` localizes `day`, `month`, and `year`.
65
107
  toBanglaCalendar("2026-03-31");
@@ -68,22 +110,64 @@ toBanglaCalendar("2026-03-31");
68
110
  toBanglaCalendar("2026-03-31", { locale: "bn-BD" });
69
111
  // → { day: "১৭", month: "চৈত্র", monthIndex: 12, year: "১৪৩২" }
70
112
 
113
+ const dynamicLocale: "en-BD" | "bn-BD" =
114
+ Math.random() > 0.5 ? "en-BD" : "bn-BD";
115
+ const structuredBangla = toBanglaCalendar("2026-03-31", {
116
+ locale: dynamicLocale
117
+ });
118
+ // → BanglaCalendarResult<"en-BD" | "bn-BD">
119
+
120
+ const locale: "en-BD" | "bn-BD" = Math.random() > 0.5 ? "en-BD" : "bn-BD";
121
+ const structuredBangla = toBanglaCalendar("2026-03-31", { locale });
122
+ // → TypeScript infers BanglaCalendarResult<"en-BD" | "bn-BD">
123
+
71
124
  format("2026-03-31", { mode: "bangla" });
72
- // → "17 Chaitra 1432"
125
+ // → "17th Chaitra 1432"
73
126
 
74
127
  format("2026-03-31", { mode: "bangla", locale: "bn-BD" });
75
- // → "১৭ই চৈত্র ১৪৩২"
128
+ // → "১৭ই চৈত্র ১৪৩২ বঙ্গাব্দ"
76
129
 
77
130
  format("2026-04-14", { mode: "bangla", locale: "bn-BD" });
78
131
  // → "১লা বৈশাখ ১৪৩৩"
79
132
 
133
+ toHijriCalendar("2026-03-31");
134
+ // → { day: 11, month: "Shawwal", monthIndex: 10, year: 1447 }
135
+
136
+ toHijriCalendar("2026-03-31", { locale: "bn-BD" });
137
+ // → { day: "১১", month: "শাওয়াল", monthIndex: 10, year: "১৪৪৭" }
138
+
139
+ const structuredHijri = toHijriCalendar("2026-03-31", {
140
+ locale: dynamicLocale
141
+ });
142
+ // → HijriCalendarResult<"en-BD" | "bn-BD">
143
+
144
+ const structuredHijri = toHijriCalendar("2026-03-31", { locale });
145
+ // → TypeScript infers HijriCalendarResult<"en-BD" | "bn-BD">
146
+
147
+ toHijriCalendar("2026-03-31", { timeZone: "UTC" });
148
+ // → { day: 11, month: "Shawwal", monthIndex: 10, year: 1447 }
149
+
150
+ format("2026-03-31", { mode: "hijri" });
151
+ // → "12th Shawwal 1447 AH"
152
+
153
+ format("2026-03-31", { mode: "hijri", timeZone: "UTC" });
154
+ // → "11th Shawwal 1447 AH"
155
+
156
+ | Timezone support | Details |
157
+ | ---------------- | ------- |
158
+ | `timeZone` | Accepts `Asia/Dhaka` and `UTC` |
159
+ | Supported list | Exported as `HIJRI_TIME_ZONES` |
160
+
161
+ format("2026-03-31", { mode: "hijri", locale: "bn-BD" });
162
+ // → "১২ই শাওয়াল ১৪৪৭ হিজরি"
163
+
80
164
  format(new Date(2026, 2, 31, 15, 4), {
81
165
  mode: "standard",
82
166
  weekday: "short",
83
167
  hour: "numeric",
84
168
  minute: "2-digit"
85
169
  });
86
- // → "Tue, 31 Mar 2026, 15:04"
170
+ // → "Tue, 31st Mar 2026, 15:04"
87
171
 
88
172
  format(new Date(2026, 2, 31, 21, 4, 9), {
89
173
  mode: "standard",
@@ -93,21 +177,30 @@ format(new Date(2026, 2, 31, 21, 4, 9), {
93
177
  second: "2-digit",
94
178
  hour12: true
95
179
  });
96
- // → "Tuesday, 31 Mar 2026, 09:04:09 PM"
180
+ // → "Tuesday, 31st Mar 2026, 09:04:09 PM"
97
181
 
98
182
  fromNow(new Date(Date.now() - 86400000), { numeric: "auto" });
99
- // "yesterday"
183
+ // Output depends on the current clock.
100
184
 
101
185
  fromNow(new Date(), { numeric: "auto" });
102
- // "today"
186
+ // Output depends on the current clock.
187
+
188
+ fromNow("2026-03-31T10:00:00Z", {
189
+ baseDate: "2026-03-31T12:00:00Z",
190
+ style: "short"
191
+ });
192
+ // → "2h ago"
193
+
194
+ parseDateDetailed("31 Mar 26", { strict: true });
195
+ // → { success: false, reason: "strict_mismatch", ... }
103
196
  ```
104
197
 
105
- Use `format()` for everything. Choose a mode (`standard`, `bangla`, `hybrid`) or pass a token pattern.
198
+ > Use `format()` for everything. Choose a mode (`standard`, `bangla`, `hijri`, `hybrid`) or pass a token pattern.
106
199
 
107
200
  ```ts
108
201
  // Show today's Bangla date in your app header
109
- format(new Date(), { mode: "bangla", locale: "bn-BD" });
110
- // → "১৭ চৈত্র ১৪৩২"
202
+ format("2026-03-31", { mode: "bangla", locale: "bn-BD" });
203
+ // → "১৭ চৈত্র ১৪৩২ বঙ্গাব্দ"
111
204
  ```
112
205
 
113
206
  ## Features
@@ -117,14 +210,14 @@ format(new Date(), { mode: "bangla", locale: "bn-BD" });
117
210
  ```ts
118
211
  import { format } from "@coreify/tarikh";
119
212
 
120
- format(new Date(), { mode: "standard" });
121
- // → "31 Mar 2026"
213
+ format("2026-03-31", { mode: "standard" });
214
+ // → "31st Mar 2026"
122
215
 
123
- format(new Date(), { mode: "standard", locale: "bn-BD" });
124
- // → "৩১ মার্চ ২০২৬"
216
+ format("2026-03-31", { mode: "standard", locale: "bn-BD" });
217
+ // → "৩১শে মার্চ ২০২৬ খ্রিস্টাব্দ"
125
218
 
126
- format(new Date(), { mode: "standard", month: "long", year: "2-digit" });
127
- // → "31 March 26"
219
+ format("2026-03-31", { mode: "standard", month: "long", year: "2-digit" });
220
+ // → "31st March 26"
128
221
 
129
222
  format(new Date(2026, 2, 31, 15, 4, 9), {
130
223
  mode: "standard",
@@ -134,23 +227,25 @@ format(new Date(2026, 2, 31, 15, 4, 9), {
134
227
  second: "2-digit",
135
228
  hour12: true
136
229
  });
137
- // → "Tuesday, 31 Mar 2026, 03:04:09 PM"
230
+ // → "Tuesday, 31st Mar 2026, 03:04:09 PM"
138
231
  ```
139
232
 
140
233
  **Options:** `locale` (`"en-BD"` | `"bn-BD"`), `month` (`"short"` | `"long"`), `year` (`"numeric"` | `"2-digit"`), `day` (`"numeric"` | `"2-digit"`), `weekday` (`"short"` | `"long"`), `hour` / `minute` / `second` (`"numeric"` | `"2-digit"`), `hour12` (`boolean`)
141
234
 
235
+ **Presets:** `preset: "date" | "dateTime" | "isoLike"`
236
+
142
237
  ### Pattern Formatting
143
238
 
144
239
  ```ts
145
240
  import { format } from "@coreify/tarikh";
146
241
 
147
- format(new Date(), { pattern: "DD MMM YYYY" });
242
+ format("2026-03-31", { pattern: "DD MMM YYYY" });
148
243
  // → "31 Mar 2026"
149
244
 
150
- format(new Date(), { pattern: "DD MMMM YYYY", locale: "bn-BD" });
245
+ format("2026-03-31", { pattern: "DD MMMM YYYY", locale: "bn-BD" });
151
246
  // → "৩১ মার্চ ২০২৬"
152
247
 
153
- format(new Date(), { pattern: "DD/MM/YYYY" });
248
+ format("2026-03-31", { pattern: "DD/MM/YYYY" });
154
249
  // → "31/03/2026"
155
250
 
156
251
  format(new Date(2026, 2, 31, 15, 4, 9), {
@@ -170,33 +265,30 @@ format(new Date(2026, 2, 31, 21, 4, 9), {
170
265
  // → "Tuesday, 31 Mar 2026 09:04:09 PM"
171
266
  ```
172
267
 
173
- `format()` is the primary API. Use `{ mode }` for date behavior or `{ pattern }` for token formatting. `mode` and `pattern` are mutually exclusive.
268
+ > `format()` is the primary API. Use `{ mode }` for date behavior or `{ pattern }` for token formatting. `mode` and `pattern` are mutually exclusive.
174
269
 
175
270
  **Tokens:** `dddd`, `ddd`, `DD`, `D`, `MMMM`, `MMM`, `MM`, `M`, `YYYY`, `YY`, `HH`, `H`, `hh`, `h`, `mm`, `m`, `ss`, `s`, `A`, `a`
176
271
 
177
- Use square brackets to keep literal text untouched by token replacement:
272
+ > Use square brackets to keep literal text untouched by token replacement:
178
273
 
179
274
  ```ts
180
275
  format(new Date(2026, 2, 31, 15, 4), { pattern: "[Today at] h:mm a" });
181
276
  // → "Today at 3:04 pm"
182
277
  ```
183
278
 
184
- Bracket literals are not nestable; the first `]` closes the literal block.
279
+ > Bracket literals are not nestable; the first `]` closes the literal block.
185
280
 
186
281
  ## 🇧🇩 Bangla Calendar (Core Feature)
187
282
 
188
- This is the reason `@coreify/tarikh` exists.
189
-
190
- Convert Gregorian dates to the Bengali calendar (Bangladesh Revised Calendar, 1987).
191
-
192
- - **Top feature:** `format("2026-04-14", { mode: "bangla", locale: "bn-BD", format: "spoken" })` returns `পহেলা বৈশাখ ১৪৩৩`.
193
- - `toBanglaCalendar()` returns a structured object.
194
- - Default output: English digits + Latin month names (`en-BD`).
195
- - Locale-aware output: Bangla date words like `১লা`, `২রা`, `৩রা`, `৪ঠা`, `৫ই`, `১৯শে` plus Bangla month names (`bn-BD`).
196
- - `monthIndex` remains numeric in both cases.
197
- - `format(..., { mode: "bangla", locale: "bn-BD", format: "spoken" })` returns spoken day words like `পহেলা`, `দোসরা`, `তেসরা`, `চৌঠা`.
198
- - `formatBanglaCalendarDay(day, { format: "spoken" })` returns colloquial spoken forms for the first four days: `পহেলা`, `দোসরা`, `তেসরা`, `চৌঠা`.
199
- - Pass `{ variant: "pohela" }` to keep the standard `পহেলা` spelling explicitly, or `{ variant: "poyla" }` to get `পয়লা` for day 1. The parser also accepts the common `পয়লা` spelling.
283
+ | Bangla calendar | Behavior |
284
+ | -------------------- | -------------------------------------------------------------- |
285
+ | `toBanglaCalendar()` | Returns a structured object |
286
+ | Default output | English digits + Latin month names (`en-BD`) |
287
+ | `bn-BD` output | Bangla day forms like `১লা`, `২রা`, `৩রা`, `৪ঠা`, `৫ই`, `১৯শে` |
288
+ | Spoken mode | Returns `পহেলা`, `দোসরা`, `তেসরা`, `চৌঠা` |
289
+ | `variant: "pohela"` | Keeps the standard `পহেলা` spelling |
290
+ | `variant: "poyla"` | Uses `পয়লা` for day 1 |
291
+ | `monthIndex` | Stays numeric in both cases |
200
292
 
201
293
  ```ts
202
294
  import {
@@ -212,16 +304,16 @@ toBanglaCalendar("2026-03-31", { locale: "bn-BD" });
212
304
  // → { day: "১৭", month: "চৈত্র", monthIndex: 12, year: "১৪৩২" }
213
305
 
214
306
  format("2026-03-31", { mode: "bangla" });
215
- // → "17 Chaitra 1432"
307
+ // → "17th Chaitra 1432"
216
308
 
217
309
  format("2026-03-31", { mode: "bangla", locale: "bn-BD" });
218
- // → "১৭ই চৈত্র ১৪৩২"
310
+ // → "১৭ই চৈত্র ১৪৩২ বঙ্গাব্দ"
219
311
 
220
312
  format("2026-04-14", { mode: "bangla" });
221
- // → "1 Baishakh 1433"
313
+ // → "1st Baishakh 1433"
222
314
 
223
315
  format("2026-04-14", { mode: "bangla", locale: "bn-BD", format: "spoken" });
224
- // → "পহেলা বৈশাখ ১৪৩৩"
316
+ // → "পহেলা বৈশাখ ১৪৩৩ বঙ্গাব্দ"
225
317
 
226
318
  format("2026-04-14", {
227
319
  mode: "bangla",
@@ -229,11 +321,11 @@ format("2026-04-14", {
229
321
  format: "spoken",
230
322
  variant: "poyla"
231
323
  });
232
- // → "পয়লা বৈশাখ ১৪৩৩"
324
+ // → "পয়লা বৈশাখ ১৪৩৩ বঙ্গাব্দ"
233
325
 
234
326
  // Show today's Bangla date in your app header
235
- format(new Date(), { mode: "bangla", locale: "bn-BD" });
236
- // → "১৭ চৈত্র ১৪৩২" (example; depends on the current date)
327
+ format("2026-03-31", { mode: "bangla", locale: "bn-BD" });
328
+ // → "১৭ চৈত্র ১৪৩২ বঙ্গাব্দ" (example; depends on the current date)
237
329
 
238
330
  formatBanglaCalendarDay(21);
239
331
  // → "২১শে"
@@ -248,17 +340,63 @@ formatBanglaCalendarDay(1, { format: "spoken", variant: "pohela" });
248
340
  // → "পহেলা"
249
341
  ```
250
342
 
343
+ ### Hijri Calendar
344
+
345
+ | Hijri calendar | Behavior |
346
+ | ---------------------- | -------------------------------------------------- |
347
+ | `toHijriCalendar()` | Returns a structured object |
348
+ | Default timezone | `Asia/Dhaka` |
349
+ | `timeZone` override | Accepts the exported `HIJRI_TIME_ZONES` values |
350
+ | Default backend | `Intl` with `islamic-umalqura` |
351
+ | `hijriSystem` override | Accepts `"islamic-umalqura"` and `"islamic-civil"` |
352
+ | Default output | English month/day/year with `AH` |
353
+ | `bn-BD` output | Bangla digits and the `হিজরি` suffix |
354
+ | `UTC` override | Exposes the alternative canonical Hijri result |
355
+
356
+ ```ts
357
+ import { HIJRI_TIME_ZONES, format, toHijriCalendar } from "@coreify/tarikh";
358
+
359
+ const [defaultHijriZone, alternateHijriZone] = HIJRI_TIME_ZONES;
360
+
361
+ toHijriCalendar("2026-03-31");
362
+ // → { day: 11, month: "Shawwal", monthIndex: 10, year: 1447 }
363
+
364
+ toHijriCalendar("2026-03-31", { locale: "bn-BD" });
365
+ // → { day: "১১", month: "শাওয়াল", monthIndex: 10, year: "১৪৪৭" }
366
+
367
+ toHijriCalendar("2026-03-31", { timeZone: "UTC" });
368
+ // → { day: 11, month: "Shawwal", monthIndex: 10, year: 1447 }
369
+
370
+ toHijriCalendar("2026-03-31", { hijriSystem: "islamic-civil" });
371
+ // → Civil Hijri output backed by Intl
372
+
373
+ // Supported values: defaultHijriZone === "Asia/Dhaka", alternateHijriZone === "UTC"
374
+
375
+ format("2026-03-31", { mode: "hijri" });
376
+ // → "12th Shawwal 1447 AH"
377
+
378
+ format("2026-03-31", { mode: "hijri", timeZone: "UTC" });
379
+ // → "11th Shawwal 1447 AH"
380
+
381
+ format("2026-03-31", { mode: "hijri", locale: "bn-BD" });
382
+ // → "১২ই শাওয়াল ১৪৪৭ হিজরি"
383
+ ```
384
+
385
+ > Hijri output is powered by `Intl` and defaults to `islamic-umalqura`. Regional moon-sighting expectations can differ from the returned value, so use `hijriSystem` and `timeZone` intentionally.
386
+
251
387
  ### Hybrid Formatting
252
388
 
253
- Mix English and Bangla independently for day, month, and year.
389
+ | Mixing rule | Summary |
390
+ | ----------------- | ------------------------------------------------------------- |
391
+ | Hybrid formatting | Mix English and Bangla independently for day, month, and year |
254
392
 
255
393
  ```ts
256
394
  import { format } from "@coreify/tarikh";
257
395
 
258
- format(new Date(), { mode: "hybrid" });
396
+ format("2026-03-31", { mode: "hybrid" });
259
397
  // → "31 মার্চ 2026"
260
398
 
261
- format(new Date(), {
399
+ format("2026-03-31", {
262
400
  mode: "hybrid",
263
401
  digits: "bn",
264
402
  month: "bn",
@@ -285,28 +423,39 @@ toEnglishDigits("৩১ মার্চ ২০২৬");
285
423
  import { fromNow } from "@coreify/tarikh";
286
424
 
287
425
  fromNow(new Date(Date.now() - 86400000));
288
- // "1 day ago"
426
+ // Output depends on the current clock.
289
427
 
290
428
  fromNow(new Date(Date.now() - 86400000), { locale: "bn-BD" });
291
- // "১ দিন আগে"
429
+ // Output depends on the current clock.
292
430
 
293
431
  fromNow(new Date(Date.now() + 3600000));
294
- // "in 1 hour"
432
+ // Output depends on the current clock.
295
433
 
296
434
  fromNow(new Date(Date.now() - 86400000), { numeric: "auto" });
297
- // "yesterday"
435
+ // Output depends on the current clock.
298
436
 
299
437
  fromNow(new Date(Date.now() + 86400000), {
300
438
  locale: "bn-BD",
301
439
  numeric: "auto"
302
440
  });
303
- // "আগামীকাল"
441
+ // Output depends on the current clock.
442
+
443
+ fromNow("2026-03-31T10:00:00Z", {
444
+ baseDate: "2026-03-31T12:00:00Z",
445
+ style: "short"
446
+ });
447
+ // → "2h ago"
448
+
449
+ fromNow(new Date(Date.now() - 30000), {
450
+ threshold: { justNow: 60000 }
451
+ });
452
+ // → "just now"
304
453
  ```
305
454
 
306
455
  ### Parsing
307
456
 
308
457
  ```ts
309
- import { parseDate } from "@coreify/tarikh";
458
+ import { parseDate, parseDateDetailed } from "@coreify/tarikh";
310
459
 
311
460
  parseDate("৩১ মার্চ ২০২৬");
312
461
  // → Date object (March 31, 2026)
@@ -337,6 +486,12 @@ parseDate("2026.03.31");
337
486
  parseDate("2026-03-31T15:30:00Z");
338
487
  // → Date object (March 31, 2026, 3:30 PM UTC)
339
488
 
489
+ parseDate("31 Mar 26", { strict: true });
490
+ // → null
491
+
492
+ parseDateDetailed("31 Mar 26", { strict: true });
493
+ // → { success: false, reason: "strict_mismatch", ... }
494
+
340
495
  // `toDate()` accepts the same Gregorian string forms as `parseDate()`,
341
496
  // plus `Date` objects and timestamps.
342
497
  // Supported string shapes:
@@ -352,6 +507,26 @@ parseDate("2026-03-31T15:30:00Z");
352
507
  // - Common Bangla month aliases like `Boishakh`, `Poush`, `Falgun`, `Asharh`
353
508
  ```
354
509
 
510
+ ### Global Defaults
511
+
512
+ ```ts
513
+ import { format, getDefaults, setDefaults } from "@coreify/tarikh";
514
+
515
+ setDefaults({
516
+ locale: "bn-BD",
517
+ mode: "standard",
518
+ month: "long",
519
+ timeZone: "UTC",
520
+ hijriSystem: "islamic-civil"
521
+ });
522
+
523
+ getDefaults();
524
+ // → { locale: "bn-BD", mode: "standard", month: "long", timeZone: "UTC", hijriSystem: "islamic-civil" }
525
+
526
+ format("2026-03-31");
527
+ // → Uses the configured defaults
528
+ ```
529
+
355
530
  ### Utilities
356
531
 
357
532
  ```ts
@@ -406,53 +581,86 @@ import {
406
581
 
407
582
  ## React Components
408
583
 
409
- Optional entry point — only included if you import from `@coreify/tarikh/react`.
584
+ | React export | Purpose |
585
+ | ----------------- | ----------------------------------- |
586
+ | `Tarikh` | Default semantic `<time>` formatter |
587
+ | `Tarikh.Relative` | Relative time rendering |
588
+ | `Tarikh.Bangla` | Bangla calendar rendering |
589
+ | `Tarikh.Hijri` | Hijri calendar rendering |
410
590
 
411
- Primary React API:
412
-
413
- Use `Tarikh` for the default formatter, then reach for the nested variants when you want relative time or Bangla calendar rendering.
591
+ > Import from `@coreify/tarikh/react` only when you need the React components.
414
592
 
415
593
  ```tsx
416
594
  import { Tarikh } from "@coreify/tarikh/react";
417
595
 
418
- <Tarikh value={new Date()} />
419
- <Tarikh.Relative value={new Date()} />
420
- <Tarikh.Bangla value={new Date()} locale="bn-BD" />
596
+ const date = "2026-03-31";
597
+
598
+ <Tarikh value={date} />
599
+ <Tarikh.Relative value={date} />
600
+ <Tarikh.Bangla value={date} locale="bn-BD" />
601
+ <Tarikh.Hijri value={date} locale="bn-BD" />
602
+ <Tarikh.Relative value={date} relativeStyle="short" />
421
603
  ```
422
604
 
423
605
  ```bash
424
606
  npm install @coreify/tarikh react
425
607
  ```
426
608
 
427
- All components render semantic `<time>` elements with `dateTime` and `aria-label` attributes. They are SSR-safe, tree-shakeable, and have zero runtime dependencies beyond React.
428
-
429
- `Tarikh` handles standard date formatting, `Tarikh.Relative` handles relative time, and `Tarikh.Bangla` handles Bangla calendar output.
609
+ | React detail | Notes |
610
+ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
611
+ | Semantics | Renders `<time>` elements with `dateTime` and `aria-label` |
612
+ | Runtime | SSR-safe, tree-shakeable, zero runtime dependencies beyond React |
613
+ | Roles | `Tarikh` standard formatting, `Tarikh.Relative` relative time, `Tarikh.Bangla` Bangla calendar, `Tarikh.Hijri` Hijri calendar |
614
+ | Relative prop note | Use `relativeStyle` instead of `style` on `Tarikh.Relative` to avoid colliding with the native DOM `style` prop |
430
615
 
431
616
  ## What `Intl.DateTimeFormat` cannot do
432
617
 
433
- If you're building for Bangladesh, existing libraries are not enough.
618
+ | Why `Intl` falls short | Summary |
619
+ | ----------------------------- | --------------------------------------------------- |
620
+ | Bangladesh-focused formatting | Needs Bangla calendar and culturally correct output |
434
621
 
435
622
  | Feature | Intl | @coreify/tarikh |
436
623
  | ------------------------------- | ------- | --------------- |
437
624
  | Bangla calendar (বৈশাখ → চৈত্র) | No | Yes |
625
+ | Hijri calendar | Partial | Yes |
438
626
  | Bangla digits in dates | Partial | Yes |
439
627
  | Hybrid formatting (mixed en/bn) | No | Yes |
440
628
  | Bangla calendar date parsing | No | Yes |
441
629
  | Relative time in Bangla | No | Yes |
442
630
  | SSR-safe React components | N/A | Yes |
443
631
 
444
- ## TypeScript
632
+ ## Common Pitfalls
445
633
 
446
- Fully typed with strict mode. Start with the primary types below; the package also exports the lower-level calendar and helper types for advanced use.
634
+ | Pitfall | What to watch for |
635
+ | ------------------------------ | ----------------------------------------------------------------------------------------------------------- |
636
+ | Hijri mismatch | Tarikh uses `Intl` and defaults to `islamic-umalqura`; local moon-sighting calendars may differ |
637
+ | Time zone expectations | Hijri conversion changes with `timeZone`, so `Asia/Dhaka` and `UTC` can return different days |
638
+ | `short` vs `long` month output | Standard mode defaults to short English month names but long Bangla month names unless you override `month` |
639
+ | Strict parsing | `strict: true` rejects loose helpers like two-digit years and legacy Bangla month aliases |
640
+
641
+ ## TypeScript
447
642
 
448
- Type-level contract note: when using `pattern`, `mode` is intentionally disallowed in TypeScript.
643
+ | Type | Purpose |
644
+ | -------------------------------- | ---------------------------------------------------------------------- |
645
+ | `FormatOptions` | Primary object-based formatting contract |
646
+ | `BanglaCalendarResult<TLocale>` | Locale-aware structured Bangla calendar return type |
647
+ | `HijriCalendarResult<TLocale>` | Locale-aware structured Hijri return type |
648
+ | `BanglaCalendarOptions<TLocale>` | Locale-aware structured Bangla conversion options |
649
+ | `HijriCalendarOptions<TLocale>` | Locale-aware structured Hijri conversion options |
650
+ | `TarikhProps` | Props for the main React `<Tarikh />` component |
651
+ | `HIJRI_TIME_ZONES` | Canonical supported Hijri time zones (`Asia/Dhaka`, `UTC`) |
652
+ | Type-level contract | When using `pattern`, `mode` is intentionally disallowed in TypeScript |
449
653
 
450
654
  ```ts
451
655
  import type {
656
+ BanglaCalendarOptions,
657
+ BanglaCalendarResult,
452
658
  Locale,
453
659
  FormatMode,
454
660
  FormatOptions,
455
661
  DateInput,
662
+ HijriCalendarOptions,
663
+ HijriCalendarResult,
456
664
  RelativeTimeOptions
457
665
  } from "@coreify/tarikh";
458
666