2008-12-19 16 views
25

Theo mặc định C# so sánh đối tượng DateTime với đánh dấu 100ns. Tuy nhiên, cơ sở dữ liệu của tôi trả về giá trị DateTime đến mili giây gần nhất. Cách tốt nhất để so sánh hai đối tượng DateTime trong C# bằng cách sử dụng một dung sai được chỉ định là gì?Làm thế nào để bạn so sánh các đối tượng DateTime bằng cách sử dụng một dung sai quy định trong C#?

Chỉnh sửa: Tôi đang xử lý vấn đề cắt ngắn chứ không phải vấn đề làm tròn. Như Joe chỉ ra dưới đây, một vấn đề làm tròn sẽ đưa ra những câu hỏi mới.

Giải pháp phù hợp với tôi là sự kết hợp của những giải pháp bên dưới.

(dateTime1 - dateTime2).Duration() < TimeSpan.FromMilliseconds(1) 

Điều này trả về true nếu chênh lệch nhỏ hơn một phần nghìn giây. Cuộc gọi đến Duration() là quan trọng để có được giá trị tuyệt đối của sự khác biệt giữa hai ngày.

Trả lời

23

tôi usally sử dụng các phương pháp TimeSpan.FromXXX để làm một cái gì đó như thế này:

if((myDate - myOtherDate) > TimeSpan.FromSeconds(10)) 
{ 
    //Do something here 
} 
+3

Một cách hơi khác nhau: if ((date1 - date2) .TotalSeconds> 10) – Thomas

+4

Điều này sẽ là '(dateTime1 - dateTime2) .Duration() Marius

5

Bạn cần phải loại bỏ các thành phần mili giây từ đối tượng ngày. Một cách là:

DateTime d = DateTime.Now; 
    d.Subtract(new TimeSpan(0, 0, 0, 0, d.Millisecond)); 

Bạn cũng có thể trừ hai datetimes

d.Subtract (DateTime.Now);

Điều này sẽ trả về đối tượng khoảng thời gian mà bạn có thể sử dụng để so sánh các thành phần ngày, giờ, phút và giây để thấy sự khác biệt.

2
 if (Math.Abs(dt1.Subtract(dt2).TotalSeconds) < 1.0) 
+0

+1 cho câu trả lời sử dụng tuyệt đối cho tài khoản cho trôi dạt đồng hồ –

10

Làm thế nào về một phương pháp mở rộng cho DateTime để thực hiện một chút của một giao diện thông thạo (đó là tất cả các cơn giận dữ phải không?)

public static class DateTimeTolerance 
{ 
    private static TimeSpan _defaultTolerance = TimeSpan.FromSeconds(10); 
    public static void SetDefault(TimeSpan tolerance) 
    { 
     _defaultTolerance = tolerance; 
    } 

    public static DateTimeWithin Within(this DateTime dateTime, TimeSpan tolerance) 
    { 
     return new DateTimeWithin(dateTime, tolerance); 
    } 

    public static DateTimeWithin Within(this DateTime dateTime) 
    { 
     return new DateTimeWithin(dateTime, _defaultTolerance); 
    } 
} 

này dựa vào một lớp học để lưu trữ nhà nước và xác định một ! quá tải vài nhà điều hành cho == và =:

public class DateTimeWithin 
{ 
    public DateTimeWithin(DateTime dateTime, TimeSpan tolerance) 
    { 
     DateTime = dateTime; 
     Tolerance = tolerance; 
    } 

    public TimeSpan Tolerance { get; private set; } 
    public DateTime DateTime { get; private set; } 

    public static bool operator ==(DateTime lhs, DateTimeWithin rhs) 
    { 
     return (lhs - rhs.DateTime).Duration() <= rhs.Tolerance; 
    } 

    public static bool operator !=(DateTime lhs, DateTimeWithin rhs) 
    { 
     return (lhs - rhs.DateTime).Duration() > rhs.Tolerance; 
    } 

    public static bool operator ==(DateTimeWithin lhs, DateTime rhs) 
    { 
     return rhs == lhs; 
    } 

    public static bool operator !=(DateTimeWithin lhs, DateTime rhs) 
    { 
     return rhs != lhs; 
    } 
} 

Sau đó trong mã của bạn, bạn có thể làm:

DateTime d1 = DateTime.Now; 
DateTime d2 = d1 + TimeSpan.FromSeconds(20); 

if(d1 == d2.Within(TimeSpan.FromMinutes(1))) { 
    // TRUE! Do whatever 
} 

Lớp mở rộng còn sở hữu một khoan dung tĩnh mặc định để bạn có thể thiết lập một sự khoan dung cho toàn bộ dự án của bạn và sử dụng Trong phương pháp không có tham số:

DateTimeTolerance.SetDefault(TimeSpan.FromMinutes(1)); 

if(d1 == d2.Within()) { // Uses default tolerance 
    // TRUE! Do whatever 
} 

Tôi có một vài đơn vị xét nghiệm nhưng mà muốn được một chút quá nhiều mã để dán ở đây.

+0

Điều này giống như một sử dụng chấp nhận được của meth mở rộng ods, hooray! Phương pháp – EndangeredMassa

+0

phải tĩnh – darasd

+0

và nó sẽ cần một tên khác, vì trình biên dịch cho rằng bạn đang cố gắng gọi phương thức DateTime.Equals tĩnh và sau đó than phiền rằng nó không thể được gọi là phương thức thể hiện. – darasd

1

Theo mặc định, C# so sánh các đối tượng DateTime với mili giây.

Thực ra độ phân giải là đánh dấu 100ns.

Nếu bạn so sánh hai giá trị DateTime từ cơ sở dữ liệu, có độ phân giải 1s, không có vấn đề gì.

Nếu bạn so sánh với một DateTime từ một nguồn khác (ví dụ: DateTime hiện tại sử dụng DateTime.Now)), thì bạn cần phải quyết định cách bạn muốn các phân số của một giây được xử lý. Ví dụ. làm tròn đến gần nhất hoặc cắt ngắn? Làm thế nào để tròn nếu nó chính xác nửa giây.

Tôi đề nghị bạn làm tròn hoặc cắt ngắn thành số tích phân giây, sau đó so sánh với giá trị từ cơ sở dữ liệu. Here's a post that describes how to round a DateTime (ví dụ này làm tròn số phút, nhưng hiệu trưởng thì giống nhau).

0

Tôi gặp vấn đề tương tự như người hỏi ban đầu nhưng để làm những điều thú vị hơn tôi đã lưu và truy xuất Nullable<DateTime>.

tôi thích joshperry's answer và mở rộng nó để làm việc cho mục đích của tôi:

public static class DateTimeTolerance 
{ 
    private static TimeSpan _defaultTolerance = TimeSpan.FromMilliseconds(10); // 10ms default resolution 
    public static void SetDefault(TimeSpan tolerance) 
    { 
     _defaultTolerance = tolerance; 
    } 

    public static DateTimeWithin Within(this DateTime dateTime, TimeSpan tolerance) 
    { 
     return new DateTimeWithin(dateTime, tolerance); 
    } 

    public static DateTimeWithin Within(this DateTime dateTime) 
    { 
     return new DateTimeWithin(dateTime, _defaultTolerance); 
    } 

    // Additional overload that can deal with Nullable dates 
    // (treats null as DateTime.MinValue) 
    public static DateTimeWithin Within(this DateTime? dateTime) 
    { 
     return dateTime.GetValueOrDefault().Within(); 
    } 

    public static DateTimeWithin Within(this DateTime? dateTime, TimeSpan tolerance) 
    { 
     return dateTime.GetValueOrDefault().Within(tolerance); 
    } 
} 

public class DateTimeWithin 
{ 
    public DateTimeWithin(DateTime dateTime, TimeSpan tolerance) 
    { 
     DateTime = dateTime; 
     Tolerance = tolerance; 
    } 

    public TimeSpan Tolerance { get; private set; } 
    public DateTime DateTime { get; private set; } 

    public static bool operator ==(DateTime lhs, DateTimeWithin rhs) 
    { 
     return (lhs - rhs.DateTime).Duration() <= rhs.Tolerance; 
    } 

    public static bool operator !=(DateTime lhs, DateTimeWithin rhs) 
    { 
     return (lhs - rhs.DateTime).Duration() > rhs.Tolerance; 
    } 

    public static bool operator ==(DateTimeWithin lhs, DateTime rhs) 
    { 
     return rhs == lhs; 
    } 

    public static bool operator !=(DateTimeWithin lhs, DateTime rhs) 
    { 
     return rhs != lhs; 
    } 

    // Overloads that can deal with Nullable dates 
    public static bool operator !=(DateTimeWithin lhs, DateTime? rhs) 
    { 
     return rhs != lhs; 
    } 

    public static bool operator ==(DateTime? lhs, DateTimeWithin rhs) 
    { 
     if (!lhs.HasValue && rhs.DateTime == default(DateTime)) return true; 
     if (!lhs.HasValue) return false; 
     return (lhs.Value - rhs.DateTime).Duration() <= rhs.Tolerance; 
    } 

    public static bool operator !=(DateTime? lhs, DateTimeWithin rhs) 
    { 
     if (!lhs.HasValue && rhs.DateTime == default(DateTime)) return true; 
     if (!lhs.HasValue) return false; 
     return (lhs.Value - rhs.DateTime).Duration() > rhs.Tolerance; 
    } 

    public static bool operator ==(DateTimeWithin lhs, DateTime? rhs) 
    { 
     return rhs == lhs; 
    } 
} 

Và một thử nghiệm đơn vị nhanh chóng để xác minh tất cả mọi thứ đang làm việc một cách chính xác:

[TestMethod] 
public void DateTimeExtensions_Within_WorksWithNullable() 
{ 
    var now = DateTime.Now; 
    var dtNow1 = new DateTime?(now); 
    var dtNow2 = new DateTime?(now.AddMilliseconds(1)); 
    var dtNowish = new DateTime?(now.AddMilliseconds(25)); 
    DateTime? dtNull = null; 

    Assert.IsTrue(now == dtNow1.Within()); // Compare DateTime to DateTime? 
    Assert.IsTrue(dtNow1 == dtNow2.Within()); // Compare two DateTime? using a different syntax 
    Assert.IsTrue(dtNow1 == dtNow2.Within()); // Same value should be true 
    Assert.IsFalse(dtNow1 == dtNowish.Within()); // Outside of the default 10ms tolerance, should not be equal 
    Assert.IsTrue(dtNow1 == dtNowish.Within(TimeSpan.FromMilliseconds(50))); // ... but we can override this 
    Assert.IsFalse(dtNow1 == dtNull.Within()); // Comparing a value to null should be false 
    Assert.IsTrue(dtNull == dtNull.Within()); // ... but two nulls should be true 
} 
+0

Chỉ trong trường hợp ai đó đang tìm kiếm một cách để dễ dàng làm điều này với 'Nullable' ngày quá. giải pháp của joshperry đã hoạt động hoàn hảo cho các đối tượng 'DateTime' bình thường. –

Các vấn đề liên quan