DateOnly / TimeOnly
Describes the possible expectations for DateOnly and TimeOnly.
| Expectation | Negated | Summary |
|---|---|---|
IsEqualTo | IsNotEqualTo | equal to the expected value |
IsOneOf | IsNotOneOf | equal to one of the expected values |
IsAfter | IsNotAfter | later than the expected value |
IsOnOrAfter | IsNotOnOrAfter | not earlier than the expected value |
IsBefore | IsNotBefore | earlier than the expected value |
IsOnOrBefore | IsNotOnOrBefore | not later than the expected value |
IsBetween | IsNotBetween | between two values, both bounds included |
HasYear, … | negated comparison | has the expected year, month, day, hour, … |
The DateOnly and TimeOnly expectations are only available on .NET 8 or later.
Equality
You can verify that the DateOnly or TimeOnly is equal to another one or not:
- DateOnly
- TimeOnly
DateOnly releaseDate = new DateOnly(1969, 9, 26);
await Expect.That(releaseDate).IsEqualTo(new DateOnly(1969, 9, 26));
await Expect.That(releaseDate).IsNotEqualTo(new DateOnly(1970, 5, 8));
TimeOnly startTime = new TimeOnly(14, 15, 16);
await Expect.That(startTime).IsEqualTo(new TimeOnly(14, 15, 16));
await Expect.That(startTime).IsNotEqualTo(new TimeOnly(13, 15, 16));
One of
You can verify that the DateOnly or TimeOnly is one of many alternatives:
- DateOnly
- TimeOnly
DateOnly releaseDate = new DateOnly(1969, 9, 26);
await Expect.That(releaseDate).IsOneOf([new DateOnly(1969, 9, 26), new DateOnly(1970, 5, 8)]);
await Expect.That(releaseDate).IsNotOneOf([new DateOnly(1965, 8, 6), new DateOnly(1966, 8, 5)]);
TimeOnly startTime = new TimeOnly(14, 15, 16);
await Expect.That(startTime).IsOneOf([new TimeOnly(14, 15, 15), new TimeOnly(14, 15, 16)]);
await Expect.That(startTime).IsNotOneOf([new TimeOnly(13, 15, 16), new TimeOnly(13, 14, 15)]);
After / before
You can verify that the DateOnly or TimeOnly is (on or) after or before another value, or that it is not:
- DateOnly
- TimeOnly
DateOnly releaseDate = new DateOnly(1969, 9, 26);
await Expect.That(releaseDate).IsAfter(new DateOnly(1968, 11, 22));
await Expect.That(releaseDate).IsOnOrAfter(new DateOnly(1969, 9, 26));
await Expect.That(releaseDate).IsBefore(new DateOnly(1970, 5, 8));
await Expect.That(releaseDate).IsOnOrBefore(new DateOnly(1969, 9, 26));
await Expect.That(releaseDate).IsNotAfter(new DateOnly(1970, 5, 8));
TimeOnly startTime = new TimeOnly(14, 15, 16);
await Expect.That(startTime).IsAfter(new TimeOnly(12, 0));
await Expect.That(startTime).IsOnOrAfter(new TimeOnly(14, 15, 16));
await Expect.That(startTime).IsBefore(new TimeOnly(18, 0));
await Expect.That(startTime).IsOnOrBefore(new TimeOnly(14, 15, 16));
await Expect.That(startTime).IsNotAfter(new TimeOnly(18, 0));
Between
You can verify that the DateOnly or TimeOnly is between two values, or that it is not:
- DateOnly
- TimeOnly
DateOnly releaseDate = new DateOnly(1969, 9, 26);
await Expect.That(releaseDate).IsBetween(new DateOnly(1969, 1, 1)).And(new DateOnly(1969, 12, 31));
await Expect.That(releaseDate).IsNotBetween(new DateOnly(1970, 1, 1)).And(new DateOnly(1970, 12, 31));
TimeOnly startTime = new TimeOnly(14, 15, 16);
await Expect.That(startTime).IsBetween(new TimeOnly(14, 0)).And(new TimeOnly(15, 0));
await Expect.That(startTime).IsNotBetween(new TimeOnly(18, 0)).And(new TimeOnly(20, 0));
Tolerance
Every comparison on this page except the Has… properties accepts a tolerance with Within, which widens the
accepted range by the tolerance:
- DateOnly
- TimeOnly
DateOnly releaseDate = new DateOnly(1969, 9, 26);
await Expect.That(releaseDate).IsEqualTo(new DateOnly(1969, 9, 25)).Within(TimeSpan.FromDays(1))
.Because("we accept values between 1969-09-24 and 1969-09-26");
await Expect.That(releaseDate).IsBefore(new DateOnly(1969, 9, 26)).Within(TimeSpan.FromDays(1));
TimeOnly startTime = new TimeOnly(14, 15, 16);
await Expect.That(startTime).IsEqualTo(new TimeOnly(14, 15, 17)).Within(TimeSpan.FromSeconds(1))
.Because("we accept values between 14:15:16 and 14:15:18");
await Expect.That(startTime).IsOneOf([new TimeOnly(14, 15, 17)]).Within(TimeSpan.FromSeconds(1));
A DateOnly has no time of day, so its tolerance must be a whole number of days. Anything else, for example
Within(TimeSpan.FromHours(23)), throws an ArgumentOutOfRangeException as soon as it is specified instead of silently
rounding down to a tolerance you did not ask for.
The default tolerance is shared with the other time types, so it is not
rejected: only its whole days apply to a DateOnly, and a default below one day has no effect.
Clock face
A TimeOnly has no date, so midnight is not a boundary for equality and ranges, but it stays one for ordering:
IsEqualTo,IsNotEqualToandIsOneOfuse the shortest distance around the clock face, so00:00and23:59are one minute apart. That distance never exceeds 12 hours, so a tolerance of 12 hours or more accepts every time.IsBetweenruns clockwise from the minimum to the maximum, so a range from23:00to01:00contains00:00.IsAfter,IsOnOrAfter,IsBeforeandIsOnOrBeforecompare the times as they are, so00:00is never after23:00. Their tolerance only ever widens the accepted range and never wraps around midnight.
TimeOnly midnight = new TimeOnly(0, 0);
await Expect.That(midnight).IsBetween(new TimeOnly(23, 0)).And(new TimeOnly(1, 0));
await Expect.That(midnight).IsEqualTo(new TimeOnly(23, 59)).Within(TimeSpan.FromMinutes(1));
await Expect.That(midnight).IsNotAfter(new TimeOnly(23, 0));
Properties
You can verify the properties of the DateOnly or TimeOnly:
- DateOnly
- TimeOnly
DateOnly releaseDate = new DateOnly(1969, 9, 26);
await Expect.That(releaseDate).HasYear(1969);
await Expect.That(releaseDate).HasMonth().GreaterThan(6);
await Expect.That(releaseDate).HasDay(26);
TimeOnly startTime = new TimeOnly(15, 16, 17, 189);
await Expect.That(startTime).HasHour(15);
await Expect.That(startTime).HasMinute(16);
await Expect.That(startTime).HasSecond().LessThan(30);
await Expect.That(startTime).HasMillisecond(189);
The Has… expectations for a number or a TimeSpan, e.g. HasLength(), HasCount(), HasYear() or HasMajor(),
continue with one of the following comparisons, each with a negated counterpart:
| Comparison | Negated | Succeeds when the value is |
|---|---|---|
EqualTo(x) | NotEqualTo(x) | equal to x |
GreaterThan(x) | NotGreaterThan(x) | greater than x |
GreaterThanOrEqualTo(x) | NotGreaterThanOrEqualTo(x) | greater than or equal to x |
LessThan(x) | NotLessThan(x) | less than x |
LessThanOrEqualTo(x) | NotLessThanOrEqualTo(x) | less than or equal to x |
Between(min).And(max) | NotBetween(min).And(max) | between min and max, both bounds included |
Passing the value directly, e.g. HasLength(10), is a shorthand for EqualTo.
The expected value is nullable, e.g. to pass a value mapped from a property. As the actual value is never null,
EqualTo(null) fails and NotEqualTo(null) succeeds, while a comparison of order against null, such as
GreaterThan(null) or Between(null).And(3), fails even when negated.