ตรวจสอบว่าช่วงสองวันที่ทับซ้อนกันหรือไม่


1248

เมื่อกำหนดช่วงวันที่สองช่วงวิธีที่ง่ายที่สุดหรือมีประสิทธิภาพมากที่สุดในการพิจารณาว่าช่วงวันที่สองช่วงนี้ทับซ้อนกันกันอย่างไร

ตัวอย่างเช่นสมมติว่าเรามีช่วงแสดงโดยตัวแปร DateTime StartDate1ไปEndDate1 และ จะStartDate2EndDate2



@ CharlesBretana ขอบคุณสำหรับสิ่งที่คุณพูดถูก - มันเกือบจะเหมือนคำถามสองมิติของฉัน!
เอียนเนลสัน

2
คล้ายกันมากกับstackoverflow.com/questions/117962/…
Steven A. Lowe

2
แบ่งสถานการณ์ 'วันที่ทั้งสองช่วงตัดกัน' เป็นกรณี ๆ (มีสองแบบ) จากนั้นทดสอบสำหรับแต่ละกรณี
พันเอก Panic

1
รหัสนี้ใช้งานได้ดี คุณสามารถดูคำตอบของฉันที่นี่: stackoverflow.com/a/16961719/1534785
Jeyhun Rahimov

คำตอบ:


2289

(StartA <= EndB) และ (EndA> = StartB)

หลักฐาน:
ให้ ConditionA หมายความว่า DateRange A สมบูรณ์หลังจาก DateRange B
_ |---- DateRange A ------| |---Date Range B -----| _
(จริงถ้าStartA > EndB)

ให้ ConditionB หมายความว่า DateRange A นั้นสมบูรณ์ก่อน DateRange B
|---- DateRange A -----| _ _ |---Date Range B ----|
(จริงถ้าEndA < StartB)

จากนั้นจึงมีการทับซ้อนกันถ้าทั้ง A Nor B เป็นจริง -
(หากช่วงหนึ่งไม่สมบูรณ์หลังจากช่วงอื่น ๆ
หรือไม่สมบูรณ์ก่อนอีกช่วงหนึ่งพวกเขาจะต้องทับซ้อนกัน)

ตอนนี้หนึ่งในกฎของDe Morganกล่าวว่า:

Not (A Or B) <=> Not A And Not B

ซึ่งแปลเป็น: (StartA <= EndB) and (EndA >= StartB)


หมายเหตุ: รวมถึงเงื่อนไขที่ขอบซ้อนกันทุกประการ หากคุณต้องการยกเว้นสิ่งเหล่านี้ให้
เปลี่ยน>=โอเปอเรเตอร์เป็น>และ<= เพื่อ<


โน้ต 2. ขอขอบคุณที่ @Baodad ดูบล็อกนี้ที่ทับซ้อนที่เกิดขึ้นจริงเป็นอย่างน้อย:
{ endA-startA, endA - startB, endB-startA, endB - startB}

(StartA <= EndB) and (EndA >= StartB) (StartA <= EndB) and (StartB <= EndA)


Note3 ขอบคุณ @tomosius รุ่นที่สั้นกว่าอ่าน:
DateRangesOverlap = max(start1, start2) < min(end1, end2)
นี่เป็นช็อตคัทการสร้างประโยคสำหรับการใช้งานที่ยาวนานขึ้นซึ่งรวมถึงการตรวจสอบพิเศษเพื่อตรวจสอบว่าวันที่เริ่มต้นเป็นวันที่หรือก่อนสิ้นสุดวันที่ สืบทอดสิ่งนี้จากด้านบน:

หากเริ่มต้นและสิ้นสุดวันที่สามารถออกคำสั่งเช่นถ้าเป็นไปได้ว่าstartA > endAหรือstartB > endBแล้วคุณยังมีการตรวจสอบว่าพวกเขาอยู่ในการสั่งซื้อเพื่อให้หมายความว่าคุณต้องเพิ่มสองกฎความถูกต้องเพิ่มเติม:
(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB) หรือ:
(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB) หรือ
(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB)) หรือ:
(Max(StartA, StartB) <= Min(EndA, EndB)

แต่ในการติดตั้งMin()และMax()คุณต้องใช้โค้ด (โดยใช้ภาษาซีประกอบไปด้วยความอดทน):
(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)


29
นี่คือตรรกะที่ง่ายขึ้นอยู่กับสมมติฐานสองข้อนี้: 1) StartA <EndA; 2) StartB <EndB ดูเหมือนว่าจะชัดเจน แต่ในความเป็นจริงข้อมูลอาจมาจากแหล่งที่ไม่รู้จักเช่นการป้อนข้อมูลของผู้ใช้หรือฐานข้อมูลโดยไม่มีการฆ่าเชื้อ โปรดทราบว่าคุณจะต้องตรวจสอบข้อมูลอินพุตเพื่อให้แน่ใจว่าสมมติฐานทั้งสองนั้นเป็นจริงก่อนที่คุณจะสามารถใช้ตรรกะที่ทำให้เข้าใจง่ายนี้ได้หรือทุกอย่างจะแยกออกจากกัน บทเรียนเรียนรู้จากประสบการณ์ของตัวเอง;)
Devy

12
@Devy คุณถูกต้อง ยกเว้นว่าจะใช้งานได้หาก startA = endA แน่นอนว่าเป็นสิ่งที่คำStartและความEndหมาย หากคุณมีสองตัวแปรชื่อด้านบนและด้านล่างหรือตะวันออกและตะวันตกหรือ HighValue และ LoValue ก็สามารถสันนิษฐานหรือบอกเป็นนัยว่าบางสิ่งบางอย่างหรือบางคนควรจะมั่นใจว่าหนึ่งในคู่ของค่าจะไม่ถูกเก็บไว้ในตัวแปรตรงกันข้าม - เพียงหนึ่งในสองคู่เท่านั้นเพราะมันจะทำงานหากค่าทั้งคู่เปลี่ยนไป
Charles Bretana

15
คุณสามารถเพิ่ม nullable ได้อย่างง่ายดายstartและend(ด้วยความหมายว่า "null start" = "จากจุดเริ่มต้นของเวลา" และ "null end" = "ถึงจุดสิ้นสุดของเวลา") เช่นนี้:(startA === null || endB === null || startA <= endB) && (endA === null || startB === null || endA >= startB)
Kevin Robatel

9
คำตอบที่ดีที่สุดใน Stackexchange! รู้สึกดีที่เห็นคำอธิบายว่าทำไมสูตรสมาร์ทนี้จึงใช้งานได้!
Abeer Sul

4
นี่คือรูปแบบกะทัดรัดที่สุดที่ฉันนึกได้ซึ่งจะคืนค่าเท็จในกรณีที่อินพุตไม่ถูกต้อง (วันที่เริ่ม> วันที่สิ้นสุด =)DateRangesOverlap = max(start1, start2) < min(end1, end2)
tomosius

406

ฉันเชื่อว่ามันเพียงพอที่จะบอกว่าทั้งสองช่วงทับกันถ้า:

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)

76
ฉันพบว่า(StartDate1 <= EndDate2) and (EndDate1 >= StartDate2)สัญกรณ์ง่ายต่อการเข้าใจ Range1 อยู่ด้านซ้ายเสมอในการทดสอบ
AL

8
สิ่งนี้จะรวมวันที่เริ่มต้นและวันที่สิ้นสุด เปลี่ยน<=เป็น<ถ้าเริ่มต้นรวมและสิ้นสุดเป็นเอกสิทธิ์
Richard Schneider

สิ่งนี้จะทำงานได้ดีมากแม้ว่า startDate2 จะอยู่ก่อน startDate1 ดังนั้นไม่จำเป็นต้องสันนิษฐานว่า startDate1 นั้นเร็วกว่า startDate2
Shehan Simen

3
ฉันพบ (StartDate1 <= EndDate2) และ (StartDate2 <= EndDate1) สัญกรณ์ (ตามคำตอบ) ง่ายต่อการเข้าใจมากกว่าที่อยู่ในคำตอบอื่น ๆ
apc

วิธีการปรับเพื่อให้ทำงานกับข้อมูลที่มี StartDate1 และ / หรือ EndDate1 ได้อย่างไร รหัสจะถือว่า StartDate1 และ EndDate1 นั้นมีอยู่เสมอ จะเกิดอะไรขึ้นถ้าได้รับ StartDate1 แต่ไม่ได้รับ EndDate1 หรือ EndDate1 ที่ได้รับ แต่ไม่ใช่ StartDate1 วิธีจัดการกรณีพิเศษนี้?
juFo

117

บทความนี้ช่วงเวลาห้องสมุดสำหรับ. NETอธิบายความสัมพันธ์ของสองช่วงเวลาโดยการแจงนับPeriodRelation :

// ------------------------------------------------------------------------
public enum PeriodRelation
{
    After,
    StartTouching,
    StartInside,
    InsideStartTouching,
    EnclosingStartTouching,
    Enclosing,
    EnclosingEndTouching,
    ExactMatch,
    Inside,
    InsideEndTouching,
    EndInside,
    EndTouching,
    Before,
} // enum PeriodRelation

ป้อนคำอธิบายรูปภาพที่นี่


ดีฉันได้ใช้พีชคณิตช่วง Allens ใน Java ด้วยดูAPI ของ IntervalRelation และ IsoInterval
Meno Hochschild

80

สำหรับเหตุผลเกี่ยวกับความสัมพันธ์ชั่วคราว (หรือความสัมพันธ์ระหว่างช่วงเวลาอื่น ๆ มานั้น) พิจารณาอัลเลนช่วงพีชคณิต มันอธิบายถึง 13 ความสัมพันธ์ที่เป็นไปได้ที่สองช่วงเวลาสามารถมีความเคารพซึ่งกันและกัน คุณสามารถค้นหาข้อมูลอ้างอิงอื่น ๆ - "Allen Interval" ดูเหมือนจะเป็นคำที่ใช้ในการค้นหา คุณยังสามารถค้นหาข้อมูลเกี่ยวกับการดำเนินการเหล่านี้ได้ในแอพพลิเคชั่นการพัฒนาเชิงเวลาของ Snodgrass ใน SQL (PDF มีให้ทางออนไลน์ที่ URL) และในวันที่ Darwen และ Lorentzos Temporal Data และ Relational Model (2002) หรือ เวลาและทฤษฎีเชิงสัมพันธ์: ฐานข้อมูลชั่วคราว Relational Model และ SQL (2014; รุ่นที่สองของ TD&RM อย่างมีประสิทธิภาพ)


คำตอบสั้น ๆ (ish) คือ: กำหนดช่วงเวลาสองวันAและBด้วยองค์ประกอบ.startและ.endและข้อ จำกัด.start <= .endจากนั้นช่วงเวลาสองช่วงจะทับซ้อนกันถ้า:

A.end >= B.start AND A.start <= B.end

คุณสามารถปรับใช้>=vs >และ<=vs <เพื่อตอบสนองความต้องการของคุณสำหรับระดับของการทับซ้อน


ความคิดเห็น ErikE:

คุณจะได้ 13 ถ้าคุณนับเรื่องตลก ๆ ... ฉันจะได้ "15 ความสัมพันธ์ที่เป็นไปได้ที่ช่วงเวลาสองช่วงสามารถมีได้" เมื่อฉันคลั่งไคล้มัน ด้วยการนับที่สมเหตุสมผลฉันได้เพียงหกและถ้าคุณละทิ้งความสนใจว่า A หรือ B มาก่อนฉันจะได้แค่สาม (ไม่มีจุดตัดแยกบางส่วนหนึ่งในทั้งหมด) 15 ไปเช่นนี้: [ก่อนหน้า: ก่อน, เริ่ม, ภายใน, จบ, หลัง], [เริ่มต้น: เริ่ม, ภายใน, จบ, หลัง], [ภายใน: ภายใน, ปลาย, หลัง], [ปลาย: ปลาย, หลัง], [ หลังจากที่: หลังจาก]

ฉันคิดว่าคุณไม่สามารถนับทั้งสองรายการ 'ก่อนหน้า: ก่อนหน้า' และ 'หลัง: หลังจาก' ฉันเห็นรายการ 7 รายการถ้าคุณเทียบความสัมพันธ์กับผู้รุกราน (ดูแผนภาพใน Wikipedia URL ที่อ้างอิงมันมี 7 รายการซึ่ง 6 รายการนั้นมีค่าผกผันที่แตกต่างกัน และสามคนนั้นมีเหตุผลหรือไม่ขึ้นอยู่กับความต้องการของคุณ

----------------------|-------A-------|----------------------
    |----B1----|
           |----B2----|
               |----B3----|
               |----------B4----------|
               |----------------B5----------------|
                      |----B6----|
----------------------|-------A-------|----------------------
                      |------B7-------|
                      |----------B8-----------|
                         |----B9----|
                         |----B10-----|
                         |--------B11--------|
                                      |----B12----|
                                         |----B13----|
----------------------|-------A-------|----------------------

1
คุณจะได้ 13 ถ้าคุณนับเรื่องตลก ๆ ... ฉันจะได้ "15 ความสัมพันธ์ที่เป็นไปได้ที่ช่วงเวลาสองช่วงสามารถมีได้" เมื่อฉันคลั่งไคล้มัน ด้วยการนับที่สมเหตุสมผลฉันได้เพียงหกและถ้าคุณละทิ้งความสนใจว่า A หรือ B มาก่อนฉันจะได้สามเท่านั้น (ไม่มีจุดตัดบางส่วนตัดกันอย่างใดอย่างหนึ่งภายในทั้งหมด) 15 ไปเช่นนี้: [ก่อนหน้า: ก่อน, เริ่ม, ภายใน, จบ, หลัง], [เริ่มต้น: เริ่ม, ภายใน, จบ, หลัง], [ภายใน: ภายใน, ปลาย, หลัง], [ปลาย: ปลาย, หลัง], [ หลังจากที่: หลังจาก]
ErikE

@Emtucifor: ฉันคิดว่าคุณไม่สามารถนับรายการทั้งสองได้ 'before: before' และ 'after: after'
Jonathan Leffler

การอัปเดตของคุณอีกครั้ง: B1 ถึง A คือก่อนหน้า: ก่อนหน้านี้และ B13 ถึง A คือหลัง: หลังจาก แผนภาพที่ดีของคุณไม่มีจุดเริ่มต้น: เริ่มระหว่าง B5 B6 และสิ้นสุด: สิ้นสุดระหว่าง B11 และ B12 หากอยู่บนจุดสิ้นสุดคุณจะต้องนับดังนั้นคะแนนรวมสุดท้ายคือ 15 ไม่ใช่ 13 ฉันไม่คิดว่าจุดสิ้นสุดมีความสำคัญดังนั้นฉันจึงนับเป็นการส่วนตัว [ก่อนหน้า: ก่อนหน้าภายในหลัง] , [ภายใน: ภายใน, หลัง], [หลังจาก: หลังจาก] ซึ่งมาถึง 6 ฉันคิดว่าจุดสิ้นสุดทั้งหมดนั้นเป็นเพียงความสับสนว่าขอบเขตนั้นครอบคลุมหรือเป็นเอกสิทธิ์ ความพิเศษของจุดสิ้นสุดไม่ได้เปลี่ยนความสัมพันธ์หลัก!
ErikE

นั่นคือในรูปแบบของฉันสิ่งเหล่านี้เทียบเท่า: (B2, B3, B4), (B6, B7, B9, B10), (B8, B11, B12) ฉันรู้ว่า B7 หมายถึงข้อมูลที่ทั้งสองช่วงตรงกันอย่างแน่นอน แต่ฉันไม่มั่นใจว่าข้อมูลเพิ่มเติมนี้ควรเป็นส่วนหนึ่งของความสัมพันธ์ทางแยกพื้นฐาน ตัวอย่างเช่นเมื่อช่วงเวลาสองช่วงมีความยาวเท่ากันแม้ว่าจะไม่เกิดขึ้นพร้อมกันหรือทับซ้อนกันควรถือว่าเป็น "ความสัมพันธ์" อื่นหรือไม่ ฉันบอกว่าไม่และการเห็นว่ามุมมองเพิ่มเติมนี้เป็นสิ่งเดียวที่ทำให้ B7 แตกต่างจาก B6 ดังนั้นฉันคิดว่าการมีจุดปลายแยกเป็นกรณี ๆ ทำให้สิ่งต่าง ๆ ไม่สอดคล้องกัน
ErikE

@Emtucifor: ตกลง - ฉันเห็นว่าทำไมฉันระบุไม่ถูกต้อง 'ก่อน: ก่อน' และ 'หลังจาก: หลังจาก' เป็นรายการ; อย่างไรก็ตามฉันไม่สามารถนึกภาพว่ารายการ 'เริ่มต้น: เริ่ม' และ 'สิ้นสุด: สิ้นสุด' ควรมีลักษณะอย่างไร เนื่องจากคุณไม่สามารถแก้ไขไดอะแกรมของฉันคุณสามารถส่งอีเมลฉัน (ดูโปรไฟล์ของฉัน) พร้อมสำเนาที่ดัดแปลงของไดอะแกรมที่แสดงความสัมพันธ์ 'start: start' และ 'end: end' ได้หรือไม่ ฉันไม่มีปัญหาสำคัญกับการจัดกลุ่มของคุณ
Jonathan Leffler

30

หากควรคำนวณการทับซ้อนกันด้วยคุณสามารถใช้สูตรต่อไปนี้:

overlap = max(0, min(EndDate1, EndDate2) - max(StartDate1, StartDate2))
if (overlap > 0) { 
    ...
}

ทับซ้อนกันเป็นระยะเวลาที่ทั้งสองเหตุการณ์แบ่งปัน? มันใช้งานได้กับเหตุการณ์ที่แตกต่างกันทั้งหมดหรือไม่
NSjonas

18

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

จากนั้นคุณสามารถตรวจจับการทับซ้อนกันได้ถ้าช่วงเริ่มต้นอื่นน้อยกว่าหรือเท่ากับช่วงสิ้นสุดช่วงแรก (ถ้าช่วงนั้นรวมอยู่ด้วยซึ่งมีทั้งเวลาเริ่มต้นและสิ้นสุด) หรือน้อยกว่า (ถ้าช่วงนั้นรวมช่วงเริ่มต้นและไม่รวมช่วงสิ้นสุด) .

สมมติว่ามีทั้งสองด้านมีความเป็นไปได้เพียงสี่อย่างเท่านั้นซึ่งความเป็นไปได้ที่ไม่ทับซ้อนกัน:

|----------------------|        range 1
|--->                           range 2 overlap
 |--->                          range 2 overlap
                       |--->    range 2 overlap
                        |--->   range 2 no overlap

จุดสิ้นสุดของช่วง 2 ไม่ได้ใส่เข้าไป ดังนั้นในรหัสหลอก:

def doesOverlap (r1, r2):
    if r1.s > r2.s:
        swap r1, r2
    if r2.s > r1.e:
        return false
    return true

สิ่งนี้สามารถทำให้เข้าใจง่ายยิ่งขึ้นไปอีก:

def doesOverlap (r1, r2):
    if r1.s > r2.s:
        swap r1, r2
    return r2.s <= r1.e

หากช่วงนั้นรวมอยู่ที่จุดเริ่มต้นและแบบเอกสิทธิ์ในตอนท้ายคุณเพียงแค่ต้องแทนที่>ด้วย>=ในifคำสั่งที่สอง(สำหรับส่วนรหัสแรก: ในส่วนรหัสที่สองคุณจะใช้<แทน<=):

|----------------------|        range 1
|--->                           range 2 overlap
 |--->                          range 2 overlap
                       |--->    range 2 no overlap
                        |--->   range 2 no overlap

คุณ จำกัด จำนวนของการตรวจสอบที่คุณต้องทำอย่างมากเนื่องจากคุณลบครึ่งหนึ่งของพื้นที่ปัญหาก่อนโดยตรวจสอบให้แน่ใจว่าช่วงที่ 1 ไม่เริ่มต้นหลังจากช่วงที่ 2


2
+1 สำหรับการกล่าวถึงปัญหารวม / พิเศษ ฉันจะตอบคำตอบด้วยตัวเองเมื่อฉันมีเวลา แต่ไม่ต้องการตอนนี้ สิ่งนี้คือคุณแทบจะไม่ยอมให้ทั้งจุดเริ่มต้นและจุดสิ้นสุดรวมเข้าด้วยกัน ในอุตสาหกรรมของฉันมันเป็นเรื่องธรรมดาที่จะปฏิบัติต่อการเริ่มต้นอย่างสุดเหวี่ยงและจบโดยรวม แต่วิธีใดวิธีหนึ่งก็ดีถ้าคุณอยู่อย่างสม่ำเสมอ นี่เป็นคำตอบแรกที่ถูกต้องสำหรับคำถามนี้ ... IMO
Brian Gideon

14

นี่เป็นอีกวิธีการใช้ JavaScript ความเชี่ยวชาญพิเศษของโซลูชันของฉัน:

  • จัดการค่า null เป็นอนันต์
  • สมมติว่าขอบเขตล่างถูกรวมและขอบเขตบนเป็นเอกสิทธิ์
  • มาพร้อมกับชุดทดสอบ

การทดสอบจะขึ้นอยู่กับจำนวนเต็ม แต่เนื่องจากวัตถุวันที่ใน JavaScript นั้นเทียบเคียงได้คุณก็สามารถโยนวัตถุวันที่สองรายการได้เช่นกัน หรือคุณสามารถโยนในเวลาประทับมิลลิวินาที

รหัส:

/**
 * Compares to comparable objects to find out whether they overlap.
 * It is assumed that the interval is in the format [from,to) (read: from is inclusive, to is exclusive).
 * A null value is interpreted as infinity
 */
function intervalsOverlap(from1, to1, from2, to2) {
    return (to2 === null || from1 < to2) && (to1 === null || to1 > from2);
}

แบบทดสอบ:

describe('', function() {
    function generateTest(firstRange, secondRange, expected) {
        it(JSON.stringify(firstRange) + ' and ' + JSON.stringify(secondRange), function() {
            expect(intervalsOverlap(firstRange[0], firstRange[1], secondRange[0], secondRange[1])).toBe(expected);
        });
    }

    describe('no overlap (touching ends)', function() {
        generateTest([10,20], [20,30], false);
        generateTest([20,30], [10,20], false);

        generateTest([10,20], [20,null], false);
        generateTest([20,null], [10,20], false);

        generateTest([null,20], [20,30], false);
        generateTest([20,30], [null,20], false);
    });

    describe('do overlap (one end overlaps)', function() {
        generateTest([10,20], [19,30], true);
        generateTest([19,30], [10,20], true);

        generateTest([10,20], [null,30], true);
        generateTest([10,20], [19,null], true);
        generateTest([null,30], [10,20], true);
        generateTest([19,null], [10,20], true);
    });

    describe('do overlap (one range included in other range)', function() {
        generateTest([10,40], [20,30], true);
        generateTest([20,30], [10,40], true);

        generateTest([10,40], [null,null], true);
        generateTest([null,null], [10,40], true);
    });

    describe('do overlap (both ranges equal)', function() {
        generateTest([10,20], [10,20], true);

        generateTest([null,20], [null,20], true);
        generateTest([10,null], [10,null], true);
        generateTest([null,null], [null,null], true);
    });
});

ผลลัพธ์เมื่อทำงานด้วยกรรม & จัสมิน & PhantomJS:

PhantomJS 1.9.8 (Linux): ดำเนินการ 20 จาก 20 สำเร็จ (0.003 วินาที / 0.004 วินาที)


9

ฉันจะทำ

StartDate1.IsBetween(StartDate2, EndDate2) || EndDate1.IsBetween(StartDate2, EndDate2)

IsBetweenบางสิ่งอยู่ที่ไหน

    public static bool IsBetween(this DateTime value, DateTime left, DateTime right) {
        return (value > left && value < right) || (value < left && value > right);
    }

ฉันต้องการ (เหลือ <ค่า && มูลค่า <ขวา) || (ขวา <ค่า && มูลค่า <ซ้าย) สำหรับวิธีนี้
แพทริค Huizinga

ขอบคุณสำหรับสิ่งนี้. ทำให้ทุกอย่างง่ายขึ้นในหัวของฉัน
sshow

1
ทำไมคุณต้องตรวจสอบสี่เงื่อนไขเมื่อคุณต้องตรวจสอบสองเงื่อนไขเท่านั้น ล้มเหลว.
ErikE

3
อาขอโทษฉันเห็นว่าตอนนี้คุณอนุญาตให้ช่วงอยู่ในลำดับที่กลับกัน (StartDateX> EndDateX) แปลก. อย่างไรก็ตามถ้า StartDate1 น้อยกว่า StartDate2 และ EndDate1 มากกว่า EndDate2 ล่ะ รหัสที่คุณให้มาจะไม่ตรวจจับเงื่อนไขการซ้อนทับนี้
ErikE

3
สิ่งนี้จะไม่ส่งคืนเท็จหรือไม่หาก Date1 มีทั้ง Date2 จากนั้น StartDate1 อยู่ก่อนหน้า StartDate2 และ EndDate1 จะอยู่หลัง EndDate2
user158037

9

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือรหัสที่ใช้เวทมนตร์:

 var isOverlapping =  ((A == null || D == null || A <= D) 
            && (C == null || B == null || C <= B)
            && (A == null || B == null || A <= B)
            && (C == null || D == null || C <= D));

อยู่ที่ไหน ..

  • A -> 1 เริ่มต้น
  • B -> 1 สิ้นสุด
  • C -> 2 เริ่มต้น
  • D -> 2 สิ้นสุด

หลักฐาน? ตรวจสอบการทดสอบนี้เค้ารหัสคอนโซล


ใช้งานได้ แต่ฉันต้องการทดสอบไม่ให้ซ้ำซ้อนเพียงสองสถานการณ์
John Albert

ขอบคุณที่อธิบายเรื่องนี้โดยใช้รูปภาพ คำตอบของคุณคือคำตอบที่สมบูรณ์แบบสำหรับคำถามนี้
Rakesh Verma

8

นี่คือทางออกของฉันในJavaซึ่งทำงานในช่วงเวลาไม่ จำกัด

private Boolean overlap (Timestamp startA, Timestamp endA,
                         Timestamp startB, Timestamp endB)
{
    return (endB == null || startA == null || !startA.after(endB))
        && (endA == null || startB == null || !endA.before(startB));
}

ฉันคิดว่าคุณหมายถึงการสิ้นสุดอย่างไร้ขีด จำกัด แทนที่จะเป็นช่วงเปิด
Henrik

@Henrik ทั้งสองข้อทำงานen.wikipedia.org/wiki/Interval_(mathematics)#Terminology
Khaled.K

!startA.after(endB)หมายถึง startA <= endB และ!endA.before(startB)หมายถึง startB <= endA สิ่งเหล่านี้เป็นเกณฑ์สำหรับช่วงปิดและไม่ใช่ช่วงเวลาเปิด
Henrik

@Henrik จริงและเงื่อนไขอื่น ๆ เช่นendB == nullและstartA == nullตรวจสอบช่วงเวลาที่เปิด
Khaled.K

1
endB == null, startA == null, endA == nullและstartB == nullมีเกณฑ์ทั้งหมดเพื่อตรวจสอบช่วงเวลามากมายและไม่ได้เป็นช่วงเวลาที่เปิดให้บริการ ตัวอย่างสำหรับความแตกต่างระหว่างช่วงเวลาที่ไม่ จำกัด และเปิด: (10, 20) และ (20, null) เป็นช่วงเวลาเปิดสองช่วงที่ไม่ทับซ้อนกัน อันสุดท้ายมีจุดจบไม่ จำกัด ฟังก์ชั่นของคุณจะกลับมาจริง แต่ช่วงเวลาไม่ทับซ้อนกันเพราะช่วงเวลาไม่รวม 20 (ตัวเลขที่ใช้แทนการประทับเวลาเพื่อความง่าย)
Henrik

7

โซลูชันที่โพสต์ที่นี่ไม่ทำงานสำหรับช่วงที่ทับซ้อนกันทั้งหมด ...

---------------------- | ------- ------- | ----------- -----------
    | ---- B1 ---- |
           | ---- B2 ---- |
               | ---- B3 ---- |
               | ---------- B4 ---------- |
               | ---------------- B5 ---------------- |
                      | ---- B6 ---- |
---------------------- | ------- ------- | ----------- -----------
                      | ------ B7 ------- |
                      | ---------- B8 ----------- |
                         | ---- B9 ---- |
                         | ---- B10 ----- |
                         | -------- B11 -------- |
                                      | ---- B12 ---- |
                                         | ---- B13 ---- |
---------------------- | ------- ------- | ----------- -----------

วิธีการทำงานของฉันคือ:

และ (
  ('start_date' ระหว่างวันที่เริ่มต้นและวันที่สิ้นสุด) - เหมาะสำหรับวันที่ด้านในและด้านนอกวันที่
  หรือ
  ('end_date' ระหว่างวันที่เริ่มต้นและวันที่สิ้นสุด) - เหมาะสำหรับวันที่ด้านนอกและวันที่เริ่มต้น
  หรือ
  (STARTDATE ระหว่าง 'start_date' และ 'end_date') - เพียงอันเดียวที่จำเป็นสำหรับช่วงนอกที่มีวันที่อยู่ภายใน
) 

5

นี่คือโซลูชันจาวาสคริปต์ของฉันกับ moment.js:

// Current row dates
var dateStart = moment("2014-08-01", "YYYY-MM-DD");
var dateEnd = moment("2014-08-30", "YYYY-MM-DD");

// Check with dates above
var rangeUsedStart = moment("2014-08-02", "YYYY-MM-DD");
var rangeUsedEnd = moment("2014-08-015", "YYYY-MM-DD");

// Range covers other ?
if((dateStart <= rangeUsedStart) && (rangeUsedEnd <= dateEnd)) {
    return false;
}
// Range intersects with other start ?
if((dateStart <= rangeUsedStart) && (rangeUsedStart <= dateEnd)) {
    return false;
}
// Range intersects with other end ?
if((dateStart <= rangeUsedEnd) && (rangeUsedEnd <= dateEnd)) {
    return false;
}

// All good
return true;


3

ใน Microsoft SQL SERVER - ฟังก์ชัน SQL

CREATE FUNCTION IsOverlapDates 
(
    @startDate1 as datetime,
    @endDate1 as datetime,
    @startDate2 as datetime,
    @endDate2 as datetime
)
RETURNS int
AS
BEGIN
DECLARE @Overlap as int
SET @Overlap = (SELECT CASE WHEN  (
        (@startDate1 BETWEEN @startDate2 AND @endDate2) -- caters for inner and end date outer
        OR
        (@endDate1 BETWEEN @startDate2 AND @endDate2) -- caters for inner and start date outer
        OR
        (@startDate2 BETWEEN @startDate1 AND @endDate1) -- only one needed for outer range where dates are inside.
        ) THEN 1 ELSE 0 END
    )
    RETURN @Overlap

END
GO

--Execution of the above code
DECLARE @startDate1 as datetime
DECLARE @endDate1 as datetime
DECLARE @startDate2 as datetime
DECLARE @endDate2 as datetime
DECLARE @Overlap as int
SET @startDate1 = '2014-06-01 01:00:00' 
SET @endDate1 =   '2014-06-01 02:00:00'
SET @startDate2 = '2014-06-01 01:00:00' 
SET @endDate2 =   '2014-06-01 01:30:00'

SET @Overlap = [dbo].[IsOverlapDates]  (@startDate1, @endDate1, @startDate2, @endDate2)

SELECT Overlap = @Overlap

3

ง่ายที่สุด

วิธีที่ง่ายที่สุดคือการใช้ไลบรารี่ที่ได้รับการออกแบบมาเป็นอย่างดีสำหรับงานวันที่

someInterval.overlaps( anotherInterval )

java.time และ ThreeTen-Extra

สิ่งที่ดีที่สุดในธุรกิจคือjava.timeกรอบการทำงานที่สร้างขึ้นใน Java 8 และใหม่กว่า เพิ่มไปยังโครงการThreeTen-Extraที่เสริม java.time ด้วยคลาสเพิ่มเติมโดยเฉพาะIntervalคลาสที่เราต้องการที่นี่

สำหรับlanguage-agnosticแท็กในคำถามนี้ซอร์สโค้ดสำหรับทั้งสองโครงการนั้นมีให้ใช้ในภาษาอื่น (คำนึงถึงสิทธิ์ใช้งาน)

Interval

org.threeten.extra.Intervalระดับเป็นประโยชน์ แต่ต้องใช้ช่วงเวลาวันที่เวลา ( java.time.Instantวัตถุ) มากกว่าค่าวันเท่านั้น ดังนั้นเราจึงดำเนินการโดยใช้ช่วงเวลาแรกของวันใน UTC เพื่อแสดงวันที่

Instant start = Instant.parse( "2016-01-01T00:00:00Z" );
Instant stop = Instant.parse( "2016-02-01T00:00:00Z" );

สร้างIntervalเพื่อเป็นตัวแทนช่วงเวลานั้น

Interval interval_A = Interval.of( start , stop );

นอกจากนี้เรายังสามารถกำหนดกับช่วงเวลาที่เริ่มต้นบวกIntervalDuration

Instant start_B = Instant.parse( "2016-01-03T00:00:00Z" );
Interval interval_B = Interval.of( start_B , Duration.of( 3 , ChronoUnit.DAYS ) );

การเปรียบเทียบเพื่อทดสอบการทับซ้อนนั้นง่าย

Boolean overlaps = interval_A.overlaps( interval_B );

คุณสามารถเปรียบเทียบการเปรียบเทียบIntervalกับรายการอื่นIntervalหรือInstant:

ทั้งหมดเหล่านี้ใช้Half-Openวิธีการที่จะกำหนดช่วงเวลาที่จุดเริ่มต้นคือการรวมและตอนจบเป็นพิเศษ


3

นี่คือส่วนขยายของคำตอบที่ยอดเยี่ยมโดย @ charles-bretana

อย่างไรก็ตามคำตอบไม่ได้สร้างความแตกต่างระหว่างช่วงเปิดปิดและครึ่งเปิด (หรือปิดครึ่ง)

กรณีที่ 1 : A, B เป็นช่วงปิด

A = [StartA, EndA]
B = [StartB, EndB]

                         [---- DateRange A ------]   (True if StartA > EndB)
[--- Date Range B -----]                           


[---- DateRange A -----]                             (True if EndA < StartB)
                         [--- Date Range B ----]

ซ้อนทับ iff: (StartA <= EndB) and (EndA >= StartB)

กรณีที่ 2 : A, B เป็นช่วงเวลาที่เปิด

A = (StartA, EndA)
B = (StartB, EndB)

                         (---- DateRange A ------)   (True if StartA >= EndB)
(--- Date Range B -----)                           

(---- DateRange A -----)                             (True if EndA <= StartB)
                         (--- Date Range B ----)

ซ้อนทับ iff: (StartA < EndB) and (EndA > StartB)

กรณีที่ 3 : A, B เปิดทันที

A = [StartA, EndA)
B = [StartB, EndB)

                         [---- DateRange A ------)   (True if StartA >= EndB) 
[--- Date Range B -----)                           

[---- DateRange A -----)                             (True if EndA <= StartB)
                         [--- Date Range B ----)

สภาพที่ทับซ้อนกัน: (StartA < EndB) and (EndA > StartB)

กรณีที่ 4 : A, B เปิดทิ้งไว้

A = (StartA, EndA]
B = (StartB, EndB]

                         (---- DateRange A ------]   (True if StartA >= EndB)
(--- Date Range B -----]                           

(---- DateRange A -----]                             (True if EndA <= StartB)
                         (--- Date Range B ----]

สภาพที่ทับซ้อนกัน: (StartA < EndB) and (EndA > StartB)

กรณีที่ 5 : เปิดขวา B ปิด

A = [StartA, EndA)
B = [StartB, EndB]

                         [---- DateRange A ------)    (True if StartA > EndB)
[--- Date Range B -----]                           


[---- DateRange A -----)                              (True if EndA <= StartB)  
                         [--- Date Range B ----]

สภาพที่ทับซ้อนกัน: (StartA <= EndB) and (EndA > StartB)

ฯลฯ ...

ในที่สุดสภาพทั่วไปสำหรับสองช่วงเวลาที่จะทับซ้อนกันคือ

(StartA <🞐 EndB) และ (EndA> 🞐 StartB)

โดยที่🞐เปลี่ยนความไม่เท่าเทียมอย่างเข้มงวดเป็นหนึ่งที่ไม่เข้มงวดเมื่อใดก็ตามที่มีการเปรียบเทียบระหว่างจุดรวมสองจุด


กรณีที่สองสามและสี่มีเงื่อนไขซ้อนกันเหมือนกันนี่เป็นเจตนาหรือไม่?
มารี

@Marie ฉันเพิ่งระบุบางกรณี (ไม่ใช่ทั้งหมด)
user2314737

สิ่งนี้ แต่อย่างละเอียดตามคำตอบของ Jonathan Lefflerจะเป็นสิ่งที่ฉันมีอยู่ในใจว่าเป็นคำตอบที่ยอมรับสำหรับคำถาม OPs
mbx

3

คำตอบสั้น ๆ ที่ใช้ momentjs :

function isOverlapping(startDate1, endDate1, startDate2, endDate2){ 
    return moment(startDate1).isSameOrBefore(endDate2) && 
    moment(startDate2).isSameOrBefore(endDate1);
}

คำตอบนั้นขึ้นอยู่กับคำตอบข้างต้น แต่มันสั้นลง


2

ในกรณีที่คุณใช้ช่วงวันที่ที่ยังไม่สิ้นสุด (ยังดำเนินต่อไป) เช่นไม่ได้ตั้งค่า endDate = '0000-00-00' คุณไม่สามารถใช้ BETWEEN ได้เนื่องจาก 0000-00-00 ไม่ใช่วันที่ที่ถูกต้อง!

ฉันใช้วิธีนี้:

(Startdate BETWEEN '".$startdate2."' AND '".$enddate2."')  //overlap: starts between start2/end2
OR (Startdate < '".$startdate2."' 
  AND (enddate = '0000-00-00' OR enddate >= '".$startdate2."')
) //overlap: starts before start2 and enddate not set 0000-00-00 (still on going) or if enddate is set but higher then startdate2

หาก startdate2 สูงกว่า enddate จะไม่มีการทับซ้อน!


2

คำตอบนั้นง่ายเกินไปสำหรับฉันดังนั้นฉันจึงได้สร้างคำสั่ง SQL แบบไดนามิกทั่วไปซึ่งจะตรวจสอบว่าบุคคลนั้นมีวันที่ทับซ้อนกันหรือไม่

SELECT DISTINCT T1.EmpID
FROM Table1 T1
INNER JOIN Table2 T2 ON T1.EmpID = T2.EmpID 
    AND T1.JobID <> T2.JobID
    AND (
        (T1.DateFrom >= T2.DateFrom AND T1.dateFrom <= T2.DateTo) 
        OR (T1.DateTo >= T2.DateFrom AND T1.DateTo <= T2.DateTo)
        OR (T1.DateFrom < T2.DateFrom AND T1.DateTo IS NULL)
    )
    AND NOT (T1.DateFrom = T2.DateFrom)

2

วิธีการแก้ปัญหาทางคณิตศาสตร์ที่ได้รับจาก @Bretana นั้นดี แต่ไม่สนใจสองรายละเอียดเฉพาะ

  1. แง่มุมของช่วงปิดหรือครึ่งเปิด
  2. ช่วงเวลาที่ว่างเปล่า

เกี่ยวกับสถานะปิดหรือสถานะเปิดของขอบเขตช่วงเวลาวิธีแก้ปัญหาของ @Bretana ใช้ได้สำหรับช่วงเวลาปิด

(StartA <= EndB) และ (EndA> = StartB)

สามารถเขียนใหม่สำหรับช่วงครึ่งเปิดเพื่อ:

(StartA <EndB) และ (EndA> StartB)

การแก้ไขนี้เป็นสิ่งจำเป็นเนื่องจากขอบเขตช่วงเวลาเปิดไม่ได้อยู่ในช่วงค่าของช่วงเวลาตามคำจำกัดความ


และเกี่ยวกับช่วงเวลาว่างเปล่าที่นี่ความสัมพันธ์ที่แสดงด้านบนไม่ถือ ช่วงเวลาว่างที่ไม่มีค่าที่ถูกต้องตามนิยามจะต้องถูกจัดการเป็นกรณีพิเศษ ฉันสาธิตโดยใช้ไลบรารีเวลา Java Time4Jผ่านตัวอย่างนี้:

MomentInterval a = MomentInterval.between(Instant.now(), Instant.now().plusSeconds(2));
MomentInterval b = a.collapse(); // make b an empty interval out of a

System.out.println(a); // [2017-04-10T05:28:11,909000000Z/2017-04-10T05:28:13,909000000Z)
System.out.println(b); // [2017-04-10T05:28:11,909000000Z/2017-04-10T05:28:11,909000000Z)

เครื่องหมายวงเล็บเหลี่ยมนำหน้า "[" หมายถึงจุดเริ่มต้นที่ปิดในขณะที่เครื่องหมายวงเล็บสุดท้าย ")" หมายถึงปลายเปิด

System.out.println(
      "startA < endB: " + a.getStartAsInstant().isBefore(b.getEndAsInstant())); // false
System.out.println(
      "endA > startB: " + a.getEndAsInstant().isAfter(b.getStartAsInstant())); // true

System.out.println("a overlaps b: " + a.intersects(b)); // a overlaps b: false

ดังที่แสดงไว้ข้างต้นช่วงเวลาที่ว่างเปล่าละเมิดเงื่อนไขการทับซ้อนด้านบน (โดยเฉพาะ startA <endB) ดังนั้น Time4J (และไลบรารี่อื่น ๆ เช่นกัน) ต้องจัดการเป็นกรณีขอบพิเศษเพื่อรับประกันว่าการทับซ้อนของช่วงเวลาใด ๆ ไม่ได้อยู่. แน่นอนช่วงเวลาวันที่ (ซึ่งถูกปิดโดยค่าเริ่มต้นใน Time4J แต่สามารถเปิดได้ครึ่งหนึ่งเช่นช่วงวันที่ว่างเปล่า) ได้รับการจัดการในลักษณะเดียวกัน


1

นี่เป็นวิธีการทั่วไปที่สามารถใช้ได้ในพื้นที่

    // Takes a list and returns all records that have overlapping time ranges.
    public static IEnumerable<T> GetOverlappedTimes<T>(IEnumerable<T> list, Func<T, bool> filter, Func<T,DateTime> start, Func<T, DateTime> end)
    {
        // Selects all records that match filter() on left side and returns all records on right side that overlap.
        var overlap = from t1 in list
                      where filter(t1)
                      from t2 in list
                      where !object.Equals(t1, t2) // Don't match the same record on right side.
                      let in1 = start(t1)
                      let out1 = end(t1)
                      let in2 = start(t2)
                      let out2 = end(t2)
                      where in1 <= out2 && out1 >= in2
                      let totover = GetMins(in1, out1, in2, out2)
                      select t2;

        return overlap;
    }

    public static void TestOverlap()
    {
        var tl1 = new TempTimeEntry() { ID = 1, Name = "Bill", In = "1/1/08 1:00pm".ToDate(), Out = "1/1/08 4:00pm".ToDate() };
        var tl2 = new TempTimeEntry() { ID = 2, Name = "John", In = "1/1/08 5:00pm".ToDate(), Out = "1/1/08 6:00pm".ToDate() };
        var tl3 = new TempTimeEntry() { ID = 3, Name = "Lisa", In = "1/1/08 7:00pm".ToDate(), Out = "1/1/08 9:00pm".ToDate() };
        var tl4 = new TempTimeEntry() { ID = 4, Name = "Joe", In = "1/1/08 3:00pm".ToDate(), Out = "1/1/08 8:00pm".ToDate() };
        var tl5 = new TempTimeEntry() { ID = 1, Name = "Bill", In = "1/1/08 8:01pm".ToDate(), Out = "1/1/08 8:00pm".ToDate() };
        var list = new List<TempTimeEntry>() { tl1, tl2, tl3, tl4, tl5 };
        var overlap = GetOverlappedTimes(list, (TempTimeEntry t1)=>t1.ID==1, (TempTimeEntry tIn) => tIn.In, (TempTimeEntry tOut) => tOut.Out);

        Console.WriteLine("\nRecords overlap:");
        foreach (var tl in overlap)
            Console.WriteLine("Name:{0} T1In:{1} T1Out:{2}", tl.Name, tl.In, tl.Out);
        Console.WriteLine("Done");

        /*  Output:
            Records overlap:
            Name:Joe T1In:1/1/2008 3:00:00 PM T1Out:1/1/2008 8:00:00 PM
            Name:Lisa T1In:1/1/2008 7:00:00 PM T1Out:1/1/2008 9:00:00 PM
            Done
         */
    }

1
public static class NumberExtensionMethods
    {
        public static Boolean IsBetween(this Int64 value, Int64 Min, Int64 Max)
        {
            if (value >= Min && value <= Max) return true;
            else return false;
        }

        public static Boolean IsBetween(this DateTime value, DateTime Min, DateTime Max)
        {
            Int64 numricValue = value.Ticks;
            Int64 numericStartDate = Min.Ticks;
            Int64 numericEndDate = Max.Ticks;

            if (numricValue.IsBetween(numericStartDate, numericEndDate) )
            {
                return true;
            }

            return false;
        }
    }

public static Boolean IsOverlap(DateTime startDate1, DateTime endDate1, DateTime startDate2, DateTime endDate2)
        {
            Int64 numericStartDate1 = startDate1.Ticks;
            Int64 numericEndDate1 = endDate1.Ticks;
            Int64 numericStartDate2 = startDate2.Ticks;
            Int64 numericEndDate2 = endDate2.Ticks;

            if (numericStartDate2.IsBetween(numericStartDate1, numericEndDate1) ||
                numericEndDate2.IsBetween(numericStartDate1, numericEndDate1) ||
                numericStartDate1.IsBetween(numericStartDate2, numericEndDate2) ||
                numericEndDate1.IsBetween(numericStartDate2, numericEndDate2))
            {
                return true;
            }

            return false;
        } 


if (IsOverlap(startdate1, enddate1, startdate2, enddate2))
            {
                Console.WriteLine("IsOverlap");
            }

3
ต้องการเพิ่มคำอธิบายไหม?
Phantômaxx

1

ใช้ Java util.Date นี่คือสิ่งที่ฉันทำ

    public static boolean checkTimeOverlaps(Date startDate1, Date endDate1, Date startDate2, Date endDate2)
    {
        if (startDate1 == null || endDate1 == null || startDate2 == null || endDate2 == null)
           return false;

        if ((startDate1.getTime() <= endDate2.getTime()) && (startDate2.getTime() <= endDate1.getTime()))
           return true;

        return false;
    }

1

วิธีที่ง่ายที่สุดที่จะทำในความคิดของฉันคือการเปรียบเทียบว่า EndDate1 ใดอยู่ก่อนหน้า StartDate2 และ EndDate2 ก่อนหน้า StartDate1

แน่นอนว่าถ้าคุณกำลังพิจารณาช่วงเวลาที่ StartDate อยู่ก่อน EndDate


1

ฉันมีสถานการณ์ที่เรามีวันที่แทนที่จะเป็นชุดข้อมูลและวันที่สามารถทับซ้อนกันเฉพาะเมื่อเริ่มต้น / สิ้นสุด ตัวอย่างด้านล่าง:

ป้อนคำอธิบายรูปภาพที่นี่

(สีเขียวคือช่วงเวลาปัจจุบันบล็อกสีน้ำเงินเป็นช่วงเวลาที่ถูกต้องส่วนสีแดงคือช่วงเวลาที่ทับซ้อนกัน)

ฉันปรับคำตอบของ Ian Nelson กับวิธีแก้ไขปัญหาต่อไปนี้:

   (startB <= startA && endB > startA)
|| (startB >= startA && startB < endA)

กรณีนี้ตรงกับกรณีที่ทับซ้อนกันทั้งหมด แต่ไม่สนใจกรณีที่ทับซ้อนกันที่อนุญาต


0

แยกปัญหาออกเป็นกรณีแล้วจัดการกับแต่ละกรณี

สถานการณ์ 'ช่วงวันที่สองจุดตัด' ถูกครอบคลุมโดยสองกรณี - ช่วงวันแรกเริ่มต้นภายในช่วงที่สองหรือช่วงวันที่ที่สองเริ่มต้นภายในช่วงแรก


0

คุณสามารถลองสิ่งนี้:

//custom date for example
$d1 = new DateTime("2012-07-08");
$d2 = new DateTime("2012-07-11");
$d3 = new DateTime("2012-07-08");
$d4 = new DateTime("2012-07-15");

//create a date period object
$interval = new DateInterval('P1D');
$daterange = iterator_to_array(new DatePeriod($d1, $interval, $d2));
$daterange1 = iterator_to_array(new DatePeriod($d3, $interval, $d4));
array_map(function($v) use ($daterange1) { if(in_array($v, $daterange1)) print "Bingo!";}, $daterange);

0

นี่คือโซลูชันของฉันมันจะคืนค่าจริงเมื่อค่าไม่ทับซ้อนกัน:

X เริ่มต้น 1 ปีสิ้นสุด 1

A เริ่มต้น 2 B สิ้นสุด 2

TEST1: (X <= A || X >= B)
        &&
TEST2: (Y >= B || Y <= A) 
        && 
TEST3: (X >= B || Y <= A)


X-------------Y
    A-----B

TEST1:  TRUE
TEST2:  TRUE
TEST3:  FALSE
RESULT: FALSE

---------------------------------------

X---Y
      A---B

TEST1:  TRUE
TEST2:  TRUE
TEST3:  TRUE
RESULT: TRUE

---------------------------------------

      X---Y
A---B

TEST1:  TRUE
TEST2:  TRUE
TEST3:  TRUE
RESULT: TRUE

---------------------------------------

     X----Y
A---------------B

TEST1:  FALSE
TEST2:  FALSE
TEST3:  FALSE
RESULT: FALSE

0

สำหรับทับทิมฉันก็พบสิ่งนี้ด้วย:

class Interval < ActiveRecord::Base

  validates_presence_of :start_date, :end_date

  # Check if a given interval overlaps this interval    
  def overlaps?(other)
    (start_date - other.end_date) * (other.start_date - end_date) >= 0
  end

  # Return a scope for all interval overlapping the given interval, including the given interval itself
  named_scope :overlapping, lambda { |interval| {
    :conditions => ["id <> ? AND (DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", interval.id, interval.end_date, interval.start_date]
  }}

end

พบที่นี่พร้อมคำอธิบายที่ดี -> http://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-ruby-or-rails


0

ข้อความค้นหาด้านล่างให้รหัสฉันซึ่งช่วงวันที่ที่ให้ไว้ (วันที่เริ่มต้นและวันที่สิ้นสุดทับซ้อนกับวันใด ๆ (วันที่เริ่มต้นและวันที่สิ้นสุด) ใน table_name ของฉัน

select id from table_name where (START_DT_TM >= 'END_DATE_TIME'  OR   
(END_DT_TM BETWEEN 'START_DATE_TIME' AND 'END_DATE_TIME'))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.