11using System ;
2+ using System . ComponentModel ;
23using System . Globalization ;
34using System . Text . RegularExpressions ;
45using Elasticsearch . Net ;
@@ -20,8 +21,15 @@ public class Time : IComparable<Time>, IEquatable<Time>
2021 private const double MicrosecondsInAMillisecond = 10 ;
2122
2223 private static readonly Regex ExpressionRegex =
23- new Regex ( @"^(?<factor>[-+]?\d+(?:\.\d+)?)\s*(?<interval>(?:y|w|d|h|m|s|ms|nanos|micros))?$" ,
24- RegexOptions . Compiled | RegexOptions . ExplicitCapture | RegexOptions . IgnoreCase ) ;
24+ new Regex ( @"^
25+ (?<factor>[+\-]? # open factor capture, allowing optional +- signs
26+ (?:(?#numeric)(?:\d+(?:\.\d*)?)|(?:\.\d+)) #a numeric in the forms: (N, N., .N, N.N)
27+ (?:(?#exponent)e[+\-]?\d+)? #an optional exponential scientific component, E also matches here (IgnoreCase)
28+ ) # numeric and exponent fall under the factor capture
29+ \s{0,10} #optional spaces (sanity checked for max 10 repetitions)
30+ (?<interval>(?:y|w|d|h|m|s|ms|nanos|micros))? #optional interval indicator
31+ $" ,
32+ RegexOptions . Compiled | RegexOptions . ExplicitCapture | RegexOptions . IgnoreCase | RegexOptions . IgnorePatternWhitespace ) ;
2533
2634 private static double FLOAT_TOLERANCE = 0.0000001 ;
2735
@@ -47,7 +55,7 @@ public static implicit operator Time(double milliseconds)
4755 public static Time MinusOne { get ; } = new Time ( - 1 , true ) ;
4856 public static Time Zero { get ; } = new Time ( 0 , true ) ;
4957
50- protected Time ( int specialFactor , bool specialValue )
58+ private Time ( int specialFactor , bool specialValue )
5159 {
5260 if ( ! specialValue ) throw new ArgumentException ( "this constructor is only for static TimeValues" ) ;
5361 this . StaticTimeValue = specialFactor ;
@@ -79,8 +87,11 @@ private void ParseExpression(string timeUnit)
7987 {
8088 var match = ExpressionRegex . Match ( timeUnit ) ;
8189 if ( ! match . Success ) throw new ArgumentException ( $ "Time expression '{ timeUnit } ' string is invalid", nameof ( timeUnit ) ) ;
90+ var factor = match . Groups [ "factor" ] . Value ;
91+ if ( ! double . TryParse ( factor , NumberStyles . Any , CultureInfo . InvariantCulture , out double f ) )
92+ throw new ArgumentException ( $ "Time expression '{ timeUnit } ' contains invalid factor: { factor } ", nameof ( timeUnit ) ) ;
8293
83- this . Factor = double . Parse ( match . Groups [ "factor" ] . Value , CultureInfo . InvariantCulture ) ;
94+ this . Factor = f ;
8495 var interval = match . Groups [ "interval" ] . Success ? match . Groups [ "interval" ] . Value : null ;
8596 switch ( interval )
8697 {
@@ -117,7 +128,7 @@ public int CompareTo(Time other)
117128 // ReSharper enable PossibleInvalidOperationException
118129 } ;
119130
120- if ( this . ApproximateMilliseconds == other . ApproximateMilliseconds ) return 0 ;
131+ if ( Math . Abs ( this . ApproximateMilliseconds - other . ApproximateMilliseconds ) < FLOAT_TOLERANCE ) return 0 ;
121132 if ( this . ApproximateMilliseconds < other . ApproximateMilliseconds ) return - 1 ;
122133 return 1 ;
123134 }
@@ -196,7 +207,9 @@ public override string ToString()
196207 return this . StaticTimeValue . Value . ToString ( ) ;
197208 if ( ! this . Factor . HasValue )
198209 return "<bad Time object should not happen>" ;
199- var factor = this . Factor . Value . ToString ( "0.##" , CultureInfo . InvariantCulture ) ;
210+
211+ var mantissa = ExponentFormat ( this . Factor . Value ) ;
212+ var factor = this . Factor . Value . ToString ( "0." + mantissa , CultureInfo . InvariantCulture ) ;
200213 return ( this . Interval . HasValue ) ? factor + this . Interval . Value . GetStringValue ( ) : factor ;
201214 }
202215
@@ -307,5 +320,15 @@ private void Reduce(double ms)
307320 Interval = TimeUnit . Millisecond ;
308321 }
309322 }
323+
324+ private static string ExponentFormat ( double d )
325+ {
326+ // Translate the double into sign, exponent and mantissa.
327+ var bits = BitConverter . DoubleToInt64Bits ( d ) ;
328+ // Note that the shift is sign-extended, hence the test against -1 not 1
329+ var exponent = ( int ) ( ( bits >> 52 ) & 0x7ffL ) ;
330+ return new string ( '#' , Math . Max ( 2 , exponent ) ) ;
331+ }
332+
310333 }
311334}
0 commit comments