เทียบเท่า Math.Min และ Math.Max ​​สำหรับวันที่หรือไม่


369

วิธีที่เร็วและง่ายที่สุดในการรับค่า Min (หรือ Max) ระหว่างสองวันคืออะไร มีเทียบเท่ากับ Math.Min (& Math.Max) สำหรับวันที่?

ฉันต้องการทำสิ่งที่ชอบ:

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

เห็นได้ชัดว่า Math.Min ข้างต้นไม่ทำงานเพราะเป็นวันที่

คำตอบ:


416

ไม่มีการโอเวอร์โหลดสำหรับค่า DateTime แต่คุณสามารถรับค่า long Ticksซึ่งเป็นค่าที่มีให้เปรียบเทียบเปรียบเทียบแล้วสร้างค่า DateTime ใหม่จากผลลัพธ์:

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

(โปรดทราบว่าโครงสร้าง DateTime ยังมีKindคุณสมบัติที่ไม่ได้เก็บไว้ในค่าใหม่โดยปกตินี่ไม่ใช่ปัญหาหากคุณเปรียบเทียบค่า DateTime ในรูปแบบต่าง ๆ การเปรียบเทียบก็ไม่สมเหตุสมผล)


2
นี้ดูเหมือนว่าฉันจะใกล้เคียงกับการเปลี่ยนสายหนึ่ง / เทียบเท่า Math.Min แต่คำตอบอื่น ๆ ได้ดีเกินไปเพื่อความสมบูรณ์
hawbsl

6
- คุณหลวมทุกข้อมูล (ยกเว้นเห็บ) ของต้นฉบับSystem.DateTime
Andreas Niedermair

9
@AndreasNiedermair: หากคุณกำลังเปรียบเทียบวันที่ที่แตกต่างกันคุณก็ไม่สามารถเปรียบเทียบได้เลย ฉันพูดถึงเรื่องนี้แล้วในคำตอบ
Guffa

4
@Iain: คุณสามารถเปรียบเทียบได้เสมอแต่ถ้าคุณเปรียบเทียบค่าที่ไม่สามารถเทียบเคียงได้ผลลัพธ์จะไร้ประโยชน์ มันก็เหมือนกับค่าอื่น ๆ ที่ไม่สามารถเปรียบเทียบได้เช่นการเปรียบเทียบระยะทางเป็นกิโลเมตรกับระยะทางเป็นไมล์ คุณสามารถเปรียบเทียบค่าได้ดี แต่มันไม่ได้มีความหมายอะไรเลย
Guffa

4
-1 สำหรับ handwaving เกี่ยวกับชนิด ดังที่แสดงในคำตอบของ @ user450 มันค่อนข้างง่ายที่จะแปลงทั้งสองครั้งเป็น UTC และเปรียบเทียบอย่างปลอดภัยโดยไม่ต้องทิ้งข้อมูล
piedar

484

ไม่มีวิธีการในการทำเช่นนั้น คุณสามารถใช้นิพจน์:

(date1 > date2 ? date1 : date2)

เพื่อหาค่าสูงสุดของทั้งสอง

คุณสามารถเขียนวิธีการทั่วไปเพื่อคำนวณMinหรือMaxสำหรับประเภทใด ๆ (โดยComparer<T>.Defaultมีการตั้งค่าอย่างเหมาะสม):

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

คุณสามารถใช้ LINQ ได้เช่นกัน:

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

15
นี่คือคำตอบที่สมควรได้รับการยอมรับ
Larry

38

เกี่ยวกับ:

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

ทำงานร่วมกับประเภทใด ๆ ที่สนับสนุนหรือIComparable<T>IComparable

จริงๆแล้วด้วย LINQ ทางเลือกอื่นคือ:

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

6
ลงคะแนนสำหรับตัวอย่าง LINQ
กำหนด

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

สิ่งนี้ทำให้วันที่มี 'ชนิด' ที่แตกต่างกันและส่งคืนอินสแตนซ์ที่ส่งผ่าน (ไม่ส่งคืน DateTime ใหม่ที่สร้างจากเห็บหรือมิลลิวินาที)

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

โปรดทราบว่าการทดสอบนี้จะล้มเหลวทางตะวันออกของกรีนวิช ...


ทำไมไม่เพียงแค่วางส่วน ToUniversalTime ()
David Thielen

18

Linq.Min()/ Linq.Max()วิธีการ:

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

ถ้าคุณต้องการเรียกมันว่า Math.Max ​​คุณสามารถทำสิ่งนี้ได้เช่นเนื้อความที่สั้นมาก ๆ :

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

โอ้นั่นคืออัจฉริยะ! วิธีนี้ฉันไม่จำเป็นต้องเปรียบเทียบแต่ละครั้งเพียงครั้งเดียวหลังจากฉันทำกับข้อมูล ขอบคุณมาก!
tfrascaroli

นี่เป็นทางออกที่หรูหรามาก
pberggreen

2

วิธีการเกี่ยวกับวิธีการDateTimeขยาย?

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

การใช้งาน:

var maxDate = date1.MaxOf(date2);

ฉันชอบที่จะใช้มันเป็นDateTime.MaxOf(dt1, dt2)แต่ฉันไม่รู้วิธีการทำเช่นนั้น ...
Zach Smith

@ZachSmith คุณไม่สามารถโหลดคลาส DateTime มากเกินไปเนื่องจากไม่ได้เป็นบางส่วน บางทีเราสามารถใช้ DateTimeHelper.Max (dt1, dt2)
shtse8

@ shtse8 - คุณหมายถึงอะไรโดยการบรรทุกเกินพิกัด? ฉันกำลังคิดที่จะเพิ่มวิธีการขยาย แต่ได้เรียนรู้ตั้งแต่ที่ไม่สามารถทำได้โดยไม่ต้องยกตัวอย่าง ดูเหมือนคุณจะบอกว่าการเพิ่มวิธีการขยายเป็นรูปแบบของการบรรทุกเกินพิกัดหรือไม่? ฉันไม่เคยคิดเลยว่า .. ถูกต้องเหรอ? ตอนนี้ที่ฉันคิดเกี่ยวกับมัน ...
Zach Smith

@ ZachSmith โอ้ฉันคิดว่าคุณกำลังเพิ่มส่วนขยายชื่อ "DateTime.MaxOf (dt1, dt2)" เช่นเดียวกับ "DateTime.Now" ซึ่งขึ้นอยู่กับสมาชิกแบบคงที่ DateTime
shtse8

-2

ตอนนี้เรามี LINQ แล้วคุณสามารถสร้างอาร์เรย์ที่มีสองค่าของคุณ (DateTimes, TimeSpans หรืออะไรก็ตาม) แล้วใช้วิธีการขยาย. Max ()

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

มันอ่านได้ดีมีประสิทธิภาพมากที่สุดและสามารถนำมาใช้ใหม่ได้มากกว่า 2 ค่า

ปัญหาทั้งหมดด้านล่างกังวลเกี่ยวกับ. Kind เป็นเรื่องใหญ่ ... แต่ฉันหลีกเลี่ยงสิ่งนั้นโดยไม่เคยทำงานในเวลาท้องถิ่น ถ้าฉันมีบางสิ่งบางอย่างที่สำคัญเกี่ยวกับเวลาฉันมักจะทำงานใน UTC แม้ว่ามันจะหมายถึงการทำงานมากขึ้นที่จะได้มี


1
สำเนาคำตอบของฉัน
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/


คำแนะนำที่ดี (จริงๆ) แต่ไม่มีคำอธิบายมันยากที่จะหาสาเหตุที่ดี กรุณาอธิบายว่าเคล็ดลับอยู่ที่ไหน หากไม่มีคำอธิบายมันเป็นเพียงบล็อคโค้ดและไม่ใช่คำตอบ
Artemix

3
มีการติดแท็ก. NET ไม่ใช่ Javascript
hawbsl

ขออภัยไม่ได้สังเกต. NET อย่างไรก็ตามเราสามารถหาวันที่ขั้นต่ำทางฝั่งไคลเอ็นต์และส่งไปยังเซิร์ฟเวอร์
Sergey Suvorov

4
คุณคิดว่าเรากำลังพูดถึงงูเห่าซึ่งไม่ถูกต้อง นอกจากนี้ยังค่อนข้างโง่ที่จะประกาศความแตกต่างของไคลเอนต์เนื่องจากมีความเสี่ยงมากกว่า (ปิดการใช้งาน JavaScript) มันจะสร้างปริมาณการใช้งานที่ไม่จำเป็นและจะช้าลง (ขึ้นอยู่กับความเร็วเครือข่าย)
jalgames
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.