Skip to main content

DateOnly / TimeOnly

Describes the possible expectations for DateOnly and TimeOnly.

ExpectationNegatedSummary
IsEqualToIsNotEqualToequal to the expected value
IsOneOfIsNotOneOfequal to one of the expected values
IsAfterIsNotAfterlater than the expected value
IsOnOrAfterIsNotOnOrAfternot earlier than the expected value
IsBeforeIsNotBeforeearlier than the expected value
IsOnOrBeforeIsNotOnOrBeforenot later than the expected value
IsBetweenIsNotBetweenbetween two values, both bounds included
HasYear, …negated comparisonhas the expected year, month, day, hour, …
.NET 8 or later

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 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));

One of​

You can verify that the DateOnly or TimeOnly is one of many alternatives:

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)]);

After / before​

You can verify that the DateOnly or TimeOnly is (on or) after or before another value, or that it is not:

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));

Between​

You can verify that the DateOnly or TimeOnly is between two values, or that it is not:

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));

Tolerance​

Every comparison on this page except the Has… properties accepts a tolerance with Within, which widens the accepted range by the tolerance:

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));

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, IsNotEqualTo and IsOneOf use the shortest distance around the clock face, so 00:00 and 23:59 are one minute apart. That distance never exceeds 12 hours, so a tolerance of 12 hours or more accepts every time.
  • IsBetween runs clockwise from the minimum to the maximum, so a range from 23:00 to 01:00 contains 00:00.
  • IsAfter, IsOnOrAfter, IsBefore and IsOnOrBefore compare the times as they are, so 00:00 is never after 23: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 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);

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:

ComparisonNegatedSucceeds 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.