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

这可能是一个愚蠢的问题,但我似乎不能理解它。我正在比较两个文件的 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;
}

先谢谢你

63788 次浏览

One way would be to create new dates, inputting the year, month, day, hour, minute, second into the constructor. Alternatively, you could simply compare each value separately.

Create a new DateTime value with the milliseconds component set to 0:

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

Ether set the milliseconds in your other datetime to zero, or subtract one date from the other and just check the TotalMinutes property of the resulting time span.

You can subtract them, to get a TimeSpan.

Then use TimeSpan.totalSeconds()

You could create an extension method that would set the milliseconds to zero for a DateTime object

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

Then in your function

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

I recommend you use an extension method:

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

then its just:

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

This is overkill for a single Truncate, but if you have several and of various types you could do this using the generalized Extension Method below:

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

More general Use Extension method:

    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
}

Care should be taken, if dt has non-zero microseconds (fractions of millis). Setting only milliseconds to zero is not enough.
To set millis and below to zero (and get a succesfull comparison), the code would be:

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

Don't know why almost all programmers needs extra lines to return a bool value from a function with a bool expression.

instead

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

you can always just use

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

if the expression is true it returns true else false.

The most straightforward way to truncate time is to format it and parse on the units that you want:

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

DOK's method re-written

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

cast sortable strings and compare. simple and run well.

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

instead of trimming unrelevant DateTime parts via creating new DateTimes, compare only relevant parts:

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

I took answer by Dean Chalk as base for performance comparison, and results are:

  • CompareWith is a bit faster than TrimMilliseconds in case of equal dates

  • CompareWith is a faster than dates are not equal

my perf test (run in Console project)

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

Here is the simplest way of doing this. You can control precision as you want.

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

and usage is pretty self-explanatory

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

Simply you can use datetime format with the format you want, and convert it again to datetime as below,

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