1
1
using System ;
2
+ using System . ComponentModel ;
2
3
using System . Globalization ;
3
4
using System . Text . RegularExpressions ;
4
5
using Elasticsearch . Net ;
@@ -20,8 +21,15 @@ public class Time : IComparable<Time>, IEquatable<Time>
20
21
private const double MicrosecondsInAMillisecond = 10 ;
21
22
22
23
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 ) ;
25
33
26
34
private static double FLOAT_TOLERANCE = 0.0000001 ;
27
35
@@ -47,7 +55,7 @@ public static implicit operator Time(double milliseconds)
47
55
public static Time MinusOne { get ; } = new Time ( - 1 , true ) ;
48
56
public static Time Zero { get ; } = new Time ( 0 , true ) ;
49
57
50
- protected Time ( int specialFactor , bool specialValue )
58
+ private Time ( int specialFactor , bool specialValue )
51
59
{
52
60
if ( ! specialValue ) throw new ArgumentException ( "this constructor is only for static TimeValues" ) ;
53
61
this . StaticTimeValue = specialFactor ;
@@ -79,8 +87,11 @@ private void ParseExpression(string timeUnit)
79
87
{
80
88
var match = ExpressionRegex . Match ( timeUnit ) ;
81
89
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 ) ) ;
82
93
83
- this . Factor = double . Parse ( match . Groups [ "factor" ] . Value , CultureInfo . InvariantCulture ) ;
94
+ this . Factor = f ;
84
95
var interval = match . Groups [ "interval" ] . Success ? match . Groups [ "interval" ] . Value : null ;
85
96
switch ( interval )
86
97
{
@@ -117,7 +128,7 @@ public int CompareTo(Time other)
117
128
// ReSharper enable PossibleInvalidOperationException
118
129
} ;
119
130
120
- if ( this . ApproximateMilliseconds == other . ApproximateMilliseconds ) return 0 ;
131
+ if ( Math . Abs ( this . ApproximateMilliseconds - other . ApproximateMilliseconds ) < FLOAT_TOLERANCE ) return 0 ;
121
132
if ( this . ApproximateMilliseconds < other . ApproximateMilliseconds ) return - 1 ;
122
133
return 1 ;
123
134
}
@@ -196,7 +207,9 @@ public override string ToString()
196
207
return this . StaticTimeValue . Value . ToString ( ) ;
197
208
if ( ! this . Factor . HasValue )
198
209
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 ) ;
200
213
return ( this . Interval . HasValue ) ? factor + this . Interval . Value . GetStringValue ( ) : factor ;
201
214
}
202
215
@@ -307,5 +320,15 @@ private void Reduce(double ms)
307
320
Interval = TimeUnit . Millisecond ;
308
321
}
309
322
}
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
+
310
333
}
311
334
}
0 commit comments