简体   繁体   中英

C# DateTime comparisons accuracy and rounding

I have two dates. One supplied by the user and accurate to the second and one from the database and accurate to the tick level. This means when they both represent 13/11/2009 17:22:17 (British dates)

userTime == dbTime 

returns false

The tick values are 633937297368344183 and 633937297370000000.

To fix this I use the code

userTime = new DateTime(
                userTime.Year, 
                userTime.Month, 
                userTime.Day, 
                userTime.Hour, 
                userTime.Minute, 
                userTime.Second);

dbTime = new DateTime(
                dbTime.Year, 
                dbTime.Month, 
                dbTime.Day, 
                dbTime.Hour, 
                dbTime.Minute, 
                dbTime.Second);

Is there a more elegant way to achieve this?

The most obvious refactoring would be to remove the duplication:

public static DateTime TruncateToSecond(DateTime original)
{
    return new DateTime(original.Year, original.Month, original.Day,
        original.Hour, original.Minute, original.Second);
}

...
if (TruncateToSecond(userTime) == TruncateToSecond(dbTime))
    ...

You could quite possibly write:

if (userTime.Ticks / TimeSpan.TicksPerSecond
    == dbTime.Ticks / TimeSpan.TicksPerSecond)
   ...

I believe that would work, simply because tick 0 is at the start of a second.

You ought to be careful about the time zone aspect of all of this, of course. You might want to consider using DateTimeOffset instead.

你能试一下吗

UserDateTime.Substract(dbDateTime).TotalSeconds == 0

I subtract them, and get a TimeSpan object. Then take the value of that difference (or the absolute value of the difference, whichever is appropriate for you), and compare that to a small threshold value, like 0.002s.

TimeSpan delta = dt1 - dt2;

// get the delta as an absolute value:
if (delta < new TimeSpan(0, 0, 0))
    delta = new TimeSpan(0, 0, 0) - delta;

// My threshold is 1 second.  The difference can be no more than 1 second. 
TimeSpan threshold = new TimeSpan(0, 0, 1);

if (delta > threshold)
{
    // error...
}

Very similar to Cheeso I've written this extension for DateTime that is especially used in unit tests:

public static bool IsSimilarTo(this DateTime thisDateTime, DateTime otherDateTime, TimeSpan tolerance)
{
    DateTime allowedMinimum = thisDateTime.Subtract(tolerance);
    DateTime allowedMaximum = thisDateTime.Add(tolerance);

    if (otherDateTime < allowedMinimum || otherDateTime > allowedMaximum)
    {
        return false;
    }

    return true;
}

It will help you with your issue, should be in a basic library :-)

you could use Microsoft.VisualBasic namespace and then

  DateTime a = new DateTime(633937297368344183L);
  DateTime b = new DateTime(633937297370000000L);

  Console.WriteLine(Microsoft.VisualBasic.DateAndTime.DateDiff(DateInterval.Second, a, b,FirstDayOfWeek.Sunday ,FirstWeekOfYear.System) == 0); //true

It seem under C# you need to specify the FirstDayOfWeek and FirstWeekOfYear .

Not under VB.net

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM