Étant donné deux plages de dates, quelle est la manière la plus simple ou la plus efficace de déterminer si les deux plages de dates se chevauchent?
Par exemple, supposons que nous ayons des plages désignées par des variables DateTime StartDate1
vers EndDate1
et StartDate2
vers EndDate2
.
datetime
math
language-agnostic
Ian Nelson
la source
la source
Réponses:
(StartA <= EndB) et (EndA> = StartB)
Preuve:
que ConditionA signifie que DateRange A complètement après DateRange B
_ |---- DateRange A ------| |---Date Range B -----| _
(True if
StartA > EndB
)Soit ConditionB signifie que DateRange A est complètement avant DateRange B
|---- DateRange A -----| _ _ |---Date Range B ----|
(Vrai si
EndA < StartB
)Il y a alors chevauchement si ni A ni B n'est vrai -
(si une plage n'est ni complètement après l'autre,
ni complètement avant l'autre, alors elles doivent se chevaucher.)
Maintenant, l'une des lois de De Morgan dit que:
Not (A Or B)
<=>Not A And Not B
Ce qui se traduit par:
(StartA <= EndB) and (EndA >= StartB)
REMARQUE: cela inclut les conditions où les bords se chevauchent exactement. Si vous souhaitez exclure,
changer les
>=
opérateurs à>
, et<=
à<
NOTE 2. Merci à @Baodad, voir ce blog , le chevauchement réel est moins:
{
endA-startA
,endA - startB
,endB-startA
,endB - startB
}(StartA <= EndB) and (EndA >= StartB)
(StartA <= EndB) and (StartB <= EndA)
NOTE 3. Grâce à @tomosius, une version plus courte se lit comme suit:
DateRangesOverlap = max(start1, start2) < min(end1, end2)
Il s'agit en fait d'un raccourci syntaxique pour une implémentation plus longue, qui comprend des vérifications supplémentaires pour vérifier que les dates de début sont à la date de fin ou avant. Dérivant cela d'en haut:
Si les dates de début et de fin peuvent être hors service, c'est-à-dire s'il est possible que
startA > endA
oustartB > endB
, alors vous devez également vérifier qu'elles sont en ordre, ce qui signifie que vous devez ajouter deux règles de validité supplémentaires:(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB)
ou:(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB)
ou,(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB))
ou:(Max(StartA, StartB) <= Min(EndA, EndB)
Mais pour implémenter
Min()
etMax()
, vous devez coder, (en utilisant C ternaire pour la concision),:(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)
la source
Start
queEnd
signifient les mots . Si vous avez deux variables nommées Top et Bottom, ou East and West, ou HighValue et LoValue, il peut être supposé ou sous-entendu que quelque chose ou quelqu'un, quelque part devrait s'assurer qu'aucune des paires de valeurs n'est stockée dans les variables opposées. -Une seule des deux paires car, eh bien, cela fonctionnera également si les deux paires de valeurs sont commutées.start
etend
(avec la sémantique "null start" = "depuis le début du temps" et "null end" = "jusqu'à la fin du temps") comme ça:(startA === null || endB === null || startA <= endB) && (endA === null || startB === null || endA >= startB)
DateRangesOverlap = max(start1, start2) < min(end1, end2)
Je pense qu'il suffit de dire que les deux gammes se chevauchent si:
la source
(StartDate1 <= EndDate2) and (EndDate1 >= StartDate2)
notation plus facile à comprendre, Range1 est toujours à gauche dans les tests.<=
de<
si le démarrage est inclusif et à la fin est exclusive.Cet article Time Period Library pour .NET décrit la relation de deux périodes par l'énumération PeriodRelation :
la source
Pour raisonner sur les relations temporelles (ou toute autre relation d'intervalle, venez-y), considérez l'algèbre d'intervalle d'Allen . Il décrit les 13 relations possibles que deux intervalles peuvent avoir l'un par rapport à l'autre. Vous pouvez trouver d'autres références - "Allen Interval" semble être un terme de recherche opérationnel. Vous pouvez également trouver des informations sur ces opérations dans Snodgrass's Developing Time-Oriented Applications in SQL (PDF disponible en ligne sur URL), et dans Date, Darwen et Lorentzos Temporal Data and the Relational Model (2002) ou Time and Relational Theory: Temporal Databases in le modèle relationnel et SQL (2014; en fait la deuxième édition de TD&RM).
La réponse courte (ish) est: étant donné deux intervalles de date
A
etB
avec les composants.start
et.end
et la contrainte.start <= .end
, alors deux intervalles se chevauchent si:Vous pouvez régler l'utilisation de
>=
vs>
et<=
vs<
pour répondre à vos exigences de degré de chevauchement.Commentaires d'ErikE:
Je pense que vous ne pouvez pas compter les deux entrées «avant: avant» et «après: après». Je pourrais voir 7 entrées si vous assimilez certaines relations à leurs inverses (voir le diagramme dans l'URL Wikipédia référencée; il a 7 entrées, dont 6 ont un inverse différent, avec des égaux n'ayant pas d'inverse distinct). Et si trois est raisonnable dépend de vos besoins.
la source
Si le chevauchement lui-même doit également être calculé, vous pouvez utiliser la formule suivante:
la source
Toutes les solutions qui vérifient une multitude de conditions en fonction de la position des plages les unes par rapport aux autres peuvent être grandement simplifiées en s'assurant simplement qu'une plage spécifique démarre plus tôt! Vous vous assurez que la première plage démarre plus tôt (ou en même temps) en échangeant les plages si nécessaire à l'avance.
Ensuite, vous pouvez détecter un chevauchement si l'autre début de plage est inférieur ou égal à la première fin de plage (si les plages sont inclusives, contenant à la fois les heures de début et de fin) ou inférieur à (si les plages incluent le début et excluent la fin) .
En supposant inclusif aux deux extrémités, il n'y a que quatre possibilités dont l'une est un non-chevauchement:
Le point final de la plage 2 n'y entre pas. Donc, en pseudo-code:
Cela pourrait être encore plus simplifié en:
Si les plages sont inclusives au début et exclusives à la fin, il vous suffit de remplacer
>
par>=
dans la deuxièmeif
instruction (pour le premier segment de code: dans le deuxième segment de code, vous utiliseriez<
plutôt que<=
):Vous limitez considérablement le nombre de vérifications que vous devez effectuer car vous supprimez la moitié de l'espace problématique tôt en vous assurant que la plage 1 ne démarre jamais après la plage 2.
la source
Voici encore une autre solution utilisant JavaScript. Spécialités de ma solution:
Les tests sont basés sur des nombres entiers, mais comme les objets de date en JavaScript sont comparables, vous pouvez également ajouter deux objets de date. Ou vous pouvez ajouter l'horodatage en millisecondes.
Code:
Tests:
Résultat lors de l'exécution avec karma & jasmine & PhantomJS:
la source
je ferais
Où
IsBetween
est quelque chose commela source
Voici le code qui fait la magie:
Où..
Preuve? Découvrez cet aperçu du code de la console de test .
la source
Voici ma solution en Java , qui fonctionne également à intervalles illimités
la source
!startA.after(endB)
signifie startA <= endB et!endA.before(startB)
signifie startB <= endA. Ce sont les critères d'un intervalle fermé et non d'un intervalle ouvert.endB == null
etstartA == null
recherchez un intervalle ouvert.endB == null
,startA == null
,endA == null
EtstartB == null
sont tous les critères pour vérifier un intervalle sans entrave et non un intervalle ouvert. Exemple pour les différences entre les intervalles non bornés et ouverts: (10, 20) et (20, null) sont deux intervalles ouverts qui ne se chevauchent pas. Le dernier a une fin illimitée. Votre fonction renverra true, mais les intervalles ne se chevauchent pas, car les intervalles n'incluent pas 20. (nombres utilisés au lieu d'horodatages pour plus de simplicité)La solution publiée ici n'a pas fonctionné pour toutes les plages qui se chevauchent ...
ma solution de travail était:
la source
C'était ma solution javascript avec moment.js:
la source
Un moyen facile de se souvenir de la solution serait
min(ends)>max(starts)
la source
Dans Microsoft SQL SERVER - Fonction SQL
la source
Le moyen le plus simple consiste à utiliser une bibliothèque dédiée bien conçue pour le travail date-heure.
java.time & ThreeTen-Extra
Le meilleur de l'entreprise est le
java.time
cadre intégré à Java 8 et versions ultérieures. Ajoutez à cela le projet ThreeTen-Extra qui complète java.time avec des classes supplémentaires, en particulier laInterval
classe dont nous avons besoin ici.Quant à la
language-agnostic
balise sur cette question, le code source pour les deux projets est disponible pour une utilisation dans d'autres langues (attention à leurs licences).Interval
La
org.threeten.extra.Interval
classe est pratique, mais nécessite des moments date-heure (java.time.Instant
objets) plutôt que des valeurs de date uniquement. Nous procédons donc en utilisant le premier moment de la journée en UTC pour représenter la date.Créez un
Interval
pour représenter cette période de temps.Nous pouvons également définir un
Interval
avec un moment de départ plus unDuration
.Il est facile de comparer le test des chevauchements.
Vous pouvez comparer un
Interval
contre un autreInterval
ouInstant
:abuts
contains
encloses
equals
isAfter
isBefore
overlaps
Tous ces éléments utilisent l'
Half-Open
approche pour définir une période de temps où le début est inclusif et la fin est exclusive .la source
Il s'agit d'une extension de l' excellente réponse de @ charles-bretana.
Cependant, la réponse ne fait pas de distinction entre les intervalles ouverts, fermés et semi-ouverts (ou semi-fermés).
Cas 1 : A, B sont des intervalles fermés
Chevauchement ssi:
(StartA <= EndB) and (EndA >= StartB)
Cas 2 : A, B sont des intervalles ouverts
Chevauchement ssi:
(StartA < EndB) and (EndA > StartB)
Cas 3 : A, B ouvert à droite
Condition de chevauchement:
(StartA < EndB) and (EndA > StartB)
Cas 4 : A, B laissé ouvert
Condition de chevauchement:
(StartA < EndB) and (EndA > StartB)
Cas 5 : A ouvert à droite, B fermé
Condition de chevauchement:
(StartA <= EndB) and (EndA > StartB)
etc...
Enfin, la condition générale de chevauchement de deux intervalles est
(StartA <🞐 EndB) et (EndA> 🞐 StartB)
où 🞐 transforme une inégalité stricte en une inégalité non stricte chaque fois que la comparaison est faite entre deux points d'extrémité inclus.
la source
Réponse courte en utilisant momentjs :
la réponse est basée sur les réponses ci-dessus, mais elle est raccourcie.
la source
Si vous utilisez une plage de dates qui n'est pas encore terminée (toujours en cours), par exemple, ne définissez pas endDate = '0000-00-00', vous ne pouvez pas utiliser BETWEEN car 0000-00-00 n'est pas une date valide!
J'ai utilisé cette solution:
Si startdate2 est supérieur à enddate, il n'y a pas de chevauchement!
la source
La réponse est trop simple pour moi, j'ai donc créé une instruction SQL dynamique plus générique qui vérifie si une personne a des dates qui se chevauchent.
la source
La solution mathématique donnée par @Bretana est bonne mais néglige deux détails spécifiques:
À propos de l'état fermé ou ouvert des limites d'intervalle, la solution de @Bretana valable pour les intervalles fermés
peut être réécrit pour des intervalles semi-ouverts pour:
Cette correction est nécessaire car une limite d'intervalle ouverte n'appartient pas à la plage de valeurs d'un intervalle par définition.
Et à propos des intervalles vides , eh bien, ici, la relation ci-dessus ne tient pas. Les intervalles vides qui ne contiennent par définition aucune valeur valide doivent être traités comme un cas spécial. Je le démontre par ma bibliothèque de temps Java Time4J via cet exemple:
Le crochet carré de tête "[" indique un début fermé tandis que le dernier crochet ")" indique une extrémité ouverte.
Comme indiqué ci-dessus, les intervalles vides violent la condition de chevauchement ci-dessus (en particulier startA <endB), donc Time4J (et d'autres bibliothèques aussi) doit le traiter comme un cas de bord spécial afin de garantir que le chevauchement de tout intervalle arbitraire avec un intervalle vide n'existe pas. Bien sûr, les intervalles de date (qui sont fermés par défaut dans Time4J mais qui peuvent également être à moitié ouverts, comme les intervalles de date vides) sont traités de la même manière.
la source
Voici une méthode générique qui peut être utile localement.
la source
la source
En utilisant Java util.Date, voici ce que j'ai fait.
la source
À mon avis, la façon la plus simple de le faire serait de comparer si EndDate1 est avant StartDate2 et EndDate2 est avant StartDate1.
Cela bien sûr si vous envisagez des intervalles où StartDate est toujours avant EndDate.
la source
J'ai eu une situation où nous avions des dates au lieu de datetimes, et les dates ne pouvaient se chevaucher qu'au début / fin. Exemple ci-dessous:
(Le vert est l'intervalle actuel, les blocs bleus sont des intervalles valides, les rouges sont des intervalles qui se chevauchent).
J'ai adapté la réponse d'Ian Nelson à la solution suivante:
Cela correspond à tous les cas de chevauchement, mais ignore ceux qui se chevauchent.
la source
Divisez le problème en cas, puis gérez chaque cas .
La situation «deux plages de dates se croisent» est couverte par deux cas - la première plage de dates commence dans la seconde ou la deuxième plage de dates commence dans la première.
la source
Vous pouvez essayer ceci:
la source
C'était ma solution, elle retourne vrai lorsque les valeurs ne se chevauchent pas:
X DÉBUT 1 Y FIN 1
A DÉBUT 2 B FIN 2
la source
Pour rubis, j'ai également trouvé ceci:
Je l'ai trouvé ici avec une belle explication -> http://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-ruby-or-rails
la source
La requête ci-dessous me donne les identifiants pour lesquels la plage de dates fournie (dates de début et de fin se chevauche avec l'une des dates (dates de début et de fin) de mon nom_table)
la source