4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

HeadwatersAdvent Calendar 2019

Day 5

C# と SQL Server の DateTime を Assert.Equals する

Posted at

C# と Database ではそれぞれミリ秒の保持の仕方が異なります。上手く Assert するには比較用のクラスを作って、 Assert の Parameter に渡してあげれば OK です。

使っているもの

  • xUnit
  • SQL Server

なぜ起きるのか

C# の DateTime ではミリ秒を正しく保持しています。

C#: 2013-05-01 23:59:59.991

しかし、これを SQL Server の datetime に入れるとこうなります。

SQL Server: 2013-05-01 23:59:59.990

これには理由があって、ミリ秒の精度が .000、.003、.007 であるためです。よって、このまま Assert.Equals すると Fail してしまいます。

解決方法

比較用のクラスをパラメーターで渡してあげて、多少の時間を許容するようにします。

Assert.Equal(expected, actual, new SqlServerDateTimeComparer());

比較用のクラス

いくつか用意してあるので合ったものを使ってください。また、このクラスでは 10 秒までの差は許容しているので、この設定値は Constructor で受け取れるようにするなどすれば、別の比較 (e.g. DateTime が DI 出来なくて死ぬ Unit Test など) にも使えると思います。

public class SqlServerNullableDateTimeComparer : IEqualityComparer<DateTime?>
{
    public bool Equals(DateTime? x, DateTime? y)
    {
        if (x == null && y == null)
        {
            return true;
        }
        if (x == null || y == null)
        {
            return false;
        }
        return (x.Value - y.Value).Duration() < TimeSpan.FromSeconds(10);
    }
    public int GetHashCode(DateTime? obj)
    {
        return obj.GetHashCode();
    }
}

public class SqlServerDateTimeComparer : IEqualityComparer<DateTime>
{
    public bool Equals(DateTime x, DateTime y)
    {
        return (x - y).Duration() < TimeSpan.FromSeconds(10);
    }
    public int GetHashCode(DateTime obj)
    {
        return obj.GetHashCode();
    }
}

public class SqlServerNullableDateTimeOffsetComparer : IEqualityComparer<DateTimeOffset?>
{
    public bool Equals(DateTimeOffset? x, DateTimeOffset? y)
    {
        if (x == null && y == null)
        {
            return true;
        }
        if (x == null || y == null)
        {
            return false;
        }
        return (x.Value - y.Value).Duration() < TimeSpan.FromSeconds(10);
    }
    public int GetHashCode(DateTimeOffset? obj)
    {
        return obj.GetHashCode();
    }
}

public class SqlServerDateTimeOffsetComparer : IEqualityComparer<DateTimeOffset>
{
    public bool Equals(DateTimeOffset x, DateTimeOffset y)
    {
        return (x - y).Duration() < TimeSpan.FromSeconds(10);
    }
    public int GetHashCode(DateTimeOffset obj)
    {
        return obj.GetHashCode();
    }
}

Note

DATETIME データ型のミリ秒に関する注意事項 – Microsoft SQL Server Japan Support Team Blog

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?