@@ -33,9 +33,8 @@ export function getTime(
3333 const dstOffset = normalizeZero (
3434 dst ? utcOffset . seconds ( ) - utcOffsetRaw . seconds ( ) : 0 ,
3535 ) ;
36- const dstTransitions = dst
37- ? getDstTransitions ( timezone . name ( ) , dateTime . year ( ) )
38- : { dstStart : null , dstEnd : null } ;
36+ const dstTransitions = getDstTransitions ( timezone . name ( ) , dateTime , dst ) ;
37+
3938 const dstFrom = dstTransitions . dstStart
4039 ? toISOWithoutFractionalZeros ( dstTransitions . dstStart . toIsoString ( ) )
4140 : null ;
@@ -62,38 +61,63 @@ export function getTime(
6261 } ;
6362}
6463
64+ /**
65+ * Get DST transition dates based on current time and DST status
66+ *
67+ * When DST is active:
68+ * - dstStart: when current DST period started
69+ * - dstEnd: when current DST period will end
70+ *
71+ * When DST is NOT active:
72+ * - dstStart: when next DST period will begin (future)
73+ * - dstEnd: when last DST period ended (past)
74+ */
6575function getDstTransitions (
6676 zoneName : string ,
67- year : number ,
77+ currentTime : tc . DateTime ,
78+ isDstActive : boolean ,
6879) : { dstStart : tc . DateTime | null ; dstEnd : tc . DateTime | null } {
6980 const db = tc . TzDatabase . instance ( ) ;
7081
7182 if ( ! db . hasDst ( zoneName ) ) {
7283 return { dstStart : null , dstEnd : null } ;
7384 }
7485
75- // Start from beginning of year
76- const startOfYear = new tc . DateTime (
77- year ,
78- 1 ,
79- 1 ,
80- 0 ,
81- 0 ,
82- 0 ,
83- 0 ,
84- tc . utc ( ) ,
85- ) . unixUtcMillis ( ) ;
86-
87- // Find next two DST changes from start of year
88- const firstChange = db . nextDstChange ( zoneName , startOfYear ) ;
89- const secondChange = firstChange
90- ? db . nextDstChange ( zoneName , firstChange )
86+ const currentMillis = currentTime . unixUtcMillis ( ) ;
87+
88+ // Find the next DST transition from current time.
89+ const nextChange = db . nextDstChange ( zoneName , currentMillis ) ;
90+
91+ // Find the previous DST transition by searching from one year ago.
92+ const oneYearAgo = currentTime . add ( - 1 , tc . TimeUnit . Year ) . unixUtcMillis ( ) ;
93+ let prevChange = db . nextDstChange ( zoneName , oneYearAgo ) ;
94+
95+ // Keep looking forward until we find the transition just before current time.
96+ while ( prevChange && prevChange < currentMillis ) {
97+ const nextTransition = db . nextDstChange ( zoneName , prevChange ) ;
98+ if ( nextTransition && nextTransition < currentMillis ) {
99+ prevChange = nextTransition ;
100+ } else {
101+ break ;
102+ }
103+ }
104+
105+ // Convert to DateTime objects.
106+ const prevDateTime = prevChange
107+ ? new tc . DateTime ( prevChange , tc . utc ( ) )
108+ : null ;
109+ const nextDateTime = nextChange
110+ ? new tc . DateTime ( nextChange , tc . utc ( ) )
91111 : null ;
92112
93- return {
94- dstStart : firstChange ? new tc . DateTime ( firstChange , tc . utc ( ) ) : null ,
95- dstEnd : secondChange ? new tc . DateTime ( secondChange , tc . utc ( ) ) : null ,
96- } ;
113+ // Return based on DST status.
114+ if ( isDstActive ) {
115+ // DST is active: prev = when it started, next = when it will end.
116+ return { dstStart : prevDateTime , dstEnd : nextDateTime } ;
117+ } else {
118+ // DST is NOT active: prev = when it last ended, next = when it will begin.
119+ return { dstStart : nextDateTime , dstEnd : prevDateTime } ;
120+ }
97121}
98122
99123function getZoneAbbreviation ( dateTime : tc . DateTime , utcOffset : tc . Duration ) {
0 commit comments