@timestamp-js/core 0.1.0-rc.0 → 0.1.0-rc.1

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
@@ -15,14 +15,14 @@ pnpm add @timestamp-js/core
15
15
  ## Basic Usage
16
16
 
17
17
  ```ts
18
- import { addToDate, addToDateClamped, getDateTime, parseTimestamp } from "@timestamp-js/core";
18
+ import { addToDate, addToDateClamped, getDateTime, parseTimestamp } from '@timestamp-js/core'
19
19
 
20
- const start = parseTimestamp("2026-06-08T09:30:15.250Z");
21
- const end = start ? addToDate(start, { day: 2, minute: 45 }) : null;
22
- const billingDate = start ? addToDateClamped(start, { month: 1 }) : null;
20
+ const start = parseTimestamp('2026-06-08T09:30:15.250Z')
21
+ const end = start ? addToDate(start, { day: 2, minute: 45 }) : null
22
+ const billingDate = start ? addToDateClamped(start, { month: 1 }) : null
23
23
 
24
- console.log(end ? getDateTime(end) : "Invalid date");
25
- console.log(billingDate ? getDateTime(billingDate) : "Invalid date");
24
+ console.log(end ? getDateTime(end) : 'Invalid date')
25
+ console.log(billingDate ? getDateTime(billingDate) : 'Invalid date')
26
26
  ```
27
27
 
28
28
  ## Timestamp Values
@@ -30,11 +30,11 @@ console.log(billingDate ? getDateTime(billingDate) : "Invalid date");
30
30
  Timestamp objects are immutable. Parsers and update helpers return frozen objects, and functions that change date/time fields return a new Timestamp instead of mutating the original.
31
31
 
32
32
  ```ts
33
- const start = parseTimestamp("2026-06-08 09:30")!;
34
- const next = addToDate(start, { day: 1 });
33
+ const start = parseTimestamp('2026-06-08 09:30')!
34
+ const next = addToDate(start, { day: 1 })
35
35
 
36
- console.log(start.date); // 2026-06-08
37
- console.log(next.date); // 2026-06-09
36
+ console.log(start.date) // 2026-06-08
37
+ console.log(next.date) // 2026-06-09
38
38
  ```
39
39
 
40
40
  ## Supported Input Shape
@@ -77,12 +77,13 @@ The publishable package lives in `packages/lib` so the repository follows the sa
77
77
  - Convert native `Date` objects into Timestamp objects.
78
78
  - Compare dates, times, date-times, and timestamp ranges, including optional second and millisecond precision.
79
79
  - Generate day and interval lists for calendar-style views.
80
+ - Generate adapter-aware calendar timestamps and day lists for optional calendar packages.
80
81
  - Format weekday and month names through `Intl.DateTimeFormat`.
81
82
  - Keep the public surface small, typed, immutable, and runtime-agnostic while the package stabilizes.
82
83
 
83
84
  ## Future Scope
84
85
 
85
- The package is intentionally not trying to become a full general-purpose date library on day one. Planned evaluations include Temporal support, explicit timezone behavior, alternate calendar systems, duration helpers, Unix timestamp helpers, compact formatting masks, and a script-tag/browser build if CodePen-style demos need it.
86
+ The package is intentionally not trying to become a full general-purpose date library on day one. Planned evaluations include Temporal support, explicit timezone behavior, more alternate calendar systems, compact formatting masks, and a script-tag/browser build if CodePen-style demos need it.
86
87
 
87
88
  ## Development
88
89
 
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Stable identifier for a calendar implementation.
3
+ *
4
+ * The built-in Gregorian adapter uses `gregorian` as its package-facing id and
5
+ * `gregory` as its Intl calendar id.
6
+ */
7
+ export type CalendarId = 'gregorian' | (string & {});
8
+ /**
9
+ * Plain calendar date fields.
10
+ */
11
+ export interface CalendarDateParts {
12
+ /**
13
+ * Calendar year.
14
+ */
15
+ readonly year: number;
16
+ /**
17
+ * Calendar month number. The first month is `1`.
18
+ */
19
+ readonly month: number;
20
+ /**
21
+ * Day of the month. The first day is `1`.
22
+ */
23
+ readonly day: number;
24
+ }
25
+ /**
26
+ * Calendar implementation contract used by Timestamp helpers.
27
+ *
28
+ * Calendar packages should implement this interface without import-time side
29
+ * effects. Core range and comparison helpers can use `epochDay` as a stable
30
+ * serial value instead of comparing calendar-specific year/month/day fields.
31
+ */
32
+ export interface CalendarSystem {
33
+ /**
34
+ * Package-facing calendar id.
35
+ */
36
+ readonly id: CalendarId;
37
+ /**
38
+ * Optional Intl calendar id, when one exists.
39
+ */
40
+ readonly intlCalendar?: string;
41
+ /**
42
+ * Human-readable calendar name.
43
+ */
44
+ readonly label: string;
45
+ /**
46
+ * Number of months in a calendar year.
47
+ */
48
+ monthsInYear(year: number): number;
49
+ /**
50
+ * True when the calendar year has a leap day or leap month.
51
+ */
52
+ isLeapYear(year: number): boolean;
53
+ /**
54
+ * Number of days in the specified calendar month.
55
+ */
56
+ daysInMonth(year: number, month: number): number;
57
+ /**
58
+ * Converts a calendar date into a stable serial day.
59
+ *
60
+ * For Gregorian this is the number of UTC days since 1970-01-01. Other
61
+ * calendar adapters should return the serial day for the equivalent civil
62
+ * instant so comparisons and ranges can stay calendar-agnostic.
63
+ */
64
+ toEpochDay(date: CalendarDateParts): number;
65
+ /**
66
+ * Converts a stable serial day into calendar date fields.
67
+ */
68
+ fromEpochDay(epochDay: number): CalendarDateParts;
69
+ /**
70
+ * Moves a calendar date by a whole number of days.
71
+ */
72
+ addDays(date: CalendarDateParts, amount: number): CalendarDateParts;
73
+ /**
74
+ * Returns the next calendar date.
75
+ */
76
+ nextDay(date: CalendarDateParts): CalendarDateParts;
77
+ /**
78
+ * Returns the previous calendar date.
79
+ */
80
+ prevDay(date: CalendarDateParts): CalendarDateParts;
81
+ /**
82
+ * Returns day-of-year for a calendar date.
83
+ */
84
+ getDayOfYear(date: CalendarDateParts): number;
85
+ /**
86
+ * Returns weekday where Sunday is `0` and Saturday is `6`.
87
+ */
88
+ getWeekday(date: CalendarDateParts): number;
89
+ }
90
+ /**
91
+ * Formats calendar fields using the Timestamp package's fixed date format.
92
+ */
93
+ export declare function formatCalendarDate(date: CalendarDateParts): string;
94
+ /**
95
+ * Built-in proleptic Gregorian calendar adapter.
96
+ *
97
+ * This preserves the current Timestamp behavior and gives future calendar
98
+ * packages a concrete contract to implement.
99
+ */
100
+ export declare const gregorianCalendar: CalendarSystem;
101
+ //# sourceMappingURL=calendar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../src/calendar.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEpD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IAEtB;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAA;IAEvB;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAE9B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IAEtB;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAElC;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAEjC;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAEhD;;;;;;OAMG;IACH,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAA;IAE3C;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAAA;IAEjD;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAAA;IAEnE;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,CAAA;IAEnD;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,CAAA;IAEnD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAA;IAE7C;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAA;CAC5C;AAWD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAElE;AAcD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,cA+C9B,CAAA"}
@@ -0,0 +1,69 @@
1
+ const MILLISECONDS_IN_DAY = 86400000;
2
+ const GREGORIAN_DAYS_IN_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
3
+ const GREGORIAN_DAYS_IN_MONTH_LEAP = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
4
+ function padNumber(value, length) {
5
+ let padded = String(value);
6
+ while (padded.length < length) {
7
+ padded = '0' + padded;
8
+ }
9
+ return padded;
10
+ }
11
+ /**
12
+ * Formats calendar fields using the Timestamp package's fixed date format.
13
+ */
14
+ export function formatCalendarDate(date) {
15
+ return `${padNumber(date.year, 4)}-${padNumber(date.month, 2)}-${padNumber(date.day, 2)}`;
16
+ }
17
+ function fromUtcDate(date) {
18
+ return {
19
+ year: date.getUTCFullYear(),
20
+ month: date.getUTCMonth() + 1,
21
+ day: date.getUTCDate(),
22
+ };
23
+ }
24
+ function toGregorianUtcDate(date) {
25
+ return new Date(Date.UTC(date.year, date.month - 1, date.day));
26
+ }
27
+ /**
28
+ * Built-in proleptic Gregorian calendar adapter.
29
+ *
30
+ * This preserves the current Timestamp behavior and gives future calendar
31
+ * packages a concrete contract to implement.
32
+ */
33
+ export const gregorianCalendar = Object.freeze({
34
+ id: 'gregorian',
35
+ intlCalendar: 'gregory',
36
+ label: 'Gregorian',
37
+ monthsInYear() {
38
+ return 12;
39
+ },
40
+ isLeapYear(year) {
41
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
42
+ },
43
+ daysInMonth(year, month) {
44
+ return (this.isLeapYear(year) ? GREGORIAN_DAYS_IN_MONTH_LEAP[month] : GREGORIAN_DAYS_IN_MONTH[month]);
45
+ },
46
+ toEpochDay(date) {
47
+ return Math.floor(Date.UTC(date.year, date.month - 1, date.day) / MILLISECONDS_IN_DAY);
48
+ },
49
+ fromEpochDay(epochDay) {
50
+ return fromUtcDate(new Date(epochDay * MILLISECONDS_IN_DAY));
51
+ },
52
+ addDays(date, amount) {
53
+ return this.fromEpochDay(this.toEpochDay(date) + amount);
54
+ },
55
+ nextDay(date) {
56
+ return this.addDays(date, 1);
57
+ },
58
+ prevDay(date) {
59
+ return this.addDays(date, -1);
60
+ },
61
+ getDayOfYear(date) {
62
+ const yearStart = this.toEpochDay({ year: date.year, month: 1, day: 1 });
63
+ return this.toEpochDay(date) - yearStart + 1;
64
+ },
65
+ getWeekday(date) {
66
+ return toGregorianUtcDate(date).getUTCDay();
67
+ },
68
+ });
69
+ //# sourceMappingURL=calendar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar.js","sourceRoot":"","sources":["../src/calendar.ts"],"names":[],"mappings":"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"}