@@ -415,22 +415,40 @@ protected virtual SqlExpression ConstructDate(IReadOnlyList<SqlExpression> argum
415415
416416 protected virtual SqlExpression ConstructTime ( IReadOnlyList < SqlExpression > arguments )
417417 {
418+ SqlExpression hour , minute , second , microsecond ;
418419 if ( arguments . Count == 4 ) {
419- return ZeroTimeLiteral
420- + ( OneHourInterval * ( arguments [ 0 ] ) )
421- + ( OneMinuteInterval * ( arguments [ 1 ] ) )
422- + ( OneSecondInterval * ( arguments [ 2 ] + ( SqlDml . Cast ( arguments [ 3 ] , SqlType . Double ) / 1000 ) ) ) ;
420+ hour = arguments [ 0 ] ;
421+ minute = arguments [ 1 ] ;
422+ second = arguments [ 2 ] ;
423+ microsecond = arguments [ 3 ] * 1000 ;
423424 }
424425 else if ( arguments . Count == 1 ) {
425426 var ticks = arguments [ 0 ] ;
426- if ( SqlHelper . IsTimeSpanTicks ( ticks , out var intervalExpr ) ) {
427- return ZeroTimeLiteral + intervalExpr ;
427+ if ( SqlHelper . IsTimeSpanTicks ( ticks , out var sourceInterval ) ) {
428+ // try to optimize and reduce calculations when TimeSpan.Ticks where used for TimeOnly(ticks) ctor
429+ return SqlDml . Cast ( SqlDml . Cast ( sourceInterval , SqlType . VarChar ) , SqlType . Time ) ;
430+ }
431+ else {
432+ hour = SqlDml . Cast ( ticks / 36000000000 , SqlType . Int32 ) ;
433+ minute = SqlDml . Cast ( ( ticks / 600000000 ) % 60 , SqlType . Int32 ) ;
434+ second = SqlDml . Cast ( ( ticks / 10000000 ) % 60 , SqlType . Int32 ) ;
435+ microsecond = SqlDml . Cast ( ( ticks % 10000000 ) / 10 , SqlType . Int32 ) ;
428436 }
429- return ZeroTimeLiteral + ( ticks / SqlDml . Literal ( 10000000.0 ) * OneSecondInterval ) ;
430437 }
431438 else {
432439 throw new InvalidOperationException ( "Unsupported count of parameters" ) ;
433- }
440+ }
441+
442+ // Using string version of time allows to control hours overflow
443+ // we cannot add hours, minutes and other parts to 00:00:00.000000 time
444+ // because hours might step over 24 hours and start counting from 0.
445+ // Starting from v10 new function is in use, which controlls overflow
446+ var hourString = SqlDml . Cast ( hour , new SqlValueType ( SqlType . VarChar , 3 ) ) ;
447+ var minuteString = SqlDml . Cast ( minute , new SqlValueType ( SqlType . VarChar , 2 ) ) ;
448+ var secondString = SqlDml . Cast ( second , new SqlValueType ( SqlType . VarChar , 2 ) ) ;
449+ var microsecondString = SqlDml . Cast ( microsecond , new SqlValueType ( SqlType . VarChar , 7 ) ) ;
450+ var composedTimeString = SqlDml . Concat ( hourString , SqlDml . Literal ( ":" ) , minuteString , SqlDml . Literal ( ":" ) , secondString , SqlDml . Literal ( "." ) , microsecondString ) ;
451+ return SqlDml . Cast ( composedTimeString , SqlType . Time ) ;
434452 }
435453
436454 protected virtual SqlExpression TimeToNanoseconds ( SqlExpression time )
0 commit comments