@read-frog/definitions 0.1.3 → 0.3.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.
@@ -0,0 +1,132 @@
1
+ import { describe, expect, it } from "vitest"
2
+ import { differenceInSrsDays, getSrsDayEnd, getSrsDayStart, isSameSrsDay } from "./srs-day"
3
+
4
+ describe("srs day boundary", () => {
5
+ it("uses local 4am as the day start", () => {
6
+ expect(getSrsDayStart(
7
+ // Sat Jan 10 2026 03:59:00 GMT-0800 (Pacific Standard Time)
8
+ new Date("2026-01-10T11:59:00.000Z"),
9
+ "America/Vancouver",
10
+ // Fri Jan 09 2026 04:00:00 GMT-0800 (Pacific Standard Time)
11
+ )).toEqual(new Date("2026-01-09T12:00:00.000Z"))
12
+
13
+ expect(getSrsDayStart(
14
+ // Sat Jan 10 2026 04:00:00 GMT-0800 (Pacific Standard Time)
15
+ new Date("2026-01-10T12:00:00.000Z"),
16
+ "America/Vancouver",
17
+ // Sat Jan 10 2026 04:00:00 GMT-0800 (Pacific Standard Time)
18
+ )).toEqual(new Date("2026-01-10T12:00:00.000Z"))
19
+ })
20
+
21
+ it("uses the next local 4am as the day end", () => {
22
+ expect(getSrsDayEnd(
23
+ // Sat Jan 10 2026 03:59:00 GMT-0800 (Pacific Standard Time)
24
+ new Date("2026-01-10T11:59:00.000Z"),
25
+ "America/Vancouver",
26
+ // Sat Jan 10 2026 04:00:00 GMT-0800 (Pacific Standard Time)
27
+ )).toEqual(new Date("2026-01-10T12:00:00.000Z"))
28
+
29
+ expect(getSrsDayEnd(
30
+ // Sat Jan 10 2026 04:00:00 GMT-0800 (Pacific Standard Time)
31
+ new Date("2026-01-10T12:00:00.000Z"),
32
+ "America/Vancouver",
33
+ // Sun Jan 11 2026 04:00:00 GMT-0800 (Pacific Standard Time)
34
+ )).toEqual(new Date("2026-01-11T12:00:00.000Z"))
35
+ })
36
+
37
+ it("compares days with the 4am boundary", () => {
38
+ expect(isSameSrsDay(
39
+ // Sat Jan 10 2026 03:59:00 GMT-0800 (Pacific Standard Time)
40
+ new Date("2026-01-10T11:59:00.000Z"),
41
+ // Fri Jan 09 2026 04:00:00 GMT-0800 (Pacific Standard Time)
42
+ new Date("2026-01-09T12:00:00.000Z"),
43
+ "America/Vancouver",
44
+ )).toBe(true)
45
+ expect(isSameSrsDay(
46
+ // Sat Jan 10 2026 04:00:00 GMT-0800 (Pacific Standard Time)
47
+ new Date("2026-01-10T12:00:00.000Z"),
48
+ // Fri Jan 09 2026 04:00:00 GMT-0800 (Pacific Standard Time)
49
+ new Date("2026-01-09T12:00:00.000Z"),
50
+ "America/Vancouver",
51
+ )).toBe(false)
52
+ })
53
+
54
+ it("counts elapsed SRS days with the 4am boundary", () => {
55
+ expect(differenceInSrsDays(
56
+ // Sat Jan 10 2026 03:59:00 GMT-0800 (Pacific Standard Time)
57
+ new Date("2026-01-10T11:59:00.000Z"),
58
+ // Fri Jan 09 2026 04:00:00 GMT-0800 (Pacific Standard Time)
59
+ new Date("2026-01-09T12:00:00.000Z"),
60
+ "America/Vancouver",
61
+ )).toBe(0)
62
+ expect(differenceInSrsDays(
63
+ // Sat Jan 10 2026 04:00:00 GMT-0800 (Pacific Standard Time)
64
+ new Date("2026-01-10T12:00:00.000Z"),
65
+ // Fri Jan 09 2026 04:00:00 GMT-0800 (Pacific Standard Time)
66
+ new Date("2026-01-09T12:00:00.000Z"),
67
+ "America/Vancouver",
68
+ )).toBe(1)
69
+ })
70
+
71
+ it("supports a custom local day start hour", () => {
72
+ expect(getSrsDayStart(
73
+ // Sat Jan 10 2026 05:59:00 GMT-0800 (Pacific Standard Time)
74
+ new Date("2026-01-10T13:59:00.000Z"),
75
+ "America/Vancouver",
76
+ 6,
77
+ // Fri Jan 09 2026 06:00:00 GMT-0800 (Pacific Standard Time)
78
+ )).toEqual(new Date("2026-01-09T14:00:00.000Z"))
79
+
80
+ expect(getSrsDayStart(
81
+ // Sat Jan 10 2026 06:00:00 GMT-0800 (Pacific Standard Time)
82
+ new Date("2026-01-10T14:00:00.000Z"),
83
+ "America/Vancouver",
84
+ 6,
85
+ // Sat Jan 10 2026 06:00:00 GMT-0800 (Pacific Standard Time)
86
+ )).toEqual(new Date("2026-01-10T14:00:00.000Z"))
87
+
88
+ expect(getSrsDayEnd(
89
+ // Sat Jan 10 2026 05:59:00 GMT-0800 (Pacific Standard Time)
90
+ new Date("2026-01-10T13:59:00.000Z"),
91
+ "America/Vancouver",
92
+ 6,
93
+ // Sat Jan 10 2026 06:00:00 GMT-0800 (Pacific Standard Time)
94
+ )).toEqual(new Date("2026-01-10T14:00:00.000Z"))
95
+
96
+ expect(isSameSrsDay(
97
+ // Sat Jan 10 2026 05:59:00 GMT-0800 (Pacific Standard Time)
98
+ new Date("2026-01-10T13:59:00.000Z"),
99
+ // Fri Jan 09 2026 06:00:00 GMT-0800 (Pacific Standard Time)
100
+ new Date("2026-01-09T14:00:00.000Z"),
101
+ "America/Vancouver",
102
+ 6,
103
+ )).toBe(true)
104
+
105
+ expect(isSameSrsDay(
106
+ // Sat Jan 10 2026 06:00:00 GMT-0800 (Pacific Standard Time)
107
+ new Date("2026-01-10T14:00:00.000Z"),
108
+ // Fri Jan 09 2026 06:00:00 GMT-0800 (Pacific Standard Time)
109
+ new Date("2026-01-09T14:00:00.000Z"),
110
+ "America/Vancouver",
111
+ 6,
112
+ )).toBe(false)
113
+
114
+ expect(differenceInSrsDays(
115
+ // Sat Jan 10 2026 05:59:00 GMT-0800 (Pacific Standard Time)
116
+ new Date("2026-01-10T13:59:00.000Z"),
117
+ // Fri Jan 09 2026 06:00:00 GMT-0800 (Pacific Standard Time)
118
+ new Date("2026-01-09T14:00:00.000Z"),
119
+ "America/Vancouver",
120
+ 6,
121
+ )).toBe(0)
122
+
123
+ expect(differenceInSrsDays(
124
+ // Sat Jan 10 2026 06:00:00 GMT-0800 (Pacific Standard Time)
125
+ new Date("2026-01-10T14:00:00.000Z"),
126
+ // Fri Jan 09 2026 06:00:00 GMT-0800 (Pacific Standard Time)
127
+ new Date("2026-01-09T14:00:00.000Z"),
128
+ "America/Vancouver",
129
+ 6,
130
+ )).toBe(1)
131
+ })
132
+ })
@@ -0,0 +1,60 @@
1
+ import { tz } from "@date-fns/tz"
2
+ import { addDays, addHours, differenceInCalendarDays, isSameDay, startOfDay, subHours } from "date-fns"
3
+
4
+ export const SRS_DAY_START_HOUR = 4
5
+
6
+ export function getSrsDayStart(
7
+ date: Date,
8
+ timezone: string,
9
+ startHour: number = SRS_DAY_START_HOUR,
10
+ ): Date {
11
+ const timezoneContext = tz(timezone)
12
+ const shiftedDate = subHours(date, startHour, { in: timezoneContext })
13
+ const shiftedDayStart = startOfDay(shiftedDate, { in: timezoneContext })
14
+
15
+ return new Date(addHours(shiftedDayStart, startHour, { in: timezoneContext }).getTime())
16
+ }
17
+
18
+ export function getSrsDayEnd(
19
+ date: Date,
20
+ timezone: string,
21
+ startHour: number = SRS_DAY_START_HOUR,
22
+ ): Date {
23
+ const timezoneContext = tz(timezone)
24
+ const shiftedDate = subHours(date, startHour, { in: timezoneContext })
25
+ const nextShiftedDayStart = addDays(startOfDay(shiftedDate, { in: timezoneContext }), 1, {
26
+ in: timezoneContext,
27
+ })
28
+
29
+ return new Date(addHours(nextShiftedDayStart, startHour, { in: timezoneContext }).getTime())
30
+ }
31
+
32
+ export function isSameSrsDay(
33
+ left: Date,
34
+ right: Date,
35
+ timezone: string,
36
+ startHour: number = SRS_DAY_START_HOUR,
37
+ ): boolean {
38
+ const timezoneContext = tz(timezone)
39
+
40
+ return isSameDay(
41
+ subHours(left, startHour, { in: timezoneContext }),
42
+ subHours(right, startHour, { in: timezoneContext }),
43
+ { in: timezoneContext },
44
+ )
45
+ }
46
+
47
+ export function differenceInSrsDays(
48
+ later: Date,
49
+ earlier: Date,
50
+ timezone: string,
51
+ startHour: number = SRS_DAY_START_HOUR,
52
+ ): number {
53
+ const timezoneContext = tz(timezone)
54
+
55
+ return differenceInCalendarDays(
56
+ subHours(later, startHour, { in: timezoneContext }),
57
+ subHours(earlier, startHour, { in: timezoneContext }),
58
+ { in: timezoneContext },
59
+ )
60
+ }
@@ -1,2 +0,0 @@
1
- export const COLUMN_MIN_WIDTH = 100
2
- export const COLUMN_MAX_WIDTH = 500