Ignore milliseconds when comparing two datetimes
C#DatetimeC# 4.0C# Problem Overview
This is probably a dumb question, but I cannot seem to figure it out. I am comparing the LastWriteTime of two files, however it is always failing because the file I downloaded off the net always has milliseconds set at 0, and my original file has an actual value. Is there a simple way to ignore the milliseconds when comparing?
Here's my function:
//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;
}
Thanks in advance
C# Solutions
Solution 1 - C#
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())
Solution 2 - C#
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
Solution 3 - C#
Create a new DateTime value with the milliseconds component set to 0:
dt = dt.AddMilliseconds(-dt.Millisecond);
Solution 4 - C#
TimeSpan difference = dtNew - dtOrig;
if (difference >= TimeSpan.FromSeconds(1))
{
...
}
Solution 5 - C#
You can subtract them, to get a TimeSpan
.
Then use TimeSpan.totalSeconds()
Solution 6 - C#
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
}
Solution 7 - C#
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));
Solution 8 - C#
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.
Solution 9 - C#
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.
Solution 10 - C#
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;
Solution 11 - C#
instead of trimming unrelevant DateTime parts via creating new DateTime
s, 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 thanTrimMilliseconds
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();
}
Solution 12 - C#
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;
}
Solution 13 - C#
cast sortable strings and compare. simple and run well.
return string.Compare(dtOrig.ToString("s"), dtNew.ToString("s"),
StringComparison.Ordinal) == 0;
Solution 14 - C#
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;
}
Solution 15 - C#
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.