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


76

这可能是一个愚蠢的问题,但我似乎无法弄清楚。我正在比较两个文件的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;
}

提前致谢


Answers:


42

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

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

26
警告:当的DateTime秒数不为零时,此功能将无效。参见@PeterIvan或@DeanChalk的答案。
TheCloudlessSky

98

我建议您使用扩展方法:

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

3
也许DateTimeKind还可以通过添加dt.Kindctor的末尾来保留
卢克·赫顿

3
返回新的DateTime(dt.Year,dt.Month,dt.Day,dt.Hour,dt.Minute,dt.Second,0,dt.Kind);
Adamy 2015年

41

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

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

1
这是最好的解决方案。快速,并保留dt.Kind。我知道在所有情况下它都具有相同的功能,但对我来说,使用更自然dt = dt.AddTicks(-(dt.Ticks % TimeSpan.TicksPerSecond));,即先使用%运算符,然后取反。那是因为%第一个操作数为负的行为对我来说有点令人困惑,因此我更喜欢%使用两个正操作数进行运算的版本。
杰普·斯蒂格·尼尔森

@JeppeStigNielsen:您的代码与我的完全相同。根据运算符的优先级,您可以相乘和/或相除,然后相加/取反。因此,括号没有改变,只是阐明了已建立的逻辑。
彼得·伊凡

不,那是不正确的。在极少数情况下(在您的上面的使用中不会发生,因此您可以使用),这是有区别的。考虑以下代码(其中ab不能声明const):long a = long.MinValue; long b = 10L; long x = (-a) % b; long y = -(a % b); long z = -a % b;这里的价值x将是负面的,因为否定aa了一遍,负值%-ed为正值的给出了否定的价值。但是的值y是正的,因为这一次我们对-10和之间的负值求反0,并且给出一个正数。现在检查z看看!
杰普·斯蒂格·尼尔森

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

这是去恕我直言的方法。
拉里


7

对于单个Truncate来说,这是过分的,但是如果您有多种类型,则可以使用下面的通用扩展方法来做到这一点:

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
    }

4
有了彼得·伊凡(Peter Ivan)的解决方案,自然就可以做到public static DateTime TruncateTo(this DateTime dt, long truncateResolution) { return dt.AddTicks(-(dt.Ticks % truncateResolution)); }。更短更清晰。然后像这样使用:DateTime dtSecs = DateTime.Now.TruncateTo(TimeSpan.TicksPerSecond); DateTime dtHrs = DateTime.Now.TruncateTo(TimeSpan.TicksPerHour);依此类推。您甚至可以截断到更奇怪的分辨率,例如3小时的倍数(3 * TimeSpan.TicksPerHour)。
杰普·斯蒂格·尼尔森

应为每个新的DateTime设置
dt.Kind

3

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


3

这是执行此操作的最简单方法。您可以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));

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
因此,您的方法返回一个DateTime,但被定义为返回一个字符串。
Ash Burlaczenko 2011年

3
我不知道为什么所有程序员在使用bour函数实现布尔功能时都需要太多行
米奇老鼠

value.Kind应该在新的DateTime中设置
Doug Domeny

1

与其通过创建new来修剪不相关的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的回答作为性能比较的基础,结果是:

  • CompareWithTrimMilliseconds日期相等的情况要快一点

  • CompareWith 比日期不相等快

我的性能测试(在Console项目中运行)

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


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

2
在英国,欧洲或澳大利亚运行您的代码,看看会发生什么。无论如何,我都不喜欢这种方法,但是您需要使用不变的语言环境,或者DateTime.ParseExact甚至要使其具有远程可靠性。
SimonMᶜKenzie'16

-6

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

代替

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

你总是可以使用

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

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


您从哪里获得ZeroMilliseconds()的?
Purusartha 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.