比较两个日期时间时忽略毫秒

问题描述 投票:0回答:16

我正在比较两个文件的LastWriteTime,但是它总是失败,因为我从网上下载的文件总是将毫秒设置为0,而我的原始文件具有实际值。有没有一种简单的方法可以在比较时忽略毫秒?

这是我的功能:

//compare file's dates
public bool CompareByModifiedDate(string strOrigFile, string strDownloadedFile)
{
     DateTime dtOrig = File.GetLastWriteTime(strOrigFile);
     DateTime dtNew = File.GetLastWriteTime(strDownloadedFile);
            
     if (dtOrig == dtNew)
        return true;
     else
        return false;
}
c# datetime c#-4.0
16个回答
127
投票

我建议你使用扩展方法:

public static DateTime TrimMilliseconds(this DateTime dt)
{
    return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, 0, dt.Kind);
}

那么它只是:

if (dtOrig.TrimMilliseconds() == dtNew.TrimMilliseconds())

60
投票

如果

dt
具有 非零微秒(毫秒的分数),则应小心。仅将毫秒设置为零是不够的。
要将毫秒及以下设置为零(并获得成功的比较),代码为:

dt = dt.AddTicks(-dt.Ticks % TimeSpan.TicksPerSecond); // TimeSpan.TicksPerSecond=10000000

48
投票

创建一个新的 DateTime 值,并将毫秒部分设置为 0:

dt = dt.AddMilliseconds(-dt.Millisecond);

35
投票
TimeSpan difference = dtNew - dtOrig;
if (difference >= TimeSpan.FromSeconds(1))
{
    ...
}

18
投票

您可以将它们相减,得到

TimeSpan

然后使用

TimeSpan.totalSeconds()


8
投票

这对于单个截断来说太过分了,但是如果您有多个不同类型的截断,您可以使用下面的通用扩展方法来完成此操作:

DateTime dtSecs = DateTime.Now.TruncateTo(Extensions.DateTruncate.Second);
DateTime dtHrs  = DateTime.Now.TruncateTo(Extensions.DateTruncate.Hour);

更通用的使用扩展方法:

    public static DateTime TruncateTo(this DateTime dt, DateTruncate TruncateTo)
    {
        if (TruncateTo == DateTruncate.Year)
            return new DateTime(dt.Year, 0, 0);
        else if (TruncateTo == DateTruncate.Month)
            return new DateTime(dt.Year, dt.Month, 0);
        else if (TruncateTo == DateTruncate.Day)
            return new DateTime(dt.Year, dt.Month, dt.Day);
        else if (TruncateTo == DateTruncate.Hour)
            return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, 0, 0);
        else if (TruncateTo == DateTruncate.Minute)
            return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 0);
        else 
            return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second);

    }
    public enum DateTruncate
    {
        Year,
        Month,
        Day,
        Hour,
        Minute,
        Second
    }

5
投票

这是最简单的方法。您可以随心所欲地控制

precision

bool AreEqual(DateTime a, DateTime b, TimeSpan precision)
{
    return Math.Abs((a - b).TotalMilliseconds) < precision.TotalMilliseconds;
}

而且用法是不言自明的

var _ = AreEqual(a, b, precision: TimeSpan.FromSeconds(1));

3
投票

一种方法是创建新日期,将年、月、日、小时、分钟、秒输入到构造函数中。或者,您可以简单地分别比较每个值。


3
投票

不要通过创建新的

DateTime
来修剪不相关的 DateTime 部分,而是仅比较 相关 部分:

public static class Extensions
{
    public static bool CompareWith(this DateTime dt1, DateTime dt2)
    {
        return
            dt1.Second == dt2.Second && // 1 of 60 match chance
            dt1.Minute == dt2.Minute && // 1 of 60 chance
            dt1.Day == dt2.Day &&       // 1 of 28-31 chance
            dt1.Hour == dt2.Hour &&     // 1 of 24 chance
            dt1.Month == dt2.Month &&   // 1 of 12 chance
            dt1.Year == dt2.Year;       // depends on dataset
    }
}

我以 Dean Chalk 的回答作为性能比较的基础,结果是:

    在相同日期的情况下,
  • CompareWith
    TrimMilliseconds
    快一点

  • CompareWith
    比日期不相等更快

我的性能测试(在控制台项目中运行)

static void Main(string[] args)
{
    var dtOrig = new DateTime(2018, 03, 1, 10, 10, 10);
    var dtNew = dtOrig.AddMilliseconds(100);

    //// perf run for not-equal dates comparison
    //dtNew = dtNew.AddDays(1);
    //dtNew = dtNew.AddMinutes(1);

    int N = 1000000;

    bool isEqual = false;

    var sw = Stopwatch.StartNew();
    for (int i = 0; i < N; i++)
    {
        // TrimMilliseconds comes from 
        // https://stackoverflow.com/a/7029046/1506454 
        // answer by Dean Chalk
        isEqual = dtOrig.TrimMilliseconds() == dtNew.TrimMilliseconds();
    }
    var ms = sw.ElapsedMilliseconds;
    Console.WriteLine("DateTime trim: " + ms + " ms");

    sw = Stopwatch.StartNew();
    for (int i = 0; i < N; i++)
    {
        isEqual = dtOrig.CompareWith(dtNew);
    }
    ms = sw.ElapsedMilliseconds;
    Console.WriteLine("DateTime partial compare: " + ms + " ms");

    Console.ReadKey();
}

2
投票

将其他日期时间中的毫秒设置为零,或从另一个日期中减去一个日期,然后检查结果时间跨度的

TotalMinutes
属性。


1
投票

您可以创建一个扩展方法,将 DateTime 对象的毫秒设置为零

public static DateTime ZeroMilliseconds(this DateTime value) {
  return new DateTime(value.Year, value.Month, value.Day, 
    value.Hours, value.Minutes, value.Seconds);
}

然后在你的函数中

 if (dtOrig.ZeroMilliseconds() == dtNew.ZeroMilliseconds())
        return true;
     else
        return false;

1
投票

您可以使用您想要的格式的日期时间格式,然后将其再次转换为日期时间,如下所示,

//compare file's dates
        
        String format1 = @"yyyy-MM-dd HH:mm:ss"; // you also can avoid seconds if you want

        public bool CompareByModifiedDate(string strOrigFile, string strDownloadedFile)
        {
            
            //.here we will use the format

            DateTime dtOrig = Convert.ToDateTime(File.GetLastWriteTime(strOrigFile).ToString(format1));
            DateTime dtNew = Convert.ToDateTime(File.GetLastWriteTime(strDownloadedFile).ToString(format1));

            if (dtOrig == dtNew)
                return true;
            else
                return false;
        }

0
投票

修剪的

DateTime
比较的通用形式可以写成如下:

static bool TrimmedEquals(DateTime dt1, DateTime dt2, long delta)
{
    return Math.Abs((dt1 - dt2).Ticks) < delta;
}

TimeSpan
Struct
有许多常量字段,可以用作
delta

或者,可以使用带有

TimeSpan
参数的方法:

static bool TrimmedEquals(DateTime dt1, DateTime dt2, TimeSpan delta)
{
    return Math.Abs((dt1 - dt2).Ticks) < delta.Ticks;
}

如果您想进行内联比较:

if (Math.Abs((dtNew - dtOrig).Ticks) < TimeSpan.TicksPerSecond)
{
    // Dates are equal
}
else
{
    // Dates are not equal
}

测试 2 个

DateTime
的输出:

DateTime dtOrig = DateTime.Now;
DateTime dtNew = DateTime.Now.AddMilliseconds(1);

Console.WriteLine($"Original Date:         {dtOrig:O}");
Console.WriteLine($"Original Date (ticks): {dtOrig.Ticks}");
Console.WriteLine($"New Date:              {dtNew:O}");
Console.WriteLine($"New Date (ticks):      {dtNew.Ticks}");

Console.WriteLine();

long[] deltas =
{
    TimeSpan.TicksPerMicrosecond,
    TimeSpan.TicksPerMillisecond,
    TimeSpan.TicksPerSecond,
    TimeSpan.TicksPerMinute,
    TimeSpan.TicksPerHour,
    TimeSpan.TicksPerDay,
};

Console.WriteLine("Test 1");
Console.WriteLine("dt1: dtOrig");
Console.WriteLine("dt2: dtNew");

foreach (long delta in deltas)
{
    if (TrimmedEquals(dtOrig, dtNew, delta))
    {
        Console.WriteLine($"Dates are equal with delta:     {delta}");
    }
    else
    {
        Console.WriteLine($"Dates are not equal with delta: {delta}");
    }
}

Console.WriteLine();

Console.WriteLine("Test 2");
Console.WriteLine("dt1: dtNew");
Console.WriteLine("dt2: dtOrig");

foreach (long delta in deltas)
{
    if (TrimmedEquals(dtNew, dtOrig, delta))
    {
        Console.WriteLine($"Dates are equal with delta:     {delta}");
    }
    else
    {
        Console.WriteLine($"Dates are not equal with delta: {delta}");
    }
}

// Original Date:         2024-12-19T12:28:04.0732065+01:00
// Original Date (ticks): 638702080840732065
// New Date:              2024-12-19T12:28:04.0805347+01:00
// New Date (ticks):      638702080840805347
//
// Test 1
// dt1: dtOrig
// dt2: dtNew
// Dates are not equal with delta: 10
// Dates are not equal with delta: 10000
// Dates are equal with delta:     10000000
// Dates are equal with delta:     600000000
// Dates are equal with delta:     36000000000
// Dates are equal with delta:     864000000000
//
// Test 2
// dt1: dtNew
// dt2: dtOrig
// Dates are not equal with delta: 10
// Dates are not equal with delta: 10000
// Dates are equal with delta:     10000000
// Dates are equal with delta:     600000000
// Dates are equal with delta:     36000000000
// Dates are equal with delta:     864000000000

-1
投票

投射可排序字符串并进行比较。简单且运行良好。

    return string.Compare(dtOrig.ToString("s"), dtNew.ToString("s"), 
StringComparison.Ordinal) == 0;

-3
投票

截断时间最直接的方法是对其进行格式化并解析您想要的单位:

var myDate = DateTime.Parse(DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss"));

DOK的方法重写了

public bool CompareByModifiedDate(string strOrigFile, string strDownloadedFile)
    {
         DateTime dtOrig = DateTime.Parse(File.GetLastWriteTime(strOrigFile).ToString("MM/dd/yyyy hh:mm:ss"));
         DateTime dtNew = DateTime.Parse(File.GetLastWriteTime(strDownloadedFile).ToString("MM/dd/yyyy hh:mm:ss"));

         if (dtOrig == dtNew)
            return true;
         else
            return false;
    }

-6
投票

不知道为什么几乎所有程序员都需要额外的行来从具有 bool 表达式的函数返回 bool 值。

相反

if (dtOrig.ZeroMilliseconds() == dtNew.ZeroMilliseconds())
    return true;
 else
    return false;

你可以随时使用

return dtOrig.ZeroMilliseconds() == dtNew.ZeroMilliseconds()

如果表达式为 true,则返回 true,否则返回 false。

© www.soinside.com 2019 - 2024. All rights reserved.