Skip to content

Commit 766833c

Browse files
authored
Fix/5.x whole time units (#2976)
* Whole time units from TimeSpan This commit changes the implementation of Time within the client for better consistency with Elasticsearch's TimeValue. The Time type in NEST 5.x is used to represent both Elasticsearch's TimeValue (which allows from nanos up to days as unit), and as time modifiers within DateMath expressions, for which Elasticsearch accepts units of y (years) M (months), w (weeks), d (days), h/H (hours), m (minutes) and s (seconds). - When converting from a TimeSpan to Time, the serialized value is a whole number with the largest unit of days. This fixes the implementation to be in line with Elasticsearch 5.0+ with elastic/elasticsearch#19102 where weeks was removed as a supported unit for TimeValue. - When constructing a Time using the constructor that takes a double of milliseconds, make the implementation consistent with the implicit conversion from double implementation; in the case of -1, both should be Time.MinusOne and the case of 0, both should be Time.Zero. If needing to express -1ms or 0ms, the constructor taking a factor and unit, or the constructor taking a string value with unit should be used. - When constructing a Time from double or TimeSpan, try to reduce the value to a whole number factor and largest represented unit (up to unit of days). For values smaller than 1 nanosecond, retain the factor as a fraction of nanoseconds. - When converting a Time to a TimeSpan, round the value to the nearest TimeSpan tick for microseconds and nanoseconds, and milliseconds for all other units. - When converting to a Time within a DateMath expression using Time.ToFirstUnitYieldingInteger(), when the value is fractional nanoseconds, round to the nearest nanosecond. Although this method is only used within the client for DateMath expressions and can return times with units smaller than a second (the smallest unit that DateMath within Elasticsearch accepts), the method is public so could be used by consumers for purposes other than DateMath. Because of this, don't break the implementation for units smaller than one second. - Allow the implicit conversion from string and the constructor that takes a string to continue to accept fractional units, which can be returned from Elasticsearch as per TimeValue's toString implementation https://github.com/elastic/elasticsearch/blob/f2501130399f6e3788e110d74dd62b3aad66804a/core/src/main/java/org/elasticsearch/common/unit/TimeValue.java#L253-L290 - Update documentation Closes #2818 * Update DateMath documentation * Additional Time unit tests Add XML documentation to Time methods to describe what ToTimeSpan() and ToFirstUnitYieldingInteger() will do Simplify multiplication by reciprocals * Support months and weeks in ToFirstUnitYieldingInteger() ToFirstUnitYieldingInteger() is used in NEST only within DateMath expressions. Support whole values in months and weeks.
1 parent d58e712 commit 766833c

File tree

5 files changed

+583
-316
lines changed

5 files changed

+583
-316
lines changed

docs/common-options/date-math/date-math-expressions.asciidoc

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -137,31 +137,38 @@ Expect("2015-05-05T00:00:00||+1d-1m").WhenSerializing(
137137

138138
==== Fractional times
139139

140-
DateMath expressions do not support fractional numbers so unlike `Time` DateMath will
141-
pick the biggest integer unit it can represent
140+
DateMath expressions do not support fractional numbers so will
141+
pick the largest unit in which the number can be expressed as an integer
142142

143143
[source,csharp]
144144
----
145-
Expect("now+25h").WhenSerializing(
146-
Nest.DateMath.Now.Add(TimeSpan.FromHours(25)));
147-
----
148-
149-
where as `Time` on its own serializes like this
150-
151-
[source,csharp]
152-
----
153-
Expect("1.04166666666667d").WhenSerializing(new Time(TimeSpan.FromHours(25)));
145+
Expect("now+25h")
146+
.WhenSerializing(Nest.DateMath.Now.Add(TimeSpan.FromHours(25)))
147+
.WhenSerializing(Nest.DateMath.Now.Add(90000000))
148+
.WhenSerializing(Nest.DateMath.Now.Add(new Time(25, Nest.TimeUnit.Hour)))
149+
.WhenSerializing(Nest.DateMath.Now.Add("25h"));
154150
155151
Expect("now+90001s").WhenSerializing(
156152
Nest.DateMath.Now.Add(TimeSpan.FromHours(25).Add(TimeSpan.FromSeconds(1))));
157153
158154
Expect("now+90000001ms").WhenSerializing(
159155
Nest.DateMath.Now.Add(TimeSpan.FromHours(25).Add(TimeSpan.FromMilliseconds(1))));
160156
161-
Expect("now+1y").WhenSerializing(
162-
Nest.DateMath.Now.Add("1y"));
157+
Expect("now+1y")
158+
.WhenSerializing(Nest.DateMath.Now.Add("1y"))
159+
.WhenSerializing(Nest.DateMath.Now.Add(new Time(1, Nest.TimeUnit.Year)));
160+
161+
Expect("now+6M")
162+
.WhenSerializing(Nest.DateMath.Now.Add("6M"))
163+
.WhenSerializing(Nest.DateMath.Now.Add("0.5y"))
164+
.WhenSerializing(Nest.DateMath.Now.Add(new Time(0.5, Nest.TimeUnit.Year)))
165+
.WhenSerializing(Nest.DateMath.Now.Add(new Time(6, Nest.TimeUnit.Month)));
166+
167+
Expect("now+364d")
168+
.WhenSerializing(Nest.DateMath.Now.Add(TimeSpan.FromDays(7 * 52)));
163169
164-
Expect("now+52w").WhenSerializing(
165-
Nest.DateMath.Now.Add(TimeSpan.FromDays(7 * 52)));
170+
Expect("now+52w")
171+
.WhenSerializing(Nest.DateMath.Now.Add(new Time("52w")))
172+
.WhenSerializing(Nest.DateMath.Now.Add(new Time(52, Nest.TimeUnit.Week)));
166173
----
167174

0 commit comments

Comments
 (0)