1- import { isPast , safeParseDate } from "@hypr/utils" ;
2-
3- interface DateParts {
4- year : number ;
5- month : number ;
6- day : number ;
7- }
8-
9- function getDatePartsInTimezone ( date : Date , timezone ?: string ) : DateParts {
10- const formatter = new Intl . DateTimeFormat ( "en-CA" , {
11- timeZone : timezone ,
12- year : "numeric" ,
13- month : "2-digit" ,
14- day : "2-digit" ,
15- } ) ;
16- const formatted = formatter . format ( date ) ;
17- const [ year , month , day ] = formatted . split ( "-" ) . map ( Number ) ;
18- return { year, month, day } ;
19- }
20-
21- function datePartsToUtcMidnight ( parts : DateParts ) : number {
22- return Date . UTC ( parts . year , parts . month - 1 , parts . day ) ;
23- }
24-
25- function differenceInCalendarDaysInTimezone (
26- dateLeft : Date ,
27- dateRight : Date ,
28- timezone ?: string ,
29- ) : number {
30- const leftParts = getDatePartsInTimezone ( dateLeft , timezone ) ;
31- const rightParts = getDatePartsInTimezone ( dateRight , timezone ) ;
32- const leftUtc = datePartsToUtcMidnight ( leftParts ) ;
33- const rightUtc = datePartsToUtcMidnight ( rightParts ) ;
34- return Math . round ( ( leftUtc - rightUtc ) / ( 1000 * 60 * 60 * 24 ) ) ;
35- }
36-
37- function differenceInCalendarMonthsInTimezone (
38- dateLeft : Date ,
39- dateRight : Date ,
40- timezone ?: string ,
41- ) : number {
42- const leftParts = getDatePartsInTimezone ( dateLeft , timezone ) ;
43- const rightParts = getDatePartsInTimezone ( dateRight , timezone ) ;
44- return (
45- ( leftParts . year - rightParts . year ) * 12 +
46- ( leftParts . month - rightParts . month )
47- ) ;
48- }
49-
50- function getSortKeyForDateInTimezone ( date : Date , timezone ?: string ) : number {
51- const parts = getDatePartsInTimezone ( date , timezone ) ;
52- return datePartsToUtcMidnight ( parts ) ;
1+ import {
2+ differenceInCalendarDays ,
3+ differenceInCalendarMonths ,
4+ isPast ,
5+ safeParseDate ,
6+ startOfDay ,
7+ startOfMonth ,
8+ TZDate ,
9+ } from "@hypr/utils" ;
10+
11+ function toTZ ( date : Date , timezone ?: string ) : Date {
12+ return timezone ? new TZDate ( date , timezone ) : date ;
5313}
5414
5515// comes from QUERIES.timelineEvents
@@ -109,8 +69,10 @@ export function getBucketInfo(
10969 precision : TimelinePrecision ;
11070} {
11171 const now = new Date ( ) ;
112- const daysDiff = differenceInCalendarDaysInTimezone ( date , now , timezone ) ;
113- const sortKey = getSortKeyForDateInTimezone ( date , timezone ) ;
72+ const tzDate = toTZ ( date , timezone ) ;
73+ const tzNow = toTZ ( now , timezone ) ;
74+ const daysDiff = differenceInCalendarDays ( tzDate , tzNow ) ;
75+ const sortKey = startOfDay ( tzDate ) . getTime ( ) ;
11476 const absDays = Math . abs ( daysDiff ) ;
11577
11678 if ( daysDiff === 0 ) {
@@ -136,7 +98,7 @@ export function getBucketInfo(
13698 const weekRangeEnd = new Date (
13799 now . getTime ( ) - weekRangeEndDay * 24 * 60 * 60 * 1000 ,
138100 ) ;
139- const weekSortKey = getSortKeyForDateInTimezone ( weekRangeEnd , timezone ) ;
101+ const weekSortKey = startOfDay ( toTZ ( weekRangeEnd , timezone ) ) . getTime ( ) ;
140102
141103 return {
142104 label : weeks === 1 ? "a week ago" : `${ weeks } weeks ago` ,
@@ -145,25 +107,17 @@ export function getBucketInfo(
145107 } ;
146108 }
147109
148- let months = Math . abs (
149- differenceInCalendarMonthsInTimezone ( date , now , timezone ) ,
150- ) ;
110+ let months = Math . abs ( differenceInCalendarMonths ( tzDate , tzNow ) ) ;
151111 if ( months === 0 ) {
152112 months = 1 ;
153113 }
154- const targetParts = getDatePartsInTimezone ( date , timezone ) ;
155- const monthStartKey = datePartsToUtcMidnight ( {
156- year : targetParts . year ,
157- month : targetParts . month ,
158- day : 1 ,
159- } ) ;
114+ const monthStartKey = startOfMonth ( tzDate ) . getTime ( ) ;
160115 const lastDayInMonthBucket = new Date (
161116 now . getTime ( ) - 28 * 24 * 60 * 60 * 1000 ,
162117 ) ;
163- const lastDayKey = getSortKeyForDateInTimezone (
164- lastDayInMonthBucket ,
165- timezone ,
166- ) ;
118+ const lastDayKey = startOfDay (
119+ toTZ ( lastDayInMonthBucket , timezone ) ,
120+ ) . getTime ( ) ;
167121 const monthSortKey = Math . min ( monthStartKey , lastDayKey ) ;
168122 return {
169123 label : months === 1 ? "a month ago" : `${ months } months ago` ,
@@ -182,7 +136,7 @@ export function getBucketInfo(
182136 const weekRangeStart = new Date (
183137 now . getTime ( ) + weekRangeStartDay * 24 * 60 * 60 * 1000 ,
184138 ) ;
185- const weekSortKey = getSortKeyForDateInTimezone ( weekRangeStart , timezone ) ;
139+ const weekSortKey = startOfDay ( toTZ ( weekRangeStart , timezone ) ) . getTime ( ) ;
186140
187141 return {
188142 label : weeks === 1 ? "next week" : `in ${ weeks } weeks` ,
@@ -191,23 +145,17 @@ export function getBucketInfo(
191145 } ;
192146 }
193147
194- let months = differenceInCalendarMonthsInTimezone ( date , now , timezone ) ;
148+ let months = differenceInCalendarMonths ( tzDate , tzNow ) ;
195149 if ( months === 0 ) {
196150 months = 1 ;
197151 }
198- const targetParts = getDatePartsInTimezone ( date , timezone ) ;
199- const monthStartKey = datePartsToUtcMidnight ( {
200- year : targetParts . year ,
201- month : targetParts . month ,
202- day : 1 ,
203- } ) ;
152+ const monthStartKey = startOfMonth ( tzDate ) . getTime ( ) ;
204153 const firstDayInMonthBucket = new Date (
205154 now . getTime ( ) + 28 * 24 * 60 * 60 * 1000 ,
206155 ) ;
207- const firstDayKey = getSortKeyForDateInTimezone (
208- firstDayInMonthBucket ,
209- timezone ,
210- ) ;
156+ const firstDayKey = startOfDay (
157+ toTZ ( firstDayInMonthBucket , timezone ) ,
158+ ) . getTime ( ) ;
211159 const monthSortKey = Math . max ( monthStartKey , firstDayKey ) ;
212160 return {
213161 label : months === 1 ? "next month" : `in ${ months } months` ,
0 commit comments