@@ -24,11 +24,6 @@ internal class Compiler : SqlCompiler
2424 protected const long MillisecondsPerDay = 86400000 ;
2525 protected const long MillisecondsPerSecond = 1000L ;
2626
27- //protected static readonly long NanosecondsPerDay = TimeSpan.FromDays(1).Ticks * 100;
28- //protected static readonly long NanosecondsPerSecond = 1000000000;
29- //protected static readonly long NanosecondsPerMillisecond = 1000000;
30- //protected static readonly long MillisecondsPerDay = (long) TimeSpan.FromDays(1).TotalMilliseconds;
31- //protected static readonly long MillisecondsPerSecond = 1000L;
3227 private bool case_SqlDateTimePart_DayOfYear ;
3328 private bool case_SqlDateTimePart_Second ;
3429
@@ -326,26 +321,35 @@ protected virtual SqlExpression ConstructDate(IReadOnlyList<SqlExpression> argum
326321
327322 protected virtual SqlExpression ConstructTime ( IReadOnlyList < SqlExpression > arguments )
328323 {
324+ SqlExpression hour , minute , second , millisecond ;
329325 if ( arguments . Count == 4 ) {
330- return DateAddMillisecond (
331- DateAddSecond (
332- DateAddMinute (
333- DateAddHour (
334- SqlDml . Cast ( SqlDml . Literal ( new TimeOnly ( 0 , 0 , 0 ) ) , SqlType . Time ) ,
335- arguments [ 0 ] ) ,
336- arguments [ 1 ] ) ,
337- arguments [ 2 ] ) ,
338- arguments [ 3 ] ) ;
326+ hour = arguments [ 0 ] ;
327+ minute = arguments [ 1 ] ;
328+ second = arguments [ 2 ] ;
329+ millisecond = arguments [ 3 ] * 10 ;
339330 }
340331 else if ( arguments . Count == 1 ) {
341332 var ticks = arguments [ 0 ] ;
342- return TimeAddInterval (
343- SqlDml . Cast ( SqlDml . Literal ( new TimeOnly ( 0 , 0 , 0 , 0 ) ) , SqlType . Time ) ,
344- SqlHelper . IsTimeSpanTicks ( ticks , out var sourceInterval ) ? sourceInterval : ticks * 100 ) ;
333+ // try to optimize and reduce calculations when TimeSpan.Ticks where used for TimeOnly(ticks) ctor
334+ ticks = SqlHelper . IsTimeSpanTicks ( ticks , out var sourceInterval ) ? sourceInterval / 100 : ticks ;
335+ hour = SqlDml . Cast ( ticks / 36000000000 , SqlType . Int32 ) ;
336+ minute = SqlDml . Cast ( ( ticks / 600000000 ) % 60 , SqlType . Int32 ) ;
337+ second = SqlDml . Cast ( ( ticks / 10000000 ) % 60 , SqlType . Int32 ) ;
338+ millisecond = SqlDml . Cast ( ( ticks % 10000000 ) / 1000 , SqlType . Int32 ) ;
345339 }
346340 else {
347341 throw new InvalidOperationException ( "Unsupported count of parameters" ) ;
348342 }
343+
344+ // using string version of time allows to control hours overflow
345+ // we cannot add hours, minutes and other parts to 00:00:00.0000 time
346+ // because hours might step over 24 hours and start counting from 0.
347+ var hourString = SqlDml . Cast ( hour , new SqlValueType ( SqlType . VarChar , 3 ) ) ;
348+ var minuteString = SqlDml . Cast ( minute , new SqlValueType ( SqlType . VarChar , 2 ) ) ;
349+ var secondString = SqlDml . Cast ( second , new SqlValueType ( SqlType . VarChar , 2 ) ) ;
350+ var millisecondString = SqlDml . Cast ( millisecond , new SqlValueType ( SqlType . VarChar , 4 ) ) ;
351+ var composedTimeString = SqlDml . Concat ( hourString , SqlDml . Literal ( ":" ) , minuteString , SqlDml . Literal ( ":" ) , secondString , SqlDml . Literal ( "." ) , millisecondString ) ;
352+ return SqlDml . Cast ( composedTimeString , SqlType . Time ) ;
349353 }
350354
351355 protected virtual SqlExpression TimeToNanoseconds ( SqlExpression time )
0 commit comments