Dates

April 3, 2026 ยท View on GitHub

By default dates and times (DateTime, DateTimeOffset, DateOnly, and TimeOnly) are sanitized during verification. This is done by finding each date and taking a counter based that that specific date. That counter is then used replace the date values. This allows for repeatable tests when date values are changing.

var dateTime = DateTime.Now;
var dateTimeOffset = DateTimeOffset.Now;
var target = new DateTimeTarget
{
    DateTime = dateTime,
    Date = new(dateTime.Year, dateTime.Month, dateTime.Day),
    DateNullable = new(dateTime.Year, dateTime.Month, dateTime.Day),
    DateString = new Date(dateTime.Year, dateTime.Month, dateTime.Day).ToString(),
    DateTimeNullable = dateTime,
    DateTimeString = dateTime.ToString("F"),
    DateTimeOffset = dateTimeOffset,
    DateTimeOffsetNullable = dateTimeOffset,
    DateTimeOffsetString = dateTimeOffset.ToString("F")
};

await Verify(target);

snippet source | anchor

Results in the following:

{
  DateTime: DateTime_1,
  DateTimeNullable: DateTime_1,
  Date: Date_1,
  DateNullable: Date_1,
  DateTimeOffset: DateTimeOffset_1,
  DateTimeOffsetNullable: DateTimeOffset_1,
  DateTimeString: DateTimeOffset_2,
  DateTimeOffsetString: DateTimeOffset_2,
  DateString: Date_1
}

snippet source | anchor

To disable this behavior use:

Instance

var target = new
{
    Date = new DateTime(2020, 10, 10, 0, 0, 0, DateTimeKind.Utc)
};

var settings = new VerifySettings();
settings.DontScrubDateTimes();

return Verify(target, settings);

snippet source | anchor

Fluent

var target = new
{
    Date = new DateTime(2020, 10, 10, 0, 0, 0, DateTimeKind.Utc)
};

return Verify(target)
    .DontScrubDateTimes();

snippet source | anchor

Globally

[ModuleInitializer]
public static void ModuleInitializer() =>
    VerifierSettings.DontScrubDateTimes();

snippet source | anchor

DisableDateCounting

If many calls are made to the current date/time in quick succession, the date counting behavior (DateTime_x) can result in inconsistent results. To revert to the simpler scrubbing convention ({Scrubbed}) use DisableDateCounting.

Instance

var target = new
{
    Date = new DateTime(2020, 10, 10, 0, 0, 0, DateTimeKind.Utc)
};

var settings = new VerifySettings();
settings.DisableDateCounting();

return Verify(target, settings);

snippet source | anchor

Fluent

var target = new
{
    Date = new DateTime(2020, 10, 10, 0, 0, 0, DateTimeKind.Utc)
};

return Verify(target)
    .DisableDateCounting();

snippet source | anchor

Globally

[ModuleInitializer]
public static void ModuleInitializer() =>
    VerifierSettings.DisableDateCounting();

snippet source | anchor

AddExtraDateTimeFormat

AddExtraDateTimeFormat allows specifying custom date formats to be scrubbed.

[ModuleInitializer]
public static void UseAddExtraDateTimeFormat() =>
    VerifierSettings.AddExtraDateTimeFormat("yyyy-MM-dd");

[Fact]
public Task WithExtraDateTimeFormat() =>
    Verify(
        new
        {
            date = "2022-11-08"
        });

snippet source | anchor

Inline Dates

Strings containing inline dates can also be scrubbed. There a equivalent APIs for DateOnly, DateTime, and DateTimeOffset.

Instance

[Fact]
public Task ScrubInlineDateTimesInstance()
{
    var settings = new VerifySettings();
    settings.ScrubInlineDateTimes("yyyy-MM-dd");
    return Verify(
        "content 2020-10-20 content",
        settings);
}

snippet source | anchor

Fluent

[Fact]
public Task ScrubInlineDateTimesFluent() =>
    Verify("content 2020-10-20 content")
        .ScrubInlineDateTimes("yyyy-MM-dd");

snippet source | anchor

Globally

public static class ModuleInitializer
{
    [ModuleInitializer]
    public static void Init() =>
        VerifierSettings.ScrubInlineDateTimes("yyyy-MM-dd");
}

snippet source | anchor

Named Date and Times

Specific date or times can be named. When any of those values are found, they will be matched with the corresponding name.

Instance

var settings = new VerifySettings();
settings.AddNamedDate(new(2020, 10, 11), "instanceNamedDate");
settings.AddNamedTime(new(1, 2), "instanceTime");
settings.AddNamedDateTime(new(2030, 1, 2), "instanceNamedDateTime");
settings.AddNamedDateTimeOffset(new DateTime(2030, 1, 2), "instanceNamedTimeOffset");
await Verify(target, settings);

snippet source | anchor

Instance

await Verify(target)
    .AddNamedDate(new(2020, 10, 11), "instanceNamedDate")
    .AddNamedTime(new(1, 2), "instanceTime")
    .AddNamedDateTime(new(2030, 1, 2), "instanceNamedDateTime")
    .AddNamedDateTimeOffset(new DateTime(2030, 1, 2), "instanceNamedTimeOffset");

snippet source | anchor

Globally

[ModuleInitializer]
public static void NamedDatesAndTimesGlobal()
{
    VerifierSettings.AddNamedDateTime(new(2030, 1, 1), "namedDateTime");
    VerifierSettings.AddNamedTime(new(1, 1), "namedTime");
    VerifierSettings.AddNamedDate(new(2030, 1, 1), "namedDate");
    VerifierSettings.AddNamedDateTimeOffset(new(new(2030, 1, 1)), "namedDateTimeOffset");
}

snippet source | anchor

Inferred Name

The name can be inferred from the variable name by omitting the name argument:

[Fact]
public Task InferredNamedDateFluent()
{
    var namedDate = new Date(1935, 10, 1);
    return Verify(
            new
            {
                value = namedDate
            })
        .AddNamedDate(namedDate);
}

snippet source | anchor

Result:

{
  value: namedDate
}

snippet source | anchor

Custom Comparers

The following comparers can be overridden

DateTime

Default Comparer:

class DateTimeComparer : IEqualityComparer<DateTime>
{
    public bool Equals(DateTime x, DateTime y) =>
        x == y &&
        x.Kind == y.Kind;

    public int GetHashCode(DateTime obj) =>
        obj.GetHashCode() + (int) obj.Kind;
}

snippet source | anchor

Custom Comparer:

[ModuleInitializer]
public static void UseCustomDateTimeComparer() =>
    Counter.UseDateTimeComparer(new CustomDateTimeComparer());

public class CustomDateTimeComparer :
    IEqualityComparer<DateTime>
{
    public bool Equals(DateTime x, DateTime y) =>
        new DateTime(x.Year, x.Month, x.Day) ==
        new DateTime(y.Year, y.Month, y.Day);

    public int GetHashCode(DateTime date) =>
        new DateTime(date.Year, date.Month, date.Day).GetHashCode();
}

snippet source | anchor

DateTimeOffset

Default Comparer:

class DateTimeOffsetComparer :
    IEqualityComparer<DateTimeOffset>
{
    public bool Equals(DateTimeOffset x, DateTimeOffset y) =>
        x == y && x.Offset == y.Offset;

    public int GetHashCode(DateTimeOffset obj) =>
        obj.GetHashCode() + (int) obj.Offset.TotalMinutes;
}

snippet source | anchor

Custom Comparer:

[ModuleInitializer]
public static void UseCustomDateTimeOffsetComparer() =>
    Counter.UseDateTimeOffsetComparer(new CustomDateTimeOffsetComparer());

public class CustomDateTimeOffsetComparer :
    IEqualityComparer<DateTimeOffset>
{
    public bool Equals(DateTimeOffset x, DateTimeOffset y) =>
        new DateTimeOffset(new(x.Year, x.Month, x.Day)) ==
        new DateTimeOffset(new(y.Year, y.Month, y.Day));

    public int GetHashCode(DateTimeOffset date)
    {
        var dateTime = new DateTime(date.Year, date.Month, date.Day);
        return new DateTimeOffset(dateTime)
            .GetHashCode();
    }
}

snippet source | anchor

TimeOnly

Default Comparer:

EqualityComparer<Time>.Default;

snippet source | anchor

Custom Comparer:

[ModuleInitializer]
public static void UseCustomTimeComparer() =>
    Counter.UseTimeComparer(new CustomTimeComparer());

public class CustomTimeComparer :
    IEqualityComparer<Time>
{
    public bool Equals(Time x, Time y) =>
        new Time(x.Hour, x.Minute, x.Second) ==
        new Time(y.Hour, y.Minute, y.Second);

    public int GetHashCode(Time date) =>
        new Time(date.Hour, date.Minute, date.Second).GetHashCode();
}

snippet source | anchor