chronal 0.0.9 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -324,9 +324,28 @@ Parses a date string into a Date object using an optional format pattern.
324
324
  - `dateString` (string) - The date string to parse
325
325
  - `format` (string, optional) - Format pattern (e.g., "YYYY-MM-DD",
326
326
  "DD/MM/YYYY")
327
+ - `options` (object, optional) - Parsing options
328
+ - `tz` (string) - IANA timezone (e.g., 'America/Sao_Paulo')
327
329
 
328
330
  **Returns:** Date object
329
331
 
332
+ **Timezone Behavior:**
333
+
334
+ When parsing date strings, `parseDate` follows these rules:
335
+
336
+ 1. **Explicit timezone** (e.g., `Z` or `+03:00`) - Always respected, ignores `config.timezone`
337
+ 2. **No timezone** - Uses `config.timezone` or the `tz` option to interpret the string as local time in that timezone
338
+
339
+ ```typescript
340
+ // With explicit UTC marker (Z) - always UTC
341
+ parseDate("2026-01-12T02:59:59.999Z"); // UTC time, ignores config
342
+
343
+ // Without timezone - uses config.timezone
344
+ setChronalConfig({ timezone: "America/Sao_Paulo" });
345
+ parseDate("2026-01-12T02:59:59.999"); // Interpreted as São Paulo time
346
+ parseDate("2026-01-12"); // Midnight in São Paulo
347
+ ```
348
+
330
349
  **Supported Tokens:**
331
350
 
332
351
  - `YYYY` - 4-digit year
@@ -346,6 +365,9 @@ parseDate("2024-06-15"); // Date object
346
365
  parseDate("15/06/2024", "DD/MM/YYYY");
347
366
  parseDate("2024-06-15 14:30:00", "YYYY-MM-DD HH:mm:ss");
348
367
  parseDate("06/15/2024", "MM/DD/YYYY");
368
+
369
+ // With timezone
370
+ parseDate("2024-06-15", { tz: "America/Sao_Paulo" }); // Parse as São Paulo time
349
371
  ```
350
372
 
351
373
  ### Manipulation
@@ -0,0 +1,2 @@
1
+ export declare function getRTF(locale: string, numeric: "auto" | "always"): Intl.RelativeTimeFormat;
2
+ //# sourceMappingURL=rtf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtf.d.ts","sourceRoot":"","sources":["../../src/core/rtf.ts"],"names":[],"mappings":"AAEA,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,2BAQhE"}
@@ -0,0 +1,10 @@
1
+ const rtfCache = new Map();
2
+ export function getRTF(locale, numeric) {
3
+ const key = `${locale}|${numeric}`;
4
+ let rtf = rtfCache.get(key);
5
+ if (!rtf) {
6
+ rtf = new Intl.RelativeTimeFormat(locale, { numeric });
7
+ rtfCache.set(key, rtf);
8
+ }
9
+ return rtf;
10
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"from-now.d.ts","sourceRoot":"","sources":["../../src/lib/from-now.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,GAAE,MAAsB,GAAG,MAAM,CAmC1E"}
1
+ {"version":3,"file":"from-now.d.ts","sourceRoot":"","sources":["../../src/lib/from-now.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,GAAE,MAAsB,GAAG,MAAM,CAyC1E"}
@@ -1,3 +1,4 @@
1
+ import { getRTF } from "../core/rtf.js";
1
2
  import { config } from "./config.js";
2
3
  /**
3
4
  * Returns a string representing how long ago the date was from now.
@@ -25,21 +26,26 @@ export function fromNow(date, locale = config.locale) {
25
26
  const minutes = Math.floor(seconds / 60);
26
27
  const hours = Math.floor(minutes / 60);
27
28
  const days = Math.floor(hours / 24);
29
+ const weeks = Math.floor(days / 7);
28
30
  const months = Math.floor(days / 30);
29
31
  const years = Math.floor(days / 365);
30
- const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
32
+ // Use auto for "now", always for everything else
31
33
  if (seconds < 60) {
32
- return rtf.format(0, "second");
34
+ return getRTF(locale, "auto").format(0, "second");
33
35
  }
36
+ const rtf = getRTF(locale, "always");
34
37
  if (minutes < 60) {
35
38
  return rtf.format(diff < 0 ? minutes : -minutes, "minute");
36
39
  }
37
40
  if (hours < 24) {
38
41
  return rtf.format(diff < 0 ? hours : -hours, "hour");
39
42
  }
40
- if (days < 30) {
43
+ if (days < 7) {
41
44
  return rtf.format(diff < 0 ? days : -days, "day");
42
45
  }
46
+ if (days < 30) {
47
+ return rtf.format(diff < 0 ? weeks : -weeks, "week");
48
+ }
43
49
  if (months < 12) {
44
50
  return rtf.format(diff < 0 ? months : -months, "month");
45
51
  }
@@ -1 +1 @@
1
- {"version":3,"file":"parse-date.d.ts","sourceRoot":"","sources":["../../src/lib/parse-date.ts"],"names":[],"mappings":"AAGA,KAAK,gBAAgB,GAAG;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAClC,IAAI,CA0FN"}
1
+ {"version":3,"file":"parse-date.d.ts","sourceRoot":"","sources":["../../src/lib/parse-date.ts"],"names":[],"mappings":"AAGA,KAAK,gBAAgB,GAAG;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAClC,IAAI,CA6FN"}
@@ -27,8 +27,10 @@ export function parseDate(dateString, options) {
27
27
  if (isNaN(date.getTime())) {
28
28
  throw new Error("Invalid date");
29
29
  }
30
- // If timezone is not UTC, interpret the date string as local time in that timezone
31
- if (timezone !== "UTC") {
30
+ // If the string has explicit timezone (Z or offset like +03:00), respect it
31
+ // Only apply config.timezone for date strings without timezone info
32
+ const hasExplicitTimezone = /Z|[+-]\d{2}:\d{2}$/.test(dateString);
33
+ if (!hasExplicitTimezone && timezone !== "UTC") {
32
34
  return parseDateInTimezone(date, timezone);
33
35
  }
34
36
  return date;
@@ -1 +1 @@
1
- {"version":3,"file":"to-now.d.ts","sourceRoot":"","sources":["../../src/lib/to-now.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,GAAE,MAAsB,GAAG,MAAM,CAmCxE"}
1
+ {"version":3,"file":"to-now.d.ts","sourceRoot":"","sources":["../../src/lib/to-now.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,GAAE,MAAsB,GAAG,MAAM,CAyCxE"}
package/esm/lib/to-now.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { getRTF } from "../core/rtf.js";
1
2
  import { config } from "./config.js";
2
3
  /**
3
4
  * Returns a string representing the time from now to the date.
@@ -26,21 +27,26 @@ export function toNow(date, locale = config.locale) {
26
27
  const minutes = Math.floor(seconds / 60);
27
28
  const hours = Math.floor(minutes / 60);
28
29
  const days = Math.floor(hours / 24);
30
+ const weeks = Math.floor(days / 7);
29
31
  const months = Math.floor(days / 30);
30
32
  const years = Math.floor(days / 365);
31
- const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
33
+ // Use auto for "now", always for everything else
32
34
  if (seconds < 60) {
33
- return rtf.format(0, "second");
35
+ return getRTF(locale, "auto").format(0, "second");
34
36
  }
37
+ const rtf = getRTF(locale, "always");
35
38
  if (minutes < 60) {
36
39
  return rtf.format(diff > 0 ? minutes : -minutes, "minute");
37
40
  }
38
41
  if (hours < 24) {
39
42
  return rtf.format(diff > 0 ? hours : -hours, "hour");
40
43
  }
41
- if (days < 30) {
44
+ if (days < 7) {
42
45
  return rtf.format(diff > 0 ? days : -days, "day");
43
46
  }
47
+ if (days < 30) {
48
+ return rtf.format(diff > 0 ? weeks : -weeks, "week");
49
+ }
44
50
  if (months < 12) {
45
51
  return rtf.format(diff > 0 ? months : -months, "month");
46
52
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chronal",
3
- "version": "0.0.9",
3
+ "version": "0.0.12",
4
4
  "description": "A tiny and fast date utility library for modern JavaScript runtimes.",
5
5
  "keywords": [
6
6
  "date",
@@ -0,0 +1,2 @@
1
+ export declare function getRTF(locale: string, numeric: "auto" | "always"): Intl.RelativeTimeFormat;
2
+ //# sourceMappingURL=rtf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtf.d.ts","sourceRoot":"","sources":["../../src/core/rtf.ts"],"names":[],"mappings":"AAEA,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,2BAQhE"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRTF = getRTF;
4
+ const rtfCache = new Map();
5
+ function getRTF(locale, numeric) {
6
+ const key = `${locale}|${numeric}`;
7
+ let rtf = rtfCache.get(key);
8
+ if (!rtf) {
9
+ rtf = new Intl.RelativeTimeFormat(locale, { numeric });
10
+ rtfCache.set(key, rtf);
11
+ }
12
+ return rtf;
13
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"from-now.d.ts","sourceRoot":"","sources":["../../src/lib/from-now.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,GAAE,MAAsB,GAAG,MAAM,CAmC1E"}
1
+ {"version":3,"file":"from-now.d.ts","sourceRoot":"","sources":["../../src/lib/from-now.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,GAAE,MAAsB,GAAG,MAAM,CAyC1E"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.fromNow = fromNow;
4
+ const rtf_js_1 = require("../core/rtf.js");
4
5
  const config_js_1 = require("./config.js");
5
6
  /**
6
7
  * Returns a string representing how long ago the date was from now.
@@ -28,21 +29,26 @@ function fromNow(date, locale = config_js_1.config.locale) {
28
29
  const minutes = Math.floor(seconds / 60);
29
30
  const hours = Math.floor(minutes / 60);
30
31
  const days = Math.floor(hours / 24);
32
+ const weeks = Math.floor(days / 7);
31
33
  const months = Math.floor(days / 30);
32
34
  const years = Math.floor(days / 365);
33
- const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
35
+ // Use auto for "now", always for everything else
34
36
  if (seconds < 60) {
35
- return rtf.format(0, "second");
37
+ return (0, rtf_js_1.getRTF)(locale, "auto").format(0, "second");
36
38
  }
39
+ const rtf = (0, rtf_js_1.getRTF)(locale, "always");
37
40
  if (minutes < 60) {
38
41
  return rtf.format(diff < 0 ? minutes : -minutes, "minute");
39
42
  }
40
43
  if (hours < 24) {
41
44
  return rtf.format(diff < 0 ? hours : -hours, "hour");
42
45
  }
43
- if (days < 30) {
46
+ if (days < 7) {
44
47
  return rtf.format(diff < 0 ? days : -days, "day");
45
48
  }
49
+ if (days < 30) {
50
+ return rtf.format(diff < 0 ? weeks : -weeks, "week");
51
+ }
46
52
  if (months < 12) {
47
53
  return rtf.format(diff < 0 ? months : -months, "month");
48
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"parse-date.d.ts","sourceRoot":"","sources":["../../src/lib/parse-date.ts"],"names":[],"mappings":"AAGA,KAAK,gBAAgB,GAAG;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAClC,IAAI,CA0FN"}
1
+ {"version":3,"file":"parse-date.d.ts","sourceRoot":"","sources":["../../src/lib/parse-date.ts"],"names":[],"mappings":"AAGA,KAAK,gBAAgB,GAAG;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAClC,IAAI,CA6FN"}
@@ -30,8 +30,10 @@ function parseDate(dateString, options) {
30
30
  if (isNaN(date.getTime())) {
31
31
  throw new Error("Invalid date");
32
32
  }
33
- // If timezone is not UTC, interpret the date string as local time in that timezone
34
- if (timezone !== "UTC") {
33
+ // If the string has explicit timezone (Z or offset like +03:00), respect it
34
+ // Only apply config.timezone for date strings without timezone info
35
+ const hasExplicitTimezone = /Z|[+-]\d{2}:\d{2}$/.test(dateString);
36
+ if (!hasExplicitTimezone && timezone !== "UTC") {
35
37
  return parseDateInTimezone(date, timezone);
36
38
  }
37
39
  return date;
@@ -1 +1 @@
1
- {"version":3,"file":"to-now.d.ts","sourceRoot":"","sources":["../../src/lib/to-now.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,GAAE,MAAsB,GAAG,MAAM,CAmCxE"}
1
+ {"version":3,"file":"to-now.d.ts","sourceRoot":"","sources":["../../src/lib/to-now.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,GAAE,MAAsB,GAAG,MAAM,CAyCxE"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toNow = toNow;
4
+ const rtf_js_1 = require("../core/rtf.js");
4
5
  const config_js_1 = require("./config.js");
5
6
  /**
6
7
  * Returns a string representing the time from now to the date.
@@ -29,21 +30,26 @@ function toNow(date, locale = config_js_1.config.locale) {
29
30
  const minutes = Math.floor(seconds / 60);
30
31
  const hours = Math.floor(minutes / 60);
31
32
  const days = Math.floor(hours / 24);
33
+ const weeks = Math.floor(days / 7);
32
34
  const months = Math.floor(days / 30);
33
35
  const years = Math.floor(days / 365);
34
- const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
36
+ // Use auto for "now", always for everything else
35
37
  if (seconds < 60) {
36
- return rtf.format(0, "second");
38
+ return (0, rtf_js_1.getRTF)(locale, "auto").format(0, "second");
37
39
  }
40
+ const rtf = (0, rtf_js_1.getRTF)(locale, "always");
38
41
  if (minutes < 60) {
39
42
  return rtf.format(diff > 0 ? minutes : -minutes, "minute");
40
43
  }
41
44
  if (hours < 24) {
42
45
  return rtf.format(diff > 0 ? hours : -hours, "hour");
43
46
  }
44
- if (days < 30) {
47
+ if (days < 7) {
45
48
  return rtf.format(diff > 0 ? days : -days, "day");
46
49
  }
50
+ if (days < 30) {
51
+ return rtf.format(diff > 0 ? weeks : -weeks, "week");
52
+ }
47
53
  if (months < 12) {
48
54
  return rtf.format(diff > 0 ? months : -months, "month");
49
55
  }