Tương đương với Math.Min & Math.Max ​​cho các ngày?


369

Cách nhanh nhất và dễ nhất để có được giá trị Min (hoặc Max) giữa hai ngày là gì? Có tương đương với Math.Min (& Math.Max) cho các ngày không?

Tôi muốn làm một cái gì đó như:

 if (Math.Min(Date1, Date2) < MINIMUM_ALLOWED_DATE) {
      //not allowed to do this
 }

Rõ ràng là Math.Min ở trên không hoạt động vì chúng là ngày.

Câu trả lời:


416

Không có quá tải cho các giá trị DateTime, nhưng bạn có thể nhận được giá trị dài Ticksđó là giá trị chứa, so sánh chúng và sau đó tạo giá trị DateTime mới từ kết quả:

new DateTime(Math.Min(Date1.Ticks, Date2.Ticks))

(Lưu ý rằng cấu trúc DateTime cũng chứa một thuộc Kindtính, không được giữ lại trong giá trị mới. Đây thường không phải là vấn đề; nếu bạn so sánh các giá trị DateTime của các loại khác nhau thì việc so sánh không có ý nghĩa gì cả.)


2
điều này đối với tôi dường như là gần nhất với sự thay thế một dòng / tương đương với Math.Min nhưng các câu trả lời khác cũng rất tuyệt, vì tính đầy đủ
hawbsl

6
-, bạn hoàn toàn mất tất cả thông tin (trừ bọ ve) của bản gốc System.DateTime-instance
Andreas Niedermair

9
@AndreasNiedermair: Nếu bạn đang so sánh ngày của các loại khác nhau, bạn không thể so sánh chúng ngay lập tức. Tôi đã bao gồm điều này trong câu trả lời.
Guffa

4
@Iain: Bạn luôn có thể so sánh chúng, nhưng nếu bạn so sánh các giá trị không thể so sánh được, kết quả là vô ích. Nó chỉ giống như với bất kỳ giá trị khác mà không thể so sánh, giống như so sánh một khoảng cách bằng km với một khoảng cách trong dặm; bạn có thể so sánh các giá trị tốt, nhưng nó không có nghĩa gì cả.
Guffa

4
-1 để viết tay về Kind. Như được hiển thị trong câu trả lời của @ user450, thật dễ dàng để chuyển đổi cả hai lần sang UTC và so sánh chúng một cách an toàn mà không cần loại bỏ thông tin.
piedar

484

Không có phương pháp được xây dựng để làm điều đó. Bạn có thể sử dụng biểu thức:

(date1 > date2 ? date1 : date2)

để tìm tối đa của hai.

Bạn có thể viết một phương thức chung để tính toán Minhoặc Maxcho bất kỳ loại nào (miễn Comparer<T>.Defaultlà được đặt phù hợp):

public static T Max<T>(T first, T second) {
    if (Comparer<T>.Default.Compare(first, second) > 0)
        return first;
    return second;
}

Bạn cũng có thể sử dụng LINQ:

new[]{date1, date2, date3}.Max()

15
Đây thực sự là câu trả lời xứng đáng được chấp nhận.
Larry

38

Làm thế nào về:

public static T Min<T>(params T[] values)
{
    if (values == null) throw new ArgumentNullException("values");
    var comparer = Comparer<T>.Default;
    switch(values.Length) {
        case 0: throw new ArgumentException();
        case 1: return values[0];
        case 2: return comparer.Compare(values[0],values[1]) < 0
               ? values[0] : values[1];
        default:
            T best = values[0];
            for (int i = 1; i < values.Length; i++)
            {
                if (comparer.Compare(values[i], best) < 0)
                {
                    best = values[i];
                }
            }
            return best;
    }        
}
// overload for the common "2" case...
public static T Min<T>(T x, T y)
{
    return Comparer<T>.Default.Compare(x, y) < 0 ? x : y;
}

Hoạt động với bất kỳ loại hỗ trợ IComparable<T>hoặc IComparable.

Trên thực tế, với LINQ, một cách khác là:

var min = new[] {x,y,z}.Min();

6
Bỏ phiếu cho ví dụ LINQ.
Vô dụng

20
public static class DateTool
{
    public static DateTime Min(DateTime x, DateTime y)
    {
        return (x.ToUniversalTime() < y.ToUniversalTime()) ? x : y;
    }
    public static DateTime Max(DateTime x, DateTime y)
    {
        return (x.ToUniversalTime() > y.ToUniversalTime()) ? x : y;
    }
}

Điều này cho phép các ngày có 'loại' khác nhau và trả về thể hiện được truyền vào (không trả về một DateTime mới được tạo từ Ticks hoặc Milliseconds).

[TestMethod()]
    public void MinTest2()
    {
        DateTime x = new DateTime(2001, 1, 1, 1, 1, 2, DateTimeKind.Utc);
        DateTime y = new DateTime(2001, 1, 1, 1, 1, 1, DateTimeKind.Local);

        //Presumes Local TimeZone adjustment to UTC > 0
        DateTime actual = DateTool.Min(x, y);
        Assert.AreEqual(x, actual);
    }

Lưu ý rằng thử nghiệm này sẽ thất bại ở phía Đông Greenwich ...


Tại sao không bỏ phần ToUniversalTime ()?
David Thielen

18

Linq.Min()/ Linq.Max()cách tiếp cận:

DateTime date1 = new DateTime(2000,1,1);
DateTime date2 = new DateTime(2001,1,1);

DateTime minresult = new[] { date1,date2 }.Min();
DateTime maxresult = new[] { date1,date2 }.Max(); 

17

Nếu bạn muốn gọi nó giống như Math.Max, bạn có thể làm một cái gì đó giống như phần thân biểu thức rất ngắn này:

public static DateTime Max(params DateTime[] dates) => dates.Max();
[...]
var lastUpdatedTime = DateMath.Max(feedItemDateTime, assemblyUpdatedDateTime);

oh, đó là thiên tài! Bằng cách này, tôi không phải so sánh mỗi lần, chỉ một lần sau khi tôi hoàn thành dữ liệu. Cảm ơn rât nhiều!
tfrascaroli

Đây là một giải pháp rất thanh lịch
pberggreen

2

Làm thế nào về một DateTimephương pháp mở rộng?

public static DateTime MaxOf(this DateTime instance, DateTime dateTime)
{
    return instance > dateTime ? instance : dateTime;
}

Sử dụng:

var maxDate = date1.MaxOf(date2);

Tôi thích sử dụng nó như DateTime.MaxOf(dt1, dt2), nhưng tôi không biết làm thế nào ...
Zach Smith

@ZachSmith Bạn không thể quá tải lớp DateTime vì nó không phải là một phần. Có lẽ chúng ta có thể sử dụng DateTimeHelper.Max (dt1, dt2)
shtse8

@ shtse8 - Ý bạn là gì khi quá tải? tôi đã nghĩ đến việc thêm một phương pháp mở rộng. nhưng đã học được rằng không thể được thực hiện mà không có một ví dụ khởi tạo. Nghe có vẻ như bạn đang nói rằng thêm một phương thức mở rộng là một hình thức quá tải? Tôi chưa bao giờ nghĩ rằng .. điều đó có đúng không? bây giờ tôi nghĩ về nó ... chính xác thì quá tải có nghĩa là gì?
Zach Smith

@ZachSmith Ồ, tôi nghĩ rằng bạn đang thêm một tiện ích mở rộng có tên "DateTime.MaxOf (dt1, dt2)" giống như "DateTime.Now" dựa trên các thành viên tĩnh DateTime.
shtse8

-2

Bây giờ chúng tôi có LINQ, bạn có thể tạo một mảng với hai giá trị của mình (DateTimes, TimeSpans, bất cứ điều gì) và sau đó sử dụng phương thức mở rộng .Max ().

var values = new[] { Date1, Date2 }; 
var max = values.Max(); 

Nó đọc rất hay, nó hiệu quả như Max có thể, và nó có thể tái sử dụng cho hơn 2 giá trị so sánh.

Toàn bộ vấn đề bên dưới đáng lo ngại .Kind là một vấn đề lớn ... nhưng tôi tránh điều đó bằng cách không bao giờ làm việc trong thời gian địa phương, bao giờ. Nếu tôi có một cái gì đó quan trọng liên quan đến thời gian, tôi luôn làm việc trong UTC, ngay cả khi điều đó có nghĩa là có nhiều công việc hơn để đạt được điều đó.


1
bản sao câu trả lời của tôi
Toshi

-3
// Two different dates
var date1 = new Date(2013, 05, 13); 
var date2 = new Date(2013, 04, 10) ;
// convert both dates in milliseconds and use Math.min function
var minDate = Math.min(date1.valueOf(), date2.valueOf());
// convert minDate to Date
var date = new Date(minDate); 

http://jsfiddle.net/5CR37/


Đề xuất tốt (thực sự), nhưng không có mô tả thật khó để tìm ra lý do tại sao nó tốt. Hãy mô tả nơi mà các mẹo là. Không có mô tả, nó chỉ là một khối mã và không phải là một câu trả lời.
Artemix

3
câu hỏi được gắn thẻ .NET không phải Javascript
hawbsl

Xin lỗi, đã không thông báo .NET. Dù sao, chúng tôi có thể tìm thấy ngày tối thiểu ở phía khách hàng và gửi nó đến máy chủ.
Serge Suvorov

4
Bạn cho rằng chúng ta đang nói về asp, điều này không nhất thiết phải đúng. Cũng sẽ khá ngu ngốc khi xác định sự khác biệt trên Máy khách, bởi vì có nhiều rủi ro hơn (JavaScript bị vô hiệu hóa), nó sẽ tạo ra lưu lượng truy cập không cần thiết và sẽ (tùy thuộc vào tốc độ mạng) chậm hơn
kết hợp vào
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.