@@ -90,7 +90,12 @@ export class MssqlQuery extends BaseQuery {
9090 }
9191
9292 public convertTz ( field ) {
93- return `TODATETIMEOFFSET(${ field } , '${ moment ( ) . tz ( this . timezone ) . format ( 'Z' ) } ')` ;
93+ const offset = moment ( ) . tz ( this . timezone ) . format ( 'Z' ) ;
94+
95+ // 1. Treating the field as UTC (add '+00:00' offset)
96+ // 2. Switch to target timezone offset
97+ // 3. Cast to DATETIME2 to get naive timestamp in target timezone
98+ return `CAST(SWITCHOFFSET(TODATETIMEOFFSET(${ field } , '+00:00'), '${ offset } ') AS DATETIME2)` ;
9499 }
95100
96101 public timeStampCast ( value : string ) {
@@ -106,21 +111,24 @@ export class MssqlQuery extends BaseQuery {
106111 }
107112
108113 /**
109- * Returns sql for source expression floored to timestamps aligned with
110- * intervals relative to origin timestamp point.
111- * The formula operates with seconds diffs so it won't produce human-expected dates aligned with offset date parts.
114+ * Returns SQL for source expression floored to timestamps aligned with
115+ * intervals relative to the origin timestamp point.
116+ * The formula operates with seconds diffs, so it won't produce human-expected dates aligned with offset date parts.
112117 */
113118 public dateBin ( interval : string , source : string , origin : string ) : string {
119+ // Both source and origin are now DATETIME2 in the query timezone (naive timestamps),
120+ // ensuring their in the same timezone context for correct date bin calculation.
121+ const originAligned = this . dateTimeCast ( `'${ origin } '` ) ;
114122 const beginOfTime = this . dateTimeCast ( 'DATEFROMPARTS(1970, 1, 1)' ) ;
115123 const timeUnit = this . diffTimeUnitForInterval ( interval ) ;
116124
117125 // Need to explicitly cast one argument of floor to float to trigger correct sign logic
118126 return `DATEADD(${ timeUnit } ,
119127 FLOOR(
120- CAST(DATEDIFF(${ timeUnit } , ${ this . dateTimeCast ( `' ${ origin } '` ) } , ${ source } ) AS FLOAT) /
128+ CAST(DATEDIFF(${ timeUnit } , ${ originAligned } , ${ source } ) AS FLOAT) /
121129 DATEDIFF(${ timeUnit } , ${ beginOfTime } , ${ this . addInterval ( beginOfTime , interval ) } )
122130 ) * DATEDIFF(${ timeUnit } , ${ beginOfTime } , ${ this . addInterval ( beginOfTime , interval ) } ),
123- ${ this . dateTimeCast ( `' ${ origin } '` ) }
131+ ${ originAligned }
124132 )` ;
125133 }
126134
0 commit comments