# Time units

edit

## Time units

edit

Whenever durations need to be specified, eg for a timeout parameter, the duration can be specified as a whole number representing time in milliseconds, or as a time value like `2d` for 2 days.

NEST uses a `Time` type to strongly type this and there are several ways to construct one.

### Constructor

edit

The most straight forward way to construct a `Time` is through its constructor

```var unitString = new Time("2d");
var unitComposed = new Time(2, Nest.TimeUnit.Day);
var unitTimeSpan = new Time(TimeSpan.FromDays(2));
var unitMilliseconds = new Time(1000 * 60 * 60 * 24 * 2);```

When serializing Time constructed from

• a string
• milliseconds (as a double)
• composition of factor and interval
• a `TimeSpan`

the expression will be serialized to a time unit string composed of the factor and interval e.g. `2d`

```Expect("2d")
.WhenSerializing(unitString)
.WhenSerializing(unitComposed)
.WhenSerializing(unitTimeSpan)
.WhenSerializing(unitMilliseconds);```

The `Milliseconds` property on `Time` is calculated even when not using the constructor that takes a `double`

```unitMilliseconds.Milliseconds.Should().Be(1000*60*60*24*2);
unitComposed.Milliseconds.Should().Be(1000*60*60*24*2);
unitTimeSpan.Milliseconds.Should().Be(1000*60*60*24*2);
unitString.Milliseconds.Should().Be(1000*60*60*24*2);```

### Implicit conversion

edit

There are implicit conversions from `string`, `TimeSpan` and `double` to an instance of `Time`, making them easier to work with

```Time oneAndHalfYear = "1.5y";
Time fourteenDays = TimeSpan.FromDays(14);
Time twoDays = 1000*60*60*24*2;

Expect("1.5y").WhenSerializing(oneAndHalfYear);
Expect("14d").WhenSerializing(fourteenDays);
Expect("2d").WhenSerializing(twoDays);```

### Equality and Comparison

edit

Milliseconds are calculated even when values are not passed as `double` milliseconds

```Time fourteenDays = TimeSpan.FromDays(14);
fourteenDays.Milliseconds.Should().Be(1209600000);```

When dealing with years or months however, whose millsecond value cannot be calculated accurately, `Milliseconds` will be -1. This is because they are not fixed durations. For example

• 30 vs. 31 vs. 28 vs. 29 days in a month
• 365 vs. 366 days in a year
```Time oneAndHalfYear = "1.5y";
oneAndHalfYear.Milliseconds.Should().Be(-1);```

This allows you to do comparisons on the expressions

```Time twoDays = 1000*60*60*24*2;

oneAndHalfYear.Should().BeGreaterThan(fourteenDays);
(oneAndHalfYear > fourteenDays).Should().BeTrue();
(oneAndHalfYear >= fourteenDays).Should().BeTrue();
(twoDays != null).Should().BeTrue();
(twoDays >= new Time("2d")).Should().BeTrue();

twoDays.Should().BeLessThan(fourteenDays);
(twoDays < fourteenDays).Should().BeTrue();
(twoDays <= fourteenDays).Should().BeTrue();
(twoDays <= new Time("2d")).Should().BeTrue();```

And assert equality

```twoDays.Should().Be(new Time("2d"));
(twoDays == new Time("2d")).Should().BeTrue();
(twoDays != new Time("2.1d")).Should().BeTrue();
(new Time("2.1d") == new Time(TimeSpan.FromDays(2.1))).Should().BeTrue();```

Equality has down to 1/10 nanosecond precision

```Time oneNanosecond = new Time(1, Nest.TimeUnit.Nanoseconds);
Time onePointNoughtNineNanoseconds = "1.09nanos";
Time onePointOneNanoseconds = "1.1nanos";

(oneNanosecond == onePointNoughtNineNanoseconds).Should().BeTrue();
(oneNanosecond == onePointOneNanoseconds).Should().BeFalse();```

### Special Time values

edit

Elasticsearch has two special values that can sometimes be passed where a `Time` is accepted

• `0` represented as `Time.Zero`
• `-1` represented as `Time.MinusOne`

The following are all equal to `Time.MinusOne`

```Time.MinusOne.Should().Be(Time.MinusOne);
new Time("-1").Should().Be(Time.MinusOne);
new Time(-1).Should().Be(Time.MinusOne);
((Time) (-1)).Should().Be(Time.MinusOne);
((Time) "-1").Should().Be(Time.MinusOne);
((Time) (-1)).Should().Be((Time) "-1");```

Similarly, the following are all equal to `Time.Zero`

```Time.Zero.Should().Be(Time.Zero);
new Time("0").Should().Be(Time.Zero);
new Time(0).Should().Be(Time.Zero);
((Time) 0).Should().Be(Time.Zero);
((Time) "0").Should().Be(Time.Zero);
((Time) 0).Should().Be((Time) "0");```

Special Time values `0` and `-1` can be compared against other Time values although admittedly, this is a tad nonsensical.

```var twoDays = new Time(2, Nest.TimeUnit.Day);
Time.MinusOne.Should().BeLessThan(Time.Zero);
Time.Zero.Should().BeGreaterThan(Time.MinusOne);
Time.Zero.Should().BeLessThan(twoDays);
Time.MinusOne.Should().BeLessThan(twoDays);```

If there is a need to construct a time of -1ms or 0ms, use the constructor that accepts a factor and time unit, or specify a string with ms time units

```(new Time(-1, Nest.TimeUnit.Millisecond) == new Time("-1ms")).Should().BeTrue();
(new Time(0, Nest.TimeUnit.Millisecond) == new Time("0ms")).Should().BeTrue();```

### Units of Time

edit

Where Units of Time can be specified as a union of either a `DateInterval` or `Time`, a `DateInterval` or `Time` may be passed which will be implicity converted to a `Union<DateInterval, Time>`, the serialized form of which represents the initial value passed

```Expect("month").WhenSerializing<Union<DateInterval, Time>>(DateInterval.Month);
Expect("day").WhenSerializing<Union<DateInterval, Time>>(DateInterval.Day);
Expect("hour").WhenSerializing<Union<DateInterval, Time>>(DateInterval.Hour);
Expect("minute").WhenSerializing<Union<DateInterval, Time>>(DateInterval.Minute);
Expect("quarter").WhenSerializing<Union<DateInterval, Time>>(DateInterval.Quarter);
Expect("second").WhenSerializing<Union<DateInterval, Time>>(DateInterval.Second);
Expect("week").WhenSerializing<Union<DateInterval, Time>>(DateInterval.Week);
Expect("year").WhenSerializing<Union<DateInterval, Time>>(DateInterval.Year);

Expect("2d").WhenSerializing<Union<DateInterval, Time>>((Time)"2d");
Expect("11664m").WhenSerializing<Union<DateInterval, Time>>((Time)TimeSpan.FromDays(8.1));```