Skip to content

Commit 59811db

Browse files
joern-lang-studitempsKai Kuchenbeckerclaude
committed
Implementiere vereinigung/1 und vereinigung/2 für Zeiträume
Ermöglicht das Vereinigen von überlappenden oder angrenzenden Zeiträumen zu einem einzelnen Intervall. Bei nicht überlappenden Zeiträumen werden beide als Tuple bzw. Liste zurückgegeben. Co-Authored-By: Kai Kuchenbecker <kai.kuchenbecker@jobvalley.com> Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3c7aa9a commit 59811db

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

lib/zeitraum.ex

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,86 @@ defmodule Shared.Zeitraum do
152152
end
153153
end
154154

155+
@doc """
156+
Bildet die Vereinigung zweier Zeiträume.
157+
158+
Sollten diese nicht überlappen werden beide als tuple zurückgegeben.
159+
160+
## Beispiel
161+
162+
iex> vereinigung(~v[2025-05], ~m[2025-01])
163+
%Timex.Interval{from: ~N[2025-01-01 00:00:00], until: ~N[2025-02-03 00:00:00], step: [seconds: 1]}
164+
165+
iex> vereinigung(~v[2025-05], ~v[2025-04])
166+
%Timex.Interval{from: ~N[2025-01-20 00:00:00], until: ~N[2025-02-03 00:00:00], step: [seconds: 1]}
167+
168+
iex> vereinigung(~v[2025-05], ~v[2025-03])
169+
{%Timex.Interval{from: ~N[2025-01-27 00:00:00], until: ~N[2025-02-03 00:00:00], step: [seconds: 1]},
170+
%Timex.Interval{from: ~N[2025-01-13 00:00:00], until: ~N[2025-01-20 00:00:00], step: [seconds: 1]}}
171+
"""
172+
@spec vereinigung(t(), t()) :: t() | {t(), t()}
173+
def vereinigung(a, b) do
174+
intervall_a = als_intervall(a)
175+
intervall_b = als_intervall(b)
176+
177+
if ueberschneidung?(intervall_a, intervall_b) or grenzen_aneinander?(intervall_a, intervall_b) do
178+
from = Enum.min([intervall_a.from, intervall_b.from], NaiveDateTime)
179+
until = Enum.max([intervall_a.until, intervall_b.until], NaiveDateTime)
180+
181+
Timex.Interval.new(from: from, until: until, step: [seconds: 1])
182+
else
183+
{intervall_a, intervall_b}
184+
end
185+
end
186+
187+
@doc """
188+
Bildet die Vereinigung aller Zeiträume.
189+
190+
Gibt eine Liste nicht überlappender Zeiträume zurück.
191+
192+
## Beispiel
193+
194+
iex> vereinigung([~v[2025-05], ~m[2025-01]])
195+
[%Timex.Interval{from: ~N[2025-01-01 00:00:00], until: ~N[2025-02-03 00:00:00], step: [seconds: 1]}]
196+
197+
iex> vereinigung([~v[2025-05], ~v[2025-04]])
198+
[%Timex.Interval{from: ~N[2025-01-20 00:00:00], until: ~N[2025-02-03 00:00:00], step: [seconds: 1]}]
199+
200+
iex> vereinigung([~v[2025-05], ~v[2025-03]])
201+
[%Timex.Interval{from: ~N[2025-01-13 00:00:00], until: ~N[2025-01-20 00:00:00], step: [seconds: 1]},
202+
%Timex.Interval{from: ~N[2025-01-27 00:00:00], until: ~N[2025-02-03 00:00:00], step: [seconds: 1]}]
203+
204+
iex> vereinigung([~D[2025-01-01], ~D[2025-01-02], ~D[2025-01-07], ~D[2025-01-02], ~D[2025-01-05], ~v[2025-01]])
205+
[%Timex.Interval{from: ~N[2024-12-30 00:00:00], until: ~N[2025-01-06 00:00:00], step: [seconds: 1]},
206+
%Timex.Interval{from: ~N[2025-01-07 00:00:00], until: ~N[2025-01-08 00:00:00], step: [seconds: 1]}]
207+
208+
"""
209+
@spec vereinigung([t()]) :: [t()]
210+
def vereinigung(intervalle) do
211+
intervalle
212+
|> Enum.map(&als_intervall/1)
213+
|> Enum.sort(__MODULE__)
214+
|> vereinige_sortierte_intervalle()
215+
end
216+
217+
defp vereinige_sortierte_intervalle([]), do: []
218+
defp vereinige_sortierte_intervalle([einzelnes]), do: [einzelnes]
219+
220+
defp vereinige_sortierte_intervalle([erstes, zweites | rest]) do
221+
case vereinigung(erstes, zweites) do
222+
%Timex.Interval{} = vereinigtes ->
223+
vereinige_sortierte_intervalle([vereinigtes | rest])
224+
225+
{_erstes, _zweites} ->
226+
[erstes | vereinige_sortierte_intervalle([zweites | rest])]
227+
end
228+
end
229+
230+
defp grenzen_aneinander?(intervall_a, intervall_b) do
231+
NaiveDateTime.compare(intervall_a.until, intervall_b.from) == :eq or
232+
NaiveDateTime.compare(intervall_b.until, intervall_a.from) == :eq
233+
end
234+
155235
@doc """
156236
Testet ob der beginn des ersten Zeitraums vor dem des zweiten liegt.
157237

0 commit comments

Comments
 (0)