Use unix timestamps in timetable logic

Parse the iso date strings into millseconds from the unix epoch and use
that through the timetable logic instead of reparsing the strings over
and over.
This commit is contained in:
Hornwitser 2025-03-09 16:49:57 +01:00
parent c4a6f6b3f9
commit 1ac607a712

View file

@ -75,7 +75,7 @@ const oneMinMs = 60 * 1000;
type Edge = { type: "start" | "end", slot: TimeSlot };
/** Point in time where multiple edges meet. */
type Junction = { ts: string, edges: Edge[] };
type Junction = { ts: number, edges: Edge[] };
/** Span of time between two adjacent junctions */
type Span = {
@ -90,8 +90,8 @@ type Span = {
and the endpoint spans are always empty and at least one hour.
*/
type Stretch = {
start: string,
end: string,
start: number,
end: number,
spans: Span[];
}
@ -156,9 +156,9 @@ function* edgesFromEvents(events: Iterable<ScheduleEvent>): Generator<Edge> {
}
function junctionsFromEdges(edges: Iterable<Edge>) {
const junctions = new Map<string, Junction>();
const junctions = new Map<number, Junction>();
for (const edge of edges) {
const ts = edge.slot[edge.type];
const ts = Date.parse(edge.slot[edge.type]);
const junction = junctions.get(ts);
if (junction) {
junction.edges.push(edge);
@ -204,14 +204,11 @@ function* spansFromJunctions(
}
function createStretch(spans: Span[]): Stretch {
let startTs = Date.parse(spans[0].start.ts) - oneHourMs;
let endTs = Date.parse(spans[spans.length - 1].end.ts) + oneHourMs;
let start = spans[0].start.ts - oneHourMs;
let end = spans[spans.length - 1].end.ts + oneHourMs;
// Extend stretch to nearest whole hours
startTs = Math.floor(startTs / oneHourMs) * oneHourMs;
endTs = Math.ceil(endTs / oneHourMs) * oneHourMs;
// Convert back to ISO date string
let start = isoStringFromTs(startTs);
let end = isoStringFromTs(endTs);
start = Math.floor(start / oneHourMs) * oneHourMs;
end = Math.ceil(end / oneHourMs) * oneHourMs;
return {
spans: [
{
@ -237,7 +234,7 @@ function* stretchesFromSpans(spans: Iterable<Span>, minSeparation: number): Gene
// Based on how spans are generated I can assume that an empty span
// will only occur between two spans with timeslots in them.
if (span.locations.size === 0
&& Date.parse(span.end.ts) - Date.parse(span.start.ts) >= minSeparation
&& span.end.ts - span.start.ts >= minSeparation
) {
yield createStretch(currentSpans);
currentSpans = [];
@ -251,8 +248,8 @@ function* stretchesFromSpans(spans: Iterable<Span>, minSeparation: number): Gene
/** Cuts up a span by whole hours that crosses it */
function* cutSpansByHours(span: Span): Generator<Span> {
const startHour = Date.parse(span.start.ts) / oneHourMs;
const endHour = Date.parse(span.end.ts) / oneHourMs;
const startHour = span.start.ts / oneHourMs;
const endHour = span.end.ts / oneHourMs;
let currentStart = startHour;
let currentEnd = Math.min(Math.floor(startHour + 1), endHour);
if (currentEnd === endHour) {
@ -262,22 +259,22 @@ function* cutSpansByHours(span: Span): Generator<Span> {
yield {
start: span.start,
end: { ts: isoStringFromTs(currentEnd * oneHourMs), edges: [] },
end: { ts: currentEnd * oneHourMs, edges: [] },
locations: span.locations,
}
currentStart = currentEnd;
while (++currentEnd < endHour) {
yield {
start: { ts: isoStringFromTs(currentStart * oneHourMs), edges: [] },
end: { ts: isoStringFromTs(currentEnd * oneHourMs), edges: [] },
start: { ts: currentStart * oneHourMs, edges: [] },
end: { ts: currentEnd * oneHourMs, edges: [] },
locations: span.locations,
}
currentStart += 1;
}
yield {
start: { ts: isoStringFromTs(currentStart * oneHourMs), edges: [] },
start: { ts: currentStart * oneHourMs, edges: [] },
end: span.end,
locations: span.locations,
}
@ -322,14 +319,14 @@ function tableElementsFromStretches(
if (first) {
first = false;
startColumnGroup();
startDay(stretch.start.slice(0, 10));
startHour(stretch.start.slice(11, 16));
startDay(isoStringFromTs(stretch.start).slice(0, 10));
startHour(isoStringFromTs(stretch.start).slice(11, 16));
for(const location of locations) {
startLocation(location.id);
}
} else {
startColumnGroup("break");
const dayName = stretch.start.slice(0, 10)
const dayName = isoStringFromTs(stretch.start).slice(0, 10)
const lastDayHeader = dayHeaders[dayHeaders.length - 1]
const sameDay = dayName === lastDayHeader.content && lastDayHeader.span;
if (!sameDay)
@ -343,7 +340,7 @@ function tableElementsFromStretches(
startColumnGroup();
if (!sameDay)
startDay(dayName);
startHour(stretch.start.slice(11, 16));
startHour(isoStringFromTs(stretch.start).slice(11, 16));
for(const location of locations) {
startLocation(location.id);
}
@ -351,9 +348,8 @@ function tableElementsFromStretches(
for (const span of stretch.spans) {
for (const cutSpan of cutSpansByHours(span)) {
const startTs = Date.parse(cutSpan.start.ts);
const endTs = Date.parse(cutSpan.end.ts);
const durationMs = endTs - startTs;
const end = cutSpan.end.ts;
const durationMs = end - cutSpan.start.ts;
for (const location of locations) {
const rows = locationRows.get(location.id)!;
@ -365,11 +361,11 @@ function tableElementsFromStretches(
}
pushColumn(durationMs / oneMinMs);
if (endTs % oneDayMs === 0) {
startDay(cutSpan.end.ts.slice(0, 10));
if (end % oneDayMs === 0) {
startDay(isoStringFromTs(cutSpan.end.ts).slice(0, 10));
}
if (endTs % oneHourMs === 0) {
startHour(cutSpan.end.ts.slice(11, 16));
if (end % oneHourMs === 0) {
startHour(isoStringFromTs(cutSpan.end.ts).slice(11, 16));
}
}
}