Implement enhanced transport connection optimization logic
Co-authored-by: clayschaad <11883505+clayschaad@users.noreply.github.com>
This commit is contained in:
parent
9e7b989bf6
commit
c35fec73eb
5 changed files with 387 additions and 4 deletions
|
|
@ -33,4 +33,71 @@ public static class TransportConnectionCalculator
|
||||||
.OrderBy(c => DateTime.Parse(c.ArrivalTime ?? "23:59"))
|
.OrderBy(c => DateTime.Parse(c.ArrivalTime ?? "23:59"))
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TransportConnection? FindBestConnection(
|
||||||
|
IReadOnlyList<TransportConnection> connections,
|
||||||
|
DateTime shiftStartTime,
|
||||||
|
int safetyBufferMinutes,
|
||||||
|
int maxEarlyArrivalMinutes,
|
||||||
|
int maxLateArrivalMinutes)
|
||||||
|
{
|
||||||
|
var latestArrivalTime = shiftStartTime.AddMinutes(-safetyBufferMinutes);
|
||||||
|
var earliestAcceptableTime = shiftStartTime.AddMinutes(-maxEarlyArrivalMinutes);
|
||||||
|
var latestAcceptableTime = shiftStartTime.AddMinutes(maxLateArrivalMinutes);
|
||||||
|
|
||||||
|
var validConnections = new List<TransportConnection>();
|
||||||
|
var lateValidConnections = new List<TransportConnection>();
|
||||||
|
|
||||||
|
foreach (var connection in connections)
|
||||||
|
{
|
||||||
|
if (DateTime.TryParse(connection.ArrivalTime, out var arrivalTime))
|
||||||
|
{
|
||||||
|
if (arrivalTime <= latestArrivalTime)
|
||||||
|
{
|
||||||
|
validConnections.Add(connection);
|
||||||
|
}
|
||||||
|
else if (arrivalTime <= latestAcceptableTime)
|
||||||
|
{
|
||||||
|
lateValidConnections.Add(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have valid connections (arriving before latest arrival time)
|
||||||
|
if (validConnections.Count > 0)
|
||||||
|
{
|
||||||
|
var sortedValid = validConnections
|
||||||
|
.OrderBy(c => DateTime.Parse(c.ArrivalTime ?? "00:00"))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var bestValidConnection = sortedValid.Last();
|
||||||
|
var bestValidArrivalTime = DateTime.Parse(bestValidConnection.ArrivalTime!);
|
||||||
|
|
||||||
|
// Check if the best valid connection arrives too early (more than maxEarlyArrivalMinutes before shift)
|
||||||
|
if (bestValidArrivalTime < earliestAcceptableTime && lateValidConnections.Count > 0)
|
||||||
|
{
|
||||||
|
// Return the earliest connection that arrives after latest arrival time but within acceptable range
|
||||||
|
var sortedLateValid = lateValidConnections
|
||||||
|
.OrderBy(c => DateTime.Parse(c.ArrivalTime ?? "23:59"))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return sortedLateValid.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestValidConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no connections arrive before latest arrival time, check if any arrive within acceptable late range
|
||||||
|
if (lateValidConnections.Count > 0)
|
||||||
|
{
|
||||||
|
var sortedLateValid = lateValidConnections
|
||||||
|
.OrderBy(c => DateTime.Parse(c.ArrivalTime ?? "23:59"))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return sortedLateValid.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
// No suitable connections found
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,9 +9,12 @@ namespace ShiftScheduler.Services
|
||||||
{
|
{
|
||||||
var latestArrivalTime = shiftStartTime.AddMinutes(-config.SafetyBufferMinutes);
|
var latestArrivalTime = shiftStartTime.AddMinutes(-config.SafetyBufferMinutes);
|
||||||
var searchDate = shiftStartTime.ToString("yyyy-MM-dd");
|
var searchDate = shiftStartTime.ToString("yyyy-MM-dd");
|
||||||
var searchTime = shiftStartTime.ToString("HH:mm");
|
|
||||||
|
|
||||||
var url = $"{config.ApiBaseUrl}/connections?from={Uri.EscapeDataString(config.StartStation)}&to={Uri.EscapeDataString(config.EndStation)}&date={searchDate}&time={searchTime}&isArrivalTime=1&limit=5";
|
// To allow connections that arrive after shift starts, we search from earlier time
|
||||||
|
// and request more connections to cover the full range
|
||||||
|
var searchTime = shiftStartTime.AddMinutes(-config.MaxEarlyArrivalMinutes - config.SafetyBufferMinutes).ToString("HH:mm");
|
||||||
|
|
||||||
|
var url = $"{config.ApiBaseUrl}/connections?from={Uri.EscapeDataString(config.StartStation)}&to={Uri.EscapeDataString(config.EndStation)}&date={searchDate}&time={searchTime}&isArrivalTime=1&limit=10";
|
||||||
var response = await httpClient.GetStringAsync(url);
|
var response = await httpClient.GetStringAsync(url);
|
||||||
var apiResponse = JsonSerializer.Deserialize<TransportApiResponse>(response, new JsonSerializerOptions
|
var apiResponse = JsonSerializer.Deserialize<TransportApiResponse>(response, new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
|
|
@ -21,7 +24,12 @@ namespace ShiftScheduler.Services
|
||||||
if (apiResponse?.Connections.Count > 0)
|
if (apiResponse?.Connections.Count > 0)
|
||||||
{
|
{
|
||||||
var allConnections = apiResponse.Connections.Select(MapToTransportConnection).ToList();
|
var allConnections = apiResponse.Connections.Select(MapToTransportConnection).ToList();
|
||||||
return TransportConnectionCalculator.FindBestConnection(allConnections, latestArrivalTime);
|
return TransportConnectionCalculator.FindBestConnection(
|
||||||
|
allConnections,
|
||||||
|
shiftStartTime,
|
||||||
|
config.SafetyBufferMinutes,
|
||||||
|
config.MaxEarlyArrivalMinutes,
|
||||||
|
config.MaxLateArrivalMinutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ namespace ShiftScheduler.Shared
|
||||||
public string ApiBaseUrl { get; set; } = string.Empty;
|
public string ApiBaseUrl { get; set; } = string.Empty;
|
||||||
public int SafetyBufferMinutes { get; set; } = 30;
|
public int SafetyBufferMinutes { get; set; } = 30;
|
||||||
public int MinBreakMinutes { get; set; } = 60;
|
public int MinBreakMinutes { get; set; } = 60;
|
||||||
|
public int MaxEarlyArrivalMinutes { get; set; } = 60; // Y parameter
|
||||||
|
public int MaxLateArrivalMinutes { get; set; } = 15; // X parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TransportConnection
|
public class TransportConnection
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,222 @@
|
||||||
|
using ShiftScheduler.Services;
|
||||||
|
using ShiftScheduler.Shared;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
|
namespace ShiftScheduler.Services.Tests;
|
||||||
|
|
||||||
|
public class TransportConnectionCalculatorTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void FindBestConnection_WithValidConnections_ShouldReturnLatestValidConnection()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var connections = new List<TransportConnection>
|
||||||
|
{
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T07:15:00" },
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T07:25:00" },
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T07:35:00" } // This one is too late
|
||||||
|
};
|
||||||
|
var latestArrivalTime = new DateTime(2023, 12, 15, 7, 30, 0);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = TransportConnectionCalculator.FindBestConnection(connections, latestArrivalTime);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.ShouldNotBeNull();
|
||||||
|
result.ArrivalTime.ShouldBe("2023-12-15T07:25:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindBestConnection_WithNoValidConnections_ShouldReturnEarliestConnection()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var connections = new List<TransportConnection>
|
||||||
|
{
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T07:35:00" },
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T07:40:00" },
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T07:32:00" }
|
||||||
|
};
|
||||||
|
var latestArrivalTime = new DateTime(2023, 12, 15, 7, 30, 0);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = TransportConnectionCalculator.FindBestConnection(connections, latestArrivalTime);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.ShouldNotBeNull();
|
||||||
|
result.ArrivalTime.ShouldBe("2023-12-15T07:32:00"); // Earliest of the invalid ones
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindBestConnection_WithEmptyConnections_ShouldReturnNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var connections = new List<TransportConnection>();
|
||||||
|
var latestArrivalTime = new DateTime(2023, 12, 15, 7, 30, 0);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = TransportConnectionCalculator.FindBestConnection(connections, latestArrivalTime);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.ShouldBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindBestConnection_WithInvalidArrivalTimes_ShouldIgnoreInvalidEntries()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var connections = new List<TransportConnection>
|
||||||
|
{
|
||||||
|
new TransportConnection { ArrivalTime = "invalid-time" },
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T07:25:00" },
|
||||||
|
new TransportConnection { ArrivalTime = "" }
|
||||||
|
};
|
||||||
|
var latestArrivalTime = new DateTime(2023, 12, 15, 7, 30, 0);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = TransportConnectionCalculator.FindBestConnection(connections, latestArrivalTime);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.ShouldNotBeNull();
|
||||||
|
result.ArrivalTime.ShouldBe("2023-12-15T07:25:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests for new enhanced logic
|
||||||
|
[Fact]
|
||||||
|
public void FindBestConnectionEnhanced_WithGoodTimingConnection_ShouldReturnLatestValidConnection()
|
||||||
|
{
|
||||||
|
// Arrange - Shift starts at 8:00, safety buffer 30 min, so latest arrival is 7:30
|
||||||
|
var connections = new List<TransportConnection>
|
||||||
|
{
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T07:15:00" },
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T07:25:00" }, // Should be selected (latest valid)
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T08:05:00" } // Too late
|
||||||
|
};
|
||||||
|
var shiftStartTime = new DateTime(2023, 12, 15, 8, 0, 0);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = TransportConnectionCalculator.FindBestConnection(
|
||||||
|
connections, shiftStartTime, 30, 60, 15);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.ShouldNotBeNull();
|
||||||
|
result.ArrivalTime.ShouldBe("2023-12-15T07:25:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindBestConnectionEnhanced_WithTooEarlyConnection_ShouldPreferLaterConnection()
|
||||||
|
{
|
||||||
|
// Arrange - Shift starts at 8:00, max early arrival 60 min, so earliest acceptable is 7:00
|
||||||
|
var connections = new List<TransportConnection>
|
||||||
|
{
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T06:45:00" }, // Too early (more than 60 min before 8:00)
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T08:05:00" } // Within acceptable late range (15 min after 8:00)
|
||||||
|
};
|
||||||
|
var shiftStartTime = new DateTime(2023, 12, 15, 8, 0, 0);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = TransportConnectionCalculator.FindBestConnection(
|
||||||
|
connections, shiftStartTime, 30, 60, 15);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.ShouldNotBeNull();
|
||||||
|
result.ArrivalTime.ShouldBe("2023-12-15T08:05:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindBestConnectionEnhanced_WithMultipleLateConnections_ShouldReturnEarliest()
|
||||||
|
{
|
||||||
|
// Arrange - Shift starts at 8:00, no valid early connections
|
||||||
|
var connections = new List<TransportConnection>
|
||||||
|
{
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T08:10:00" },
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T08:05:00" }, // Should be selected (earliest late)
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T08:12:00" }
|
||||||
|
};
|
||||||
|
var shiftStartTime = new DateTime(2023, 12, 15, 8, 0, 0);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = TransportConnectionCalculator.FindBestConnection(
|
||||||
|
connections, shiftStartTime, 30, 60, 15);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.ShouldNotBeNull();
|
||||||
|
result.ArrivalTime.ShouldBe("2023-12-15T08:05:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindBestConnectionEnhanced_WithConnectionsBeyondAcceptableRange_ShouldReturnNull()
|
||||||
|
{
|
||||||
|
// Arrange - All connections are too late (beyond max late arrival)
|
||||||
|
var connections = new List<TransportConnection>
|
||||||
|
{
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T08:20:00" },
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T08:25:00" },
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T08:30:00" }
|
||||||
|
};
|
||||||
|
var shiftStartTime = new DateTime(2023, 12, 15, 8, 0, 0);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = TransportConnectionCalculator.FindBestConnection(
|
||||||
|
connections, shiftStartTime, 30, 60, 15);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.ShouldBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindBestConnectionEnhanced_WithAcceptableEarlyConnection_ShouldNotPreferLate()
|
||||||
|
{
|
||||||
|
// Arrange - Early connection is acceptable (not too early), should prefer it over late
|
||||||
|
var connections = new List<TransportConnection>
|
||||||
|
{
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T07:20:00" }, // 40 min before shift - acceptable
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T08:05:00" } // 5 min after shift
|
||||||
|
};
|
||||||
|
var shiftStartTime = new DateTime(2023, 12, 15, 8, 0, 0);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = TransportConnectionCalculator.FindBestConnection(
|
||||||
|
connections, shiftStartTime, 30, 60, 15);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.ShouldNotBeNull();
|
||||||
|
result.ArrivalTime.ShouldBe("2023-12-15T07:20:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindBestConnectionEnhanced_WithEmptyConnections_ShouldReturnNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var connections = new List<TransportConnection>();
|
||||||
|
var shiftStartTime = new DateTime(2023, 12, 15, 8, 0, 0);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = TransportConnectionCalculator.FindBestConnection(
|
||||||
|
connections, shiftStartTime, 30, 60, 15);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.ShouldBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindBestConnectionEnhanced_WithMixedValidAndLateConnections_ShouldChooseBasedOnTiming()
|
||||||
|
{
|
||||||
|
// Arrange - Test scenario where both valid and late connections exist
|
||||||
|
var connections = new List<TransportConnection>
|
||||||
|
{
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T06:30:00" }, // Too early (90 min before shift)
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T07:25:00" }, // Valid but would be considered too early
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T08:05:00" }, // Late but acceptable
|
||||||
|
new TransportConnection { ArrivalTime = "2023-12-15T08:20:00" } // Too late
|
||||||
|
};
|
||||||
|
var shiftStartTime = new DateTime(2023, 12, 15, 8, 0, 0);
|
||||||
|
|
||||||
|
// Act - MaxEarlyArrivalMinutes = 30, so earliest acceptable is 7:30
|
||||||
|
var result = TransportConnectionCalculator.FindBestConnection(
|
||||||
|
connections, shiftStartTime, 30, 30, 15);
|
||||||
|
|
||||||
|
// Assert - 7:25 arrives at 7:25, which is 35 min before shift (more than 30 min), so should prefer late connection
|
||||||
|
result.ShouldNotBeNull();
|
||||||
|
result.ArrivalTime.ShouldBe("2023-12-15T08:05:00");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,9 @@ public class TransportServiceTests
|
||||||
EndStation = "Bern",
|
EndStation = "Bern",
|
||||||
ApiBaseUrl = "https://transport.opendata.ch/v1",
|
ApiBaseUrl = "https://transport.opendata.ch/v1",
|
||||||
SafetyBufferMinutes = 30,
|
SafetyBufferMinutes = 30,
|
||||||
MinBreakMinutes = 60
|
MinBreakMinutes = 60,
|
||||||
|
MaxEarlyArrivalMinutes = 60,
|
||||||
|
MaxLateArrivalMinutes = 15
|
||||||
};
|
};
|
||||||
|
|
||||||
_transportService = new TransportService(_httpClient, config);
|
_transportService = new TransportService(_httpClient, config);
|
||||||
|
|
@ -238,4 +240,86 @@ public class TransportServiceTests
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetConnectionAsync_WithNewLogic_ShouldHandleEarlyAndLateConnections()
|
||||||
|
{
|
||||||
|
// Arrange - Shift starts at 8:00, test new logic with late-arriving connections
|
||||||
|
var shiftStartTime = new DateTime(2023, 12, 15, 8, 0, 0);
|
||||||
|
var apiResponse = CreateConnectionsForNewLogicTest();
|
||||||
|
var jsonResponse = JsonSerializer.Serialize(apiResponse);
|
||||||
|
|
||||||
|
SetupHttpMockResponse(HttpStatusCode.OK, jsonResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await _transportService.GetConnectionAsync(shiftStartTime);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.ShouldNotBeNull();
|
||||||
|
// With MaxEarlyArrivalMinutes = 60, connections arriving before 7:00 are too early
|
||||||
|
// The connection arriving at 6:30 (90 min before shift) should be considered too early
|
||||||
|
// So it should prefer the connection at 8:05 (5 min after shift, within MaxLateArrivalMinutes = 15)
|
||||||
|
result.ArrivalTime.ShouldBe("2023-12-15T08:05:00");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TransportApiResponse CreateConnectionsForNewLogicTest()
|
||||||
|
{
|
||||||
|
return new TransportApiResponse
|
||||||
|
{
|
||||||
|
Connections = new List<TransportApiConnection>
|
||||||
|
{
|
||||||
|
// Too early connection (90 min before shift start)
|
||||||
|
new TransportApiConnection
|
||||||
|
{
|
||||||
|
From = new TransportApiCheckpoint
|
||||||
|
{
|
||||||
|
Station = new TransportApiStation { Name = "Zurich HB", Id = "zurich" },
|
||||||
|
Departure = "2023-12-15T05:30:00",
|
||||||
|
Platform = "5"
|
||||||
|
},
|
||||||
|
To = new TransportApiCheckpoint
|
||||||
|
{
|
||||||
|
Station = new TransportApiStation { Name = "Bern", Id = "bern" },
|
||||||
|
Arrival = "2023-12-15T06:30:00",
|
||||||
|
Platform = "3"
|
||||||
|
},
|
||||||
|
Duration = "01:00:00"
|
||||||
|
},
|
||||||
|
// Late but acceptable connection (5 min after shift start)
|
||||||
|
new TransportApiConnection
|
||||||
|
{
|
||||||
|
From = new TransportApiCheckpoint
|
||||||
|
{
|
||||||
|
Station = new TransportApiStation { Name = "Zurich HB", Id = "zurich" },
|
||||||
|
Departure = "2023-12-15T07:20:00",
|
||||||
|
Platform = "4"
|
||||||
|
},
|
||||||
|
To = new TransportApiCheckpoint
|
||||||
|
{
|
||||||
|
Station = new TransportApiStation { Name = "Bern", Id = "bern" },
|
||||||
|
Arrival = "2023-12-15T08:05:00",
|
||||||
|
Platform = "2"
|
||||||
|
},
|
||||||
|
Duration = "00:45:00"
|
||||||
|
},
|
||||||
|
// Too late connection (20 min after shift start, beyond MaxLateArrivalMinutes)
|
||||||
|
new TransportApiConnection
|
||||||
|
{
|
||||||
|
From = new TransportApiCheckpoint
|
||||||
|
{
|
||||||
|
Station = new TransportApiStation { Name = "Zurich HB", Id = "zurich" },
|
||||||
|
Departure = "2023-12-15T07:35:00",
|
||||||
|
Platform = "6"
|
||||||
|
},
|
||||||
|
To = new TransportApiCheckpoint
|
||||||
|
{
|
||||||
|
Station = new TransportApiStation { Name = "Bern", Id = "bern" },
|
||||||
|
Arrival = "2023-12-15T08:20:00",
|
||||||
|
Platform = "1"
|
||||||
|
},
|
||||||
|
Duration = "00:45:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue