Autor |
Beitrag |
Narses
Beiträge: 10182
Erhaltene Danke: 1255
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Di 07.03.17 18:23
Moin!
Komischer Titel, sorry, mir fällt kein besserer ein. Ich brauche bitte mal etwas Input, wie man dieses Problem grundsätzlich angeht. Es geht um folgendes: - Gegeben sind zwei Unix-Timestamps ("Zeitpunkte")
- Die Differenz der Timestamps ist die "Laufzeit" in Sekunden, soweit, so einfach
- Leider gibt es aber pro Wochentag "gewertete" und "wertungsfreie" Intervalle (hört sich schwieriger an, als es ist): Beispiel, MO, MI und FR "zählt" nur die Zeit zwischen 8-16 Uhr, DI und DO zwischen 8-18 Uhr, die restliche Zeit des Tages (SA+SO sowieso) ist "egal"
- Mich interessiert nun, wieviel der "Laufzeit" (Differenz der beiden Timestamps) in der "gewerteten" Zeit der dazwischen liegenden Tage liegt; die Anteile in den "wertungsfreien" Tageszeiten können einfach entfallen
Wie geht man sowas an, ohne sich in Fallunterscheidungen zu verlieren?! Irgendwie habe ich da grade ein Brett vorm Kopp! Ideen?
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Di 07.03.17 18:41
- Nachträglich durch die Entwickler-Ecke gelöscht -
Für diesen Beitrag haben gedankt: Narses
|
|
Ralf Jansen
Beiträge: 4706
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Di 07.03.17 19:46
Zitat: | Wie geht man sowas an, ohne sich in Fallunterscheidungen zu verlieren?! |
Kommt drauf an Wenn deine Beispiele soweit treffend sind das jeder Tag sich immer gleich verhält, also ein Montag immer wie ein Montag usw. ohne Regeln für besondere Montage dann würde ich so vorgehen.
A. Für jeden ganzen Wochentag die an diesem Tag zu berücksichtigende Zeit bestimmen (7 Konstanten unabhängig von deinem konkreten Zeitraum also was vorberechnetes)
B. Aus deinem konkreten Zeitraum die Randbeißer rausrechnen. Also die beiden Tage am Anfang und Ende die nicht vollständig abgebildet sind und die einzeln behandeln.
C. Anhand der nun kompletten Tage und der Info vom Startdatum(und dessen Wochentag) und der Anzahl folgender Tage kann ich das dann simpel die Anzahl der jeweiligen Wochentage ermitteln und das mit den Konstanten aus A ausmultiplizieren. (17 Montage mal 14400 Sekunden + 18 Dienstage * 14400 Sekunden usw.)
D. Jetzt die beiden anteiligen Tage(die Randbeißer) anhand ihres jeweiligen Wochentags noch dazurechnen. Je nachdem wie komplex die Regeln sind, mehrere zu berücksichtigende gewertete Zeiträume am Tag oder sowas, steckt hier etwas Komplexität. Wäre aber eigentlich der selbe Algo den man auch für A verwenden würde.
Das sollte man so halbwegs sauber in handhabbaren Einzelteilen zerlegen und dann lösen können.
Für diesen Beitrag haben gedankt: Narses
|
|
Boldar
Beiträge: 1555
Erhaltene Danke: 70
Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
|
Verfasst: Mi 08.03.17 04:33
Oder, wenn es viele/unregelmäßige Regeln gibt, eventuell iterativ mit Regeln aus einem Array:
Jeweils Funktion, die für jeden Zeitpunkt die nächste Intervallgrenze ermittelt plus die Zeit bis dahin zurückgibt. Diese Funktion dann solange ausführen, bisder Zielpinkt erreicht ist, und wenn Man sich in einem Gewertetem intervall befindet, die Zeit zum Ergebnis addieren.
Ich kann das nachher mal versuchen in (Pseudo-)code zu gießen, falls das jetzt zu unverständlich war.
So könnte man jedenfalls auf unregelmäßige Regeln behandeln, die sich nicht Wöchentlich wiederholen.
Für diesen Beitrag haben gedankt: Narses
|
|
jfheins
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: Mi 08.03.17 21:47
Da sich deine Regeln alle auf ganze Tage beziehen, würde ich den Zeitraum erst mal nach Tagen unterteilen. Dann kannst du für jeden Tag eine Überschneidung zwischen dem Zeitintervall und der interessanten Zeit berechnen. Also Top-Down programmiert in etwa so:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
| Voraussetzung: Mal orgendlich zusammenfassen class TimeSpan { public GetSeconds() Oder sowas public TimeSpan IntersectWith(TimeSpan t) }
var givenTime = new TimeSpan(ostern, weihnachten) int sum = 0; foreach (day in getDays(givenTime)) { sum += Evaluate(givenTime, day); }
function Evaluate(TimeSpan t, Day d) { switch (getWeekDayFor(d)) { case MO: return t.IntersectWith(new TimeSpan(day, 8, 16)).GetSeconds(); case D1: return t.IntersectWith(new TimeSpan(day, 8, 18)).GetSeconds(); case MI: return t.IntersectWith(new TimeSpan(day, 8, 16)).GetSeconds(); case DO: return t.IntersectWith(new TimeSpan(day, 8, 18)).GetSeconds(); case FR: return t.IntersectWith(new TimeSpan(day, 8, 16)).GetSeconds(); } return 0; }
function IEnumerable<TimeSpan> getDays(TimeSpan) liefert nacheinander alle Tage (komplett, als TimeSpan), die sich mit der Zeitspanne überschneiden. |
Ich vermute, du wirst um ein switch-case nicht drum herum kommen. (Oder du baust dir eine Zeit-Gewichtungsregel-Auswerte-Software, die du mit beliebigen Wichtungsregeln füttern kannst. Also z.B. Karfreitag wird mit 0 gewertet... aber das muss man wollen)
Das wichtige (was ich sehe) ist, dass dein switch-case nicht unerwartet cases dazu bekommt. Solange die Wochentage die Fälle sind, sehe ich da kein Problem.
Falls es mehrere relevante pro Tag geben kann (Mittagspause?), würde ich es so machen:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| function Evaluate(TimeSpan t, Day d) { const Dictionary<Weekday, TimeSpan[]> rules = new ....;
rules[Monday] = { new TimeSpan(day, 8, 11.5), new TimeSpan(day, 12.5, 16) }; rules[Tuesday] = { new TimeSpan(day, 8, 11.5), new TimeSpan(day, 12.5, 18) };
var weekday = getWeekDayFor(d); if rules.HasKey(weekday ) { return rules[weekday].Select(ts => t.IntersectWith(ts).GetSeconds()).Sum(); }
return 0; } |
Aber ich glaube, das ist erst mal Overkill. Erst mal was machen, was funktioniert. Dann wird man sehen, welchen Erweiterungsbedarf man hat.
Für diesen Beitrag haben gedankt: Narses
|
|
Narses
Beiträge: 10182
Erhaltene Danke: 1255
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mi 08.03.17 23:18
Moin!
Herzlichen Dank allen Ideen-Spendern.
Ich habe auch in Boldars Richtung gedacht und deshalb folgenden Ansatz gewählt: (PHP-Pseudocode)
PHP-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:
| function getWorkTime(DateTime $start, DateTime $stop) { $sow = clone $start; assertNextWorkDay($sow); setStartOfWork($sow); if ($sow < $start) $sow = clone $start; $eow = clone $stop; assertPrevWorkDay($eow); setEndOfWork($eow); if ($eow > $stop) $eow = clone $stop; $delta = 0; while ($sow < $eow) { if (isSameDay($sow, $eow)) { $delta += secondsBetween($sow, $eow); } else { $this_eow = clone $sow; setEndOfWork($this_eow); if ($sow < $this_eow) $delta += secondsBetween($sow, $this_eow); } nextWorkDay($sow); setStartOfWork($sow); } return $delta; | Dieser Ansatz funktioniert unter der Annahme, dass es pro Werktag immer nur eine "gewertete" Zeitspanne gibt. (das reicht mir allerdings schon).
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
|