Diberi dua rentang tanggal, apa cara paling sederhana atau paling efisien untuk menentukan apakah dua rentang tanggal tumpang tindih?
Sebagai contoh, misalkan kita memiliki rentang yang ditandai oleh variabel DateTime StartDate1
ke EndDate1
dan StartDate2
ke EndDate2
.
datetime
math
language-agnostic
Ian Nelson
sumber
sumber
Jawaban:
(StartA <= EndB) dan (EndA> = StartB)
Bukti:
Biarkan KondisiA Berarti DateRange A Lengkap Setelah DateRange B
_ |---- DateRange A ------| |---Date Range B -----| _
(Benar jika
StartA > EndB
)Biarkan ConditionB Berarti DateRange A Sepenuhnya Sebelum DateRange B
|---- DateRange A -----| _ _ |---Date Range B ----|
(Benar jika
EndA < StartB
)Kemudian Tumpang tindih ada jika Baik A maupun B tidak benar -
(Jika satu rentang tidak sepenuhnya setelah yang lain,
atau sepenuhnya sebelum yang lain, maka mereka harus tumpang tindih.)
Sekarang salah satu hukum De Morgan mengatakan bahwa:
Not (A Or B)
<=>Not A And Not B
Yang diterjemahkan menjadi:
(StartA <= EndB) and (EndA >= StartB)
CATATAN: Ini termasuk kondisi di mana tepinya tumpang tindih. Jika Anda ingin mengecualikan itu,
ubah
>=
operator menjadi>
, dan<=
ke<
CATATAN 2. Berkat @Baodad, lihat blog ini , tumpang tindih sebenarnya paling:
{
endA-startA
,endA - startB
,endB-startA
,endB - startB
}(StartA <= EndB) and (EndA >= StartB)
(StartA <= EndB) and (StartB <= EndA)
CATATAN 3. Berkat @tomosius, versi yang lebih singkat berbunyi:
DateRangesOverlap = max(start1, start2) < min(end1, end2)
Ini sebenarnya adalah jalan pintas sintaksis untuk implementasi yang lebih lama, yang mencakup pemeriksaan tambahan untuk memverifikasi bahwa tanggal mulai adalah pada atau sebelum tanggal akhir. Mendapat ini dari atas:
Jika tanggal mulai dan berakhir dapat rusak, yaitu, jika mungkin itu
startA > endA
ataustartB > endB
, maka Anda juga harus memeriksa apakah mereka dalam urutan, sehingga Anda harus menambahkan dua aturan validitas tambahan:(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB)
atau:(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB)
atau,(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB))
atau:(Max(StartA, StartB) <= Min(EndA, EndB)
Tetapi untuk mengimplementasikan
Min()
danMax()
, Anda harus kode, (menggunakan C ternary untuk keseness) ,:(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)
sumber
Start
danEnd
artinya. Jika Anda memiliki dua variabel bernama Atas dan Bawah, atau Timur dan Barat, atau HighValue dan LoValue, dapat diasumsikan atau tersirat bahwa sesuatu atau seseorang, di suatu tempat harus memastikan bahwa salah satu pasangan nilai tidak disimpan dalam variabel yang berlawanan. -Hanya satu dari dua pasangan karena, yah, itu juga akan berfungsi jika kedua pasangan nilai diaktifkan.start
danend
(dengan semantik yang "null start" = "Dari awal waktu" dan "null end" = "Sampai akhir waktu") seperti itu:(startA === null || endB === null || startA <= endB) && (endA === null || startB === null || endA >= startB)
DateRangesOverlap = max(start1, start2) < min(end1, end2)
Saya percaya bahwa cukup untuk mengatakan bahwa kedua rentang tumpang tindih jika:
sumber
(StartDate1 <= EndDate2) and (EndDate1 >= StartDate2)
notasi lebih mudah dimengerti, Range1 selalu di sebelah kiri dalam tes.<=
ke<
jika mulai inklusif dan akhir eksklusif.Artikel ini Perpustakaan Periode Waktu untuk .NET menjelaskan hubungan dua periode waktu dengan enumerasi PeriodRelation :
sumber
Untuk alasan tentang hubungan temporal (atau hubungan interval lainnya, lihat itu), pertimbangkan Aljabar Interval Allen . Ini menggambarkan 13 kemungkinan hubungan yang dapat dimiliki oleh dua interval satu sama lain. Anda dapat menemukan referensi lain - "Interval Allen" tampaknya merupakan istilah pencarian operatif. Anda juga dapat menemukan informasi tentang operasi ini di Mengembangkan Aplikasi Berorientasi Waktu Snodgrass dalam SQL (PDF tersedia online di URL), dan dalam Date, Darwen dan Lorentzos Data Temporal dan Model Relasional (2002) atau Teori Waktu dan Relasional: Database Temporal di Model Relasional dan SQL (2014; efektif TD&RM edisi kedua).
Jawaban singkat (ish) adalah: diberi dua interval tanggal
A
danB
dengan komponen.start
dan.end
kendala.start <= .end
, kemudian dua interval tumpang tindih jika:Anda dapat mengatur penggunaan
>=
vs>
dan<=
vs<
untuk memenuhi persyaratan Anda untuk tingkat tumpang tindih.Komentar dari ErikE:
Saya pikir Anda tidak dapat menghitung dua entri 'sebelum: sebelum' dan 'setelah: setelah'. Saya bisa melihat 7 entri jika Anda menyamakan beberapa hubungan dengan inversnya (lihat diagram dalam URL Wikipedia yang direferensikan; ia memiliki 7 entri, 6 di antaranya memiliki invers berbeda, dengan yang sama dengan tidak memiliki invers berbeda). Dan apakah ketiganya masuk akal tergantung pada kebutuhan Anda.
sumber
Jika tumpang tindih itu sendiri juga harus dihitung, Anda dapat menggunakan rumus berikut:
sumber
Semua solusi yang memeriksa banyak kondisi berdasarkan di mana rentang tersebut terkait satu sama lain dapat sangat disederhanakan dengan hanya memastikan bahwa rentang tertentu dimulai lebih awal! Anda memastikan bahwa rentang pertama dimulai lebih awal (atau pada saat yang sama) dengan menukar kisaran jika perlu di depan.
Kemudian, Anda dapat mendeteksi tumpang tindih jika mulai rentang lainnya kurang dari atau sama dengan akhir rentang pertama (jika rentang inklusif, mengandung waktu mulai dan akhir) atau kurang dari (jika rentang termasuk awal dan eksklusif akhir) .
Dengan asumsi inklusif di kedua ujungnya, hanya ada empat kemungkinan yang salah satunya adalah tumpang tindih:
Titik akhir rentang 2 tidak masuk ke dalamnya. Jadi, dalam pseudo-code:
Ini bisa disederhanakan menjadi:
Jika rentang inklusif di awal dan eksklusif di akhir, Anda hanya perlu mengganti
>
dengan>=
dalamif
pernyataan kedua (untuk segmen kode pertama: di segmen kode kedua, Anda akan menggunakan<
daripada<=
):Anda sangat membatasi jumlah cek yang harus Anda lakukan karena Anda menghapus setengah dari ruang masalah lebih awal dengan memastikan rentang 1 tidak pernah dimulai setelah rentang 2.
sumber
Berikut ini adalah solusi lain menggunakan JavaScript. Spesialisasi dari solusi saya:
Tes didasarkan pada bilangan bulat tetapi karena objek tanggal dalam JavaScript sebanding, Anda bisa melempar dua objek tanggal juga. Atau Anda bisa melempar cap waktu milidetik.
Kode:
Tes:
Hasil saat dijalankan dengan karma & melati & PhantomJS:
sumber
Saya akan lakukan
Di mana
IsBetween
ada sesuatu sepertisumber
Berikut adalah kode yang melakukan keajaiban:
Dimana..
Bukti? Lihat inti kode konsol pengujian ini .
sumber
Inilah solusi saya di Jawa , yang bekerja pada interval tidak terbatas juga
sumber
!startA.after(endB)
berarti startA <= endB dan!endA.before(startB)
berarti startB <= endA. Ini adalah kriteria untuk interval tertutup dan bukan interval terbuka.endB == null
danstartA == null
periksa interval terbuka.endB == null
,startA == null
,endA == null
DanstartB == null
semua kriteria untuk memeriksa selang waktu tak terbatas dan tidak interval terbuka. Contoh untuk perbedaan antara interval tidak terikat dan terbuka: (10, 20) dan (20, null) adalah dua interval terbuka yang tidak tumpang tindih. Yang terakhir memang memiliki akhir tanpa batas. Fungsi Anda akan kembali benar, tetapi interval tidak tumpang tindih, karena interval tidak termasuk 20. (nomor yang digunakan bukan cap waktu untuk kesederhanaan)Solusi yang diposting di sini tidak berfungsi untuk semua rentang yang tumpang tindih ...
solusi kerja saya adalah:
sumber
Ini adalah solusi javascript saya dengan moment.js:
sumber
Cara mudah untuk mengingat solusinya adalah
min(ends)>max(starts)
sumber
Di Microsoft SQL SERVER - Fungsi SQL
sumber
Cara paling sederhana adalah dengan menggunakan perpustakaan khusus yang dirancang dengan baik untuk pekerjaan waktu.
java.time & ThreeTen-Extra
Yang terbaik dalam bisnis ini adalah
java.time
kerangka kerja yang dibangun ke Java 8 dan yang lebih baru. Tambahkan ke proyek ThreeTen-Extra yang melengkapi java.time dengan kelas tambahan, khususnyaInterval
kelas yang kita butuhkan di sini.Adapun
language-agnostic
tag pada Pertanyaan ini, kode sumber untuk kedua proyek tersedia untuk digunakan dalam bahasa lain (perhatikan lisensinya).Interval
The
org.threeten.extra.Interval
kelas berguna, tetapi membutuhkan tanggal-waktu saat (java.time.Instant
benda) bukan nilai tanggal-satunya. Jadi kami melanjutkan dengan menggunakan momen pertama hari itu di UTC untuk mewakili tanggal.Buat
Interval
untuk mewakili rentang waktu itu.Kita juga dapat mendefinisikan sebuah
Interval
dengan momen awal plus aDuration
.Membandingkan untuk menguji tumpang tindih itu mudah.
Anda dapat membandingkan sebuah
Interval
terhadap yang lainInterval
atauInstant
:abuts
contains
encloses
equals
isAfter
isBefore
overlaps
Semua ini menggunakan
Half-Open
pendekatan untuk menentukan rentang waktu di mana awal termasuk dan akhir adalah eksklusif .sumber
Ini adalah ekstensi untuk jawaban yang sangat baik oleh @ charles-bretana
Namun jawabannya tidak membuat perbedaan antara interval terbuka, tertutup, dan setengah terbuka (atau setengah tertutup).
Kasus 1 : A, B adalah interval tertutup
Jika tumpang tindih:
(StartA <= EndB) and (EndA >= StartB)
Kasus 2 : A, B adalah interval terbuka
Jika tumpang tindih:
(StartA < EndB) and (EndA > StartB)
Kasus 3 : A, B langsung terbuka
Kondisi tumpang tindih:
(StartA < EndB) and (EndA > StartB)
Kasus 4 : A, B dibiarkan terbuka
Kondisi tumpang tindih:
(StartA < EndB) and (EndA > StartB)
Kasus 5 : Hak terbuka, B ditutup
Kondisi tumpang tindih:
(StartA <= EndB) and (EndA > StartB)
dll ...
Akhirnya, kondisi umum untuk dua interval untuk tumpang tindih adalah
(StartA <🞐 EndB) dan (EndA> 🞐 StartB)
di mana 🞐 mengubah ketimpangan yang ketat menjadi yang tidak ketat setiap kali perbandingan dilakukan antara dua titik akhir yang disertakan.
sumber
Jawaban singkat menggunakan momentjs :
jawabannya didasarkan pada jawaban di atas, tetapi diperpendek.
sumber
Jika Anda menggunakan rentang tanggal yang belum berakhir (masih berjalan) misalnya tidak mengatur endDate = '0000-00-00' Anda tidak dapat menggunakan ANTARA karena 0000-00-00 bukan tanggal yang valid!
Saya menggunakan solusi ini:
Jika startdate2 lebih tinggi maka enddate tidak ada tumpang tindih!
sumber
Jawabannya terlalu sederhana bagi saya sehingga saya telah membuat pernyataan SQL dinamis yang lebih umum yang memeriksa untuk melihat apakah seseorang memiliki tanggal yang tumpang tindih.
sumber
Solusi matematis yang diberikan oleh @Bretana baik tetapi mengabaikan dua detail spesifik:
Tentang keadaan batas interval tertutup atau terbuka, solusi @Bretana berlaku untuk interval tertutup
dapat ditulis ulang untuk interval setengah terbuka ke:
Koreksi ini diperlukan karena batas interval terbuka tidak termasuk dalam rentang nilai interval menurut definisi.
Dan tentang interval kosong , well, di sini hubungan yang ditunjukkan di atas tidak berlaku. Interval kosong yang tidak mengandung nilai yang valid menurut definisi harus ditangani sebagai kasus khusus. Saya mendemonstrasikannya dengan perpustakaan waktu Java saya Time4J melalui contoh ini:
Braket persegi terkemuka "[" menunjukkan awal yang tertutup sementara braket terakhir ")" menunjukkan ujung terbuka.
Seperti yang ditunjukkan di atas, interval kosong melanggar kondisi tumpang tindih di atas (terutama startA <endB), sehingga Time4J (dan perpustakaan lain juga) harus menanganinya sebagai kasus tepi khusus untuk menjamin bahwa tumpang tindih dari setiap interval sewenang-wenang dengan interval kosong tidak ada. Tentu saja, interval tanggal (yang ditutup secara default di Time4J tetapi juga bisa setengah terbuka, seperti interval tanggal kosong) ditangani dengan cara yang sama.
sumber
Berikut ini adalah metode umum yang dapat berguna secara lokal.
sumber
sumber
Menggunakan Java util.Date, inilah yang saya lakukan.
sumber
Cara termudah untuk melakukannya menurut saya adalah membandingkan apakah EndDate1 baik sebelum StartDate2 dan EndDate2 sebelum StartDate1.
Itu tentu saja jika Anda mempertimbangkan interval di mana StartDate selalu sebelum EndDate.
sumber
Saya memiliki situasi di mana kami memiliki tanggal alih-alih data, dan tanggal bisa tumpang tindih hanya pada awal / akhir. Contoh di bawah ini:
(Hijau adalah interval saat ini, blok biru adalah interval yang valid, yang merah adalah interval yang tumpang tindih).
Saya mengadaptasi jawaban Ian Nelson untuk solusi berikut:
Ini cocok dengan semua kasus yang tumpang tindih tetapi mengabaikan yang tumpang tindih yang diizinkan.
sumber
Bagi masalah menjadi beberapa kasus kemudian tangani setiap kasus .
Situasi 'dua rentang tanggal berpotongan' dicakup oleh dua kasus - rentang tanggal pertama dimulai dalam yang kedua, atau rentang tanggal kedua dimulai dalam yang pertama.
sumber
Anda dapat mencoba ini:
sumber
Ini adalah solusi saya, ini mengembalikan true ketika nilai tidak tumpang tindih:
X MULAI 1 Y AKHIR 1
A MULAI 2 B AKHIR 2
sumber
Untuk ruby saya juga menemukan ini:
Ditemukan di sini dengan penjelasan yang bagus -> http://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-ruby-or-rails
sumber
Kueri di bawah ini memberi saya id yang rentang tanggal yang disediakan (tanggal mulai dan berakhir tumpang tindih dengan salah satu tanggal (tanggal mulai dan berakhir) di nama_kabel saya
sumber