Setara dengan Math.Min & Math.Max ​​untuk Tanggal?

369

Apa cara tercepat dan termudah untuk mendapatkan nilai Min (atau Maks) antara dua tanggal? Apakah ada yang setara dengan Math.Min (& Math.Max) untuk tanggal?

Saya ingin melakukan sesuatu seperti:

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

Jelas Matematika di atas. Tidak berfungsi karena mereka berkencan.

hawbsl
sumber

Jawaban:

416

Tidak ada kelebihan untuk nilai DateTime, tetapi Anda bisa mendapatkan nilai panjang Ticksyang berisi nilai-nilai tersebut, membandingkannya dan kemudian membuat nilai DateTime baru dari hasilnya:

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

(Perhatikan bahwa struktur DateTime juga mengandung Kindproperti, yang tidak disimpan dalam nilai baru. Ini biasanya bukan masalah; jika Anda membandingkan nilai DateTime dari berbagai jenis, perbandingannya tetap tidak masuk akal.)

Guffa
sumber
2
bagi saya ini tampaknya paling dekat dengan penggantian satu baris / setara untuk Math.Min tetapi jawaban lain juga bagus, untuk kelengkapan
hawbsl
6
-, Anda benar-benar kehilangan setiap informasi (kecuali kutu) dari System.DateTime-instance asli
Andreas Niedermair
9
@AndreasNiedermair: Jika Anda membandingkan tanggal dari berbagai jenis, Anda tidak bisa langsung membandingkannya. Saya sudah membahas ini dalam jawabannya.
Guffa
4
@ Iain: Anda selalu bisa membandingkannya, tetapi jika Anda membandingkan nilai yang tidak sebanding, hasilnya tidak berguna. Sama saja dengan nilai-nilai lain yang tidak sebanding, seperti membandingkan jarak dalam kilometer dengan jarak dalam mil; Anda dapat membandingkan nilainya dengan baik, tetapi tidak berarti apa-apa.
Guffa
4
-1 untuk handwaving about Kind. Seperti yang ditunjukkan pada jawaban @ user450, cukup mudah untuk mengonversi kedua kali menjadi UTC dan membandingkannya dengan aman tanpa membuang informasi.
piedar
484

Tidak ada metode bawaan untuk melakukan itu. Anda dapat menggunakan ungkapan:

(date1 > date2 ? date1 : date2)

untuk menemukan maksimum keduanya.

Anda dapat menulis metode generik untuk menghitung Minatau Maxuntuk jenis apa pun (asalkan Comparer<T>.Defaultdiatur dengan tepat):

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

Anda dapat menggunakan LINQ juga:

new[]{date1, date2, date3}.Max()
Mehrdad Afshari
sumber
15
Ini sebenarnya jawaban yang pantas diterima.
Larry
38

Bagaimana tentang:

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

Bekerja dengan semua jenis yang mendukung IComparable<T>atau IComparable.

Sebenarnya, dengan LINQ, alternatif lain adalah:

var min = new[] {x,y,z}.Min();
Marc Gravell
sumber
6
Pilih contoh LINQ.
Oundless
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;
    }
}

Ini memungkinkan tanggal untuk memiliki 'jenis' yang berbeda dan mengembalikan instance yang disahkan (tidak mengembalikan DateTime baru yang dibuat dari Kutu atau Milidetik).

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

Perhatikan bahwa tes ini akan gagal di Timur Greenwich ...

pengguna450
sumber
Mengapa tidak langsung membatalkan bagian ToUniversalTime ()?
David Thielen
18

Linq.Min()/ Linq.Max()pendekatan:

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(); 
Toshi
sumber
17

Jika Anda ingin menyebutnya lebih seperti Math.Max, Anda dapat melakukan sesuatu seperti badan ekspresi yang sangat singkat ini:

public static DateTime Max(params DateTime[] dates) => dates.Max();
[...]
var lastUpdatedTime = DateMath.Max(feedItemDateTime, assemblyUpdatedDateTime);
R. Salisbury
sumber
oh, itu jenius! Dengan cara ini saya tidak perlu membandingkan setiap kali, hanya satu kali setelah saya selesai dengan data. Terima kasih banyak!
tfrascaroli
Ini adalah solusi yang sangat elegan
pberggreen
2

Bagaimana dengan DateTimemetode ekstensi?

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

Pemakaian:

var maxDate = date1.MaxOf(date2);
Oundless
sumber
Saya lebih suka menggunakannya DateTime.MaxOf(dt1, dt2), tapi saya tidak tahu bagaimana melakukan itu ...
Zach Smith
@ ZachSmith Anda tidak dapat membebani kelas DateTime karena itu tidak parsial. Mungkin kita bisa menggunakan DateTimeHelper.Max (dt1, dt2)
shtse8
@ shtse8 - apa maksud Anda dengan overloading? saya sedang berpikir untuk menambahkan metode ekstensi. tetapi telah belajar bahwa tidak dapat dilakukan tanpa contoh instantiated. Kedengarannya seperti Anda mengatakan bahwa menambahkan metode ekstensi adalah bentuk kelebihan beban? saya tidak pernah mempertimbangkan itu .. apakah itu benar? sekarang saya berpikir tentang hal itu ... apa sebenarnya arti kelebihan muatan?
Zach Smith
@ ZachSmith Oh, saya pikir Anda menambahkan ekstensi yang disebut "DateTime.MaxOf (dt1, dt2)" sama seperti "DateTime.Now" yang didasarkan pada anggota statis DateTime.
shtse8
-2

Sekarang kita memiliki LINQ, Anda dapat membuat array dengan dua nilai Anda (DateTimes, TimeSpans, apa pun) dan kemudian menggunakan metode ekstensi .Max ().

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

Bunyinya bagus, seefisien Max, dan dapat digunakan kembali untuk lebih dari 2 nilai perbandingan.

Seluruh masalah di bawah ini mengkhawatirkan .Ind adalah masalah besar ... tapi saya menghindarinya dengan tidak pernah bekerja di waktu lokal, selamanya. Jika saya memiliki sesuatu yang penting mengenai waktu, saya selalu bekerja di UTC, walaupun itu berarti lebih banyak pekerjaan untuk sampai di sana.

Craig Brunetti
sumber
1
salinan jawaban saya
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/

Sergey Suvorov
sumber
Saran yang bagus (sungguh), tetapi tanpa deskripsi sulit untuk menemukan mengapa itu bagus. Tolong jelaskan di mana triknya. Tanpa deskripsi itu hanya blok kode dan bukan jawaban.
Artemix
3
pertanyaan ditandai. NET bukan Javascript
hawbsl
Maaf, tidak melihat .NET. Bagaimanapun, kami dapat menemukan tanggal minimum di sisi klien dan mengirimkannya ke server.
Sergey Suvorov
4
Anda berasumsi bahwa kita berbicara tentang asp, yang belum tentu benar. Ini juga akan sangat bodoh untuk menghitung perbedaan pada Klien, karena ada jauh lebih banyak risiko (JavaScript dinonaktifkan), itu akan menghasilkan lalu lintas yang tidak perlu dan itu akan (tergantung pada kecepatan jaringan) lebih lambat
jalgames