Pit: PHP: Datumsprüfung gesucht

Hallo,

ich habe ein Ausgangsdatum X vorliegen und ich habe eine Kalenderwoche Y vorliegen, das sich chronologisch hinter dem X-Datum befindet. Zudem habe ich eine Wiederholungsregel Z, z.b. day, week, month oder year. Nun suche ich ein Verfahren, nachdem ich effizient prüfen kann, ob sich X + n*Z innerhalb von Y befindet. Und zusätzlich natürlich, wie oft bzw. wann.

Habt Ihr eine Idee? Ich komme tatsächlich nur darauf, alle Datümer X+n*Z durchzugehen, bis ich > Y bin und jeden Schritt nach Treffer/Nichttreffer zu prüfen.

Pit

  1. @@Pit

    ich habe ein Ausgangsdatum X vorliegen und ich habe eine Kalenderwoche Y vorliegen, das sich chronologisch hinter dem X-Datum befindet. Zudem habe ich eine Wiederholungsregel Z, z.b. day, week, month oder year. Nun suche ich ein Verfahren, nachdem ich effizient prüfen kann, ob sich X + n*Z innerhalb von Y befindet.

    Habt Ihr eine Idee? Ich komme tatsächlich nur darauf, alle Datümer X+n*Z durchzugehen, bis ich > Y bin und jeden Schritt nach Treffer/Nichttreffer zu prüfen.

    Der Aufwand ist linear O(n). Wie effizient soll es denn noch sein?

    Bei day und week geht’s mit konstantem Aufwand O(1): gib TRUE zurück. Oder allgemeiner: wenn Z < Länge(Y), dann TRUE, weil es immer ein n gibt, sodass X + n × Z in Y liegt.

    LLAP 🖖

    --
    “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
  2. Tach!

    ich habe ein Ausgangsdatum X vorliegen und ich habe eine Kalenderwoche Y vorliegen, das sich chronologisch hinter dem X-Datum befindet. Zudem habe ich eine Wiederholungsregel Z, z.b. day, week, month oder year. Nun suche ich ein Verfahren, nachdem ich effizient prüfen kann, ob sich X + n*Z innerhalb von Y befindet. Und zusätzlich natürlich, wie oft bzw. wann.

    Sowohl "wie oft" als auch "wann" ist kein Problem mehr, nachdem du alle n gefunden hast. Für ein einzelnes n ist die Prüfung recht trivial, aber wenn ich deine Beschreibung richtig interpretiere, geht es dir eigentlich darum, alle gültigen n überhaupt zu finden.

    Habt Ihr eine Idee? Ich komme tatsächlich nur darauf, alle Datümer X+n*Z durchzugehen, bis ich > Y bin und jeden Schritt nach Treffer/Nichttreffer zu prüfen.

    Vielleicht kann man da eine Formel finden. Ein Problem sind aber, wenn Monats- oder Jahreswechsel in den Zeiträumen liegen. Dann ist der Monat in solch einer Formel nicht nur m sondern m und m+1 oder m-1 je nach Betrachtungsweise. Es hilft auch nichts, diese Klippen umschiffen zu wollen, indem man einfach nur Tageszahlen nimmt, zum Beispiel die julianische Tagesnummer. Denn du hast weiterhin das Problem, dass die Monate und Jahre unterschiedlich lang sind. Es ist also nicht einfach zu einem JD-X (JD=Julian Day) eine Anzahl Monate/Jahre zu addieren. Also bleibt dir meines Erachtens nur die lineare Vorgehensweise.

    dedlfix.

  3. Hi,

    ich habe ein Ausgangsdatum X vorliegen und ich habe eine Kalenderwoche Y vorliegen, das sich chronologisch hinter dem X-Datum befindet.

    Das läßt darauf schließen, daß Y nicht nur "KW 33" ist, sondern daß es um die Kalenderwoche eines konkreten Jahres geht, also z.B. KW 33/2018.

    Dann könnte man das Datum des 1. und letzten Tages von Y errechnen, als Y1 und YL.

    Für Wiederholung day und week kommt ja eh immer true raus, das kann man schon vorher abhandeln.

    Für month: falls Y1 < YL (sprich: die KW ist komplett im Monat): nimm den Tag im Monat des Ausgangsdatums X (TiM(X)), ist er größergleich dem TiM(Y1) und kleinergleich dem TiM(YL), hast Du einen Treffer.

    falls Y1 > YL (sprich: KW geht über die Monatsgrenze): falls TiM(X) > TiM(Y1) oder TiM(X) < TiM(YL) hast Du einen Treffer.

    falls Y1 == YL: Y1 und Y2 nochmal neu berechnen, diesmal aber korrekt 😉

    (Sonderbehandlung, falls TiM(X) > 28 und Y fällt in Februar überlasse ich Dir)

    Für year: ähnliche Vorgehensweise, nur diesmal auch noch den Monat berücksichtigen. Evtl. das X' aus X erzeugen mit X' im selben Jahr wie Y (wegen Schaltjahr ...). Dann kann man statt des TiM das Julianische Dingens (Tag im Jahr) benutzen.

    cu,
    Andreas a/k/a MudGuard

    1. Hallo MudGuard,

      da wirst Du recht haben, es wird eine Kombination aus Wochennummer und Jahr sein. Aber nicht zwingend das aktuelle Jahr, gerade dann nicht, wenn X sich dem Jahresende nähert. Interessant ist, ob bei einem Y von "KW 33/2020" nur 33/2020 wichtig ist oder auch 33/2019 und 33/2018.

      Was mich von Pit interessiert, ist, ob Z+nX mit X=Tag|Woche|Monat|Jahr ausreicht. Gerade bei X=„Woche“ kann ich mir vorstellen, dass es Termine gibt, die sich alle 2 oder 4 Wochen wiederholen. Bei Monats- und Jahresrhythmen frage ich mich, ob da der Zyklusbruch Woche/Monat relevant wird. Was ist mit Terminen wie "am 1. Dienstag im Monat"?

      Den ersten Tag einer Kalenderwoche kann man mit setISODate bestimmen.

      Die Sonderfälle, die Du bei der TiM oder TiJ Rechnung bekommst, dürftest Du loswerden wenn Du mit Julianischen Tagen arbeitest -> cal_to_jd, damit bekommst Du keine Tagesnummer im Jahr, sondern eine fortlaufende Tagesnummer basierend auf einem Bezugsdatum in ferner Vergangenheit.

      Rolf

      --
      sumpsi - posui - clusi
      1. Hallo und erstmal danke an alle Beteiligten, dass Ihr Euch meinen Kopf ein wenig mit zerbrecht!

        Das sind schon wieder so viele gute Gedanken dabei, deshalb nochmal danke an jeden Einzelnen hier.

        da wirst Du recht haben, es wird eine Kombination aus Wochennummer und Jahr sein. Aber nicht zwingend das aktuelle Jahr, gerade dann nicht, wenn X sich dem Jahresende nähert. Interessant ist, ob bei einem Y von "KW 33/2020" nur 33/2020 wichtig ist oder auch 33/2019 und 33/2018.

        Ich hatte verschiedene Szenarien durchgespielt, hierunter eines, das ausschließlich KW33/2020 (auf obiges Bsp. bezogen) plus ggf. max. weitere 3 KW berücksichtigt, die der User in seinem Profil als anzuzeigenden Zeitraum festgelegt hat. Hiervon bin ich inzwischen wieder abgerückt, weil dieses Szenarium im weiteren Verlauf die Anzahl der db-Zugriffe unglaublich aufblähen würde. Performanter scheint mir da zu sein (und das ist aktueller Stand), dass (wieder auf obiges Bsp. bezogen) alle KWs von heute bis zur KW33/2020 relevant sein sollen. Das macht zwar im ersten Schritt sehr viele db-Einträge aus, aber im 2. Schritt (und der wird deutlich öfter ausgeführt) nur einen einzigen db-Zugriff, da ich für jede Regel den zeitpunkt festhalte, bis wann sie bereits abgehandelt wurde.

        Was mich von Pit interessiert, ist, ob Z+nX mit X=Tag|Woche|Monat|Jahr ausreicht. Gerade bei X=„Woche“ kann ich mir vorstellen, dass es Termine gibt, die sich alle 2 oder 4 Wochen wiederholen. Bei Monats- und Jahresrhythmen frage ich mich, ob da der Zyklusbruch Woche/Monat relevant wird. Was ist mit Terminen wie "am 1. Dienstag im Monat"?

        Bisher hätte ich "Z+nX mit X=Tag|Woche|Monat|Jahr" bejaht, aber Du hast recht, einige (durchaus nützliche und auch gängige) Terminvarianten würde ich damit außer Acht lassen 😟

        Den ersten Tag einer Kalenderwoche kann man mit setISODate bestimmen.

        Mache ich bisher so: strtotime("{$jahr}-W{$kalenderwoche}")

        Die Sonderfälle, die Du bei der TiM oder TiJ Rechnung bekommst, dürftest Du loswerden wenn Du mit Julianischen Tagen arbeitest -> cal_to_jd.

        Damit kenne ich mich mal so gar nicht aus... 😟

        Pit

        1. Tach!

          Was ist mit Terminen wie "am 1. Dienstag im Monat"?

          Bisher hätte ich "Z+nX mit X=Tag|Woche|Monat|Jahr" bejaht, aber Du hast recht, einige (durchaus nützliche und auch gängige) Terminvarianten würde ich damit außer Acht lassen 😟

          Wegen solcher hinzukommender Anwendungsfälle würde ich eine generische Lösung bevorzugen, statt eine die je nach Wiederholungsregel unterschiedlich arbeitet und deswegen für jede neue erweitert werden muss. Laufzeitunterschiede schätze ich als nicht spürbar ein, beziehungsweise würde erst bei Auffälligkeiten nach anderen Wegen suchen.

          Die Sonderfälle, die Du bei der TiM oder TiJ Rechnung bekommst, dürftest Du loswerden wenn Du mit Julianischen Tagen arbeitest -> cal_to_jd.

          Daran hatte ich auch schon gedacht, aber eine fortlaufende Tageszählung kann nicht besonders gut umgehen mit x + n Monate, weil "Monat" keine feste Länge hat. Und Jahr auch nicht.

          dedlfix.

          1. Hi dedlfix,

            Wegen solcher hinzukommender Anwendungsfälle würde ich eine generische Lösung bevorzugen, statt eine die je nach Wiederholungsregel unterschiedlich arbeitet und deswegen für jede neue erweitert werden muss. Laufzeitunterschiede schätze ich als nicht spürbar ein, beziehungsweise würde erst bei Auffälligkeiten nach anderen Wegen suchen.

            Kannst du etwas genauer werden? Wenns ichs linear angehe (und mal die von Rolf genannten Fälle zumindest erstmal außen vor lasse), benötige ich eigentlich nur 4 Werte: Startzeitpunkt- und Endzeitpunkt des Anzeigezeitraums, Startzeitpunkt des "Durchlaufs" sowie den wdh-Tonus als Iterator. Wäre doch generisch genug, oder?

            Pit

            1. Tach!

              Wenns ichs linear angehe (und mal die von Rolf genannten Fälle zumindest erstmal außen vor lasse), benötige ich eigentlich nur 4 Werte: Startzeitpunkt- und Endzeitpunkt des Anzeigezeitraums, Startzeitpunkt des "Durchlaufs" sowie den wdh-Tonus als Iterator. Wäre doch generisch genug, oder?

              Genau das meine ich damit. Du musst schauen, wie es bei vielen Iterationen wird, also ein großer Abstand zwischen X und Y sowie Z=1 Tag oder so.

              dedlfix.

              1. Hi dedlfix,

                Genau das meine ich damit. Du musst schauen, wie es bei vielen Iterationen wird, also ein großer Abstand zwischen X und Y sowie Z=1 Tag oder so.

                Habe ich mir auch schon Gedanken drüber gemacht. Um diese Wahrscheinlichkeit zu minimieren, dachte ich mir, nächtlich per Cron ein Regelupdate für den Zeitraum n Jahre zu fahren. Somit wären ab dem Update die Termine eh "hartcodiert" vorhanden. Alternativ könnte man für Tageswiederholungen einen maximalen Zeitraum (z.b. 1 Jahr) vorgeben. Oder aber man riskiert, dass ein User ggf. bis zur max. Scriptlaufzeit gehen muß.

                Oder hast Du noch ne andere Idee hierfür?

                Pit

                1. Tach!

                  Genau das meine ich damit. Du musst schauen, wie es bei vielen Iterationen wird, also ein großer Abstand zwischen X und Y sowie Z=1 Tag oder so.

                  Habe ich mir auch schon Gedanken drüber gemacht.

                  Erstmal probieren. Bei Versuchsaufbauten braucht man üblicherweise eine sehr hohe Durchlauf-Anzahl, um überhaupt erstmal in einen Bereich zu kommen, der sich vom Grundrauschen erkennbar unterscheidet. In deinem Fall hier sind die Unbekannten die Laufzeiten der Datumsfunktionen. Von denen hängt es ab, ob du schon bei 100 oder erst bei 100000 Intervallschritten was merkst.

                  dedlfix.

                  1. Hi,

                    Erstmal probieren. Bei Versuchsaufbauten braucht man üblicherweise eine sehr hohe Durchlauf-Anzahl, um überhaupt erstmal in einen Bereich zu kommen, der sich vom Grundrauschen erkennbar unterscheidet. In deinem Fall hier sind die Unbekannten die Laufzeiten der Datumsfunktionen. Von denen hängt es ab, ob du schon bei 100 oder erst bei 100000 Intervallschritten was merkst.

                    Ich habs probiert, mit dem Ergebnis, dass ich es umprogrammieren mußte. Meine Idee, immer von Terminoriginal an bis zum Anzeigezeitraum zu gehen, hat mich bei täglichen Wiederholungen sogar in den Scriptlauf-Timeout (>30sek) befördert. Wenn auch immerhin erst ab ca. 6000 Iterationen inkl. allem drum und dran, ging das also gar nicht. Daher bin ich umgestiegen auf ein System, das nun on the fly die Termine immer erst für den gesamten Anzeigezeitraum generiert, wenn dieser verfügbar sein soll. Das geht natürlich schnell und problemlos.

                    Pit

          2. Hallo dedlfix,

            ... würde ich eine generische Lösung bevorzugen, statt eine die je nach Wiederholungsregel unterschiedlich arbeitet und deswegen für jede neue erweitert werden muss. (... ... ...) Daran hatte ich auch schon gedacht, aber eine fortlaufende Tageszählung kann nicht besonders gut umgehen mit x + n Monate, weil "Monat" keine feste Länge hat. Und Jahr auch nicht.

            Tjaaa, ich sprach nicht ohne Grund von dem Zyklusbruch Woche/Monat. Ich denke, man braucht hier tatsächlich unterschiedliche Algorithmen. Je Zyklustyp einen. Der jeweilige Algorithmus wird dann jeweils schön kompakt und kann die für diesen Zyklustyp beste Datenrepräsentation verwenden. Eigentlich ein gefundenes Fressen für ein Factory-Pattern (damit man es nachher auch garantiert nicht mehr kapiert 😂)

            Rolf

            --
            sumpsi - posui - clusi