@@ -76,6 +76,16 @@ private static string FormatTimeSpan(TimeSpan timeSpan, List<string> tokens, Cul
7676 // NOTE/TODO: assumes there is exactly one [hh], [mm] or [ss] using the integer part of TimeSpan.TotalXXX when formatting.
7777 // The timeSpan input is then truncated to the remainder fraction, which is used to format mm and/or ss.
7878 var result = new StringBuilder ( ) ;
79+ var containsMilliseconds = false ;
80+ for ( var i = tokens . Count - 1 ; i >= 0 ; i -- )
81+ {
82+ if ( tokens [ i ] . StartsWith ( ".0" ) )
83+ {
84+ containsMilliseconds = true ;
85+ break ;
86+ }
87+ }
88+
7989 for ( var i = 0 ; i < tokens . Count ; i ++ )
8090 {
8191 var token = tokens [ i ] ;
@@ -89,6 +99,15 @@ private static string FormatTimeSpan(TimeSpan timeSpan, List<string> tokens, Cul
8999 else if ( token . StartsWith ( "s" , StringComparison . OrdinalIgnoreCase ) )
90100 {
91101 var value = timeSpan . Seconds ;
102+ if ( ! containsMilliseconds )
103+ {
104+ var roundedMilliseconds = GetRoundedMilliseconds ( timeSpan ) ;
105+
106+ if ( roundedMilliseconds >= 500 )
107+ {
108+ value += 1 ;
109+ }
110+ }
92111 var digits = token . Length ;
93112 result . Append ( value . ToString ( "D" + digits ) ) ;
94113 }
@@ -114,7 +133,7 @@ private static string FormatTimeSpan(TimeSpan timeSpan, List<string> tokens, Cul
114133 timeSpan = TimeSpan . FromSeconds ( timeSpan . TotalSeconds - value ) ;
115134 }
116135 else if ( token . StartsWith ( ".0" ) ) {
117- var value = timeSpan . Milliseconds ;
136+ var value = GetRoundedMilliseconds ( timeSpan ) ;
118137 var digits = token . Length - 1 ;
119138 result . Append ( "." + value . ToString ( "D" + digits ) ) ;
120139 }
@@ -127,6 +146,17 @@ private static string FormatTimeSpan(TimeSpan timeSpan, List<string> tokens, Cul
127146 return result . ToString ( ) ;
128147 }
129148
149+ /// <summary>
150+ /// In .Net Core 3.0, TimeSpan is stored with microseconds. As a result, 31:44.500 may be presented as 31:44.499999,
151+ /// and TimeSpan.Microseconds will return 499 instead of 500. This method returns a number of microseconds rounded
152+ /// to a whole.
153+ /// </summary>
154+ private static int GetRoundedMilliseconds ( TimeSpan timeSpan )
155+ {
156+ var milliseconds = timeSpan . TotalMilliseconds - ( int ) timeSpan . TotalSeconds * 1000 ;
157+ return ( int ) Math . Round ( milliseconds ) ;
158+ }
159+
130160 private static string FormatDate ( DateTime date , List < string > tokens , CultureInfo culture )
131161 {
132162 var containsAmPm = ContainsAmPm ( tokens ) ;
0 commit comments