Time windows¶
Info
This feature is configurable via .json input, without the need for code
customization and is available for both the Marketplace app and Platform. You
can find a list of all available features.
Info
The format for timestamps should be RFC3339, e.g.:
"2023-01-01T00:00:00Z".
| Field name | Required | Data type | SI Unit | Defined on | Example | Configurable via defaults |
|---|---|---|---|---|---|---|
start_time_window |
No | array of timestamp or array of array of timestamp |
NA | stop |
{"start_time_window": [["2023-01-01T12:00:00Z", "2023-01-01T12:05:00Z"], ["2023-01-01T12:30:00Z", "2023-01-01T13:35:00Z"]]} |
✅ |
In vehicle routing problems stops often have to be serviced within specific time windows. E.g., in a bike sharing problem the stations have to be filled up with bikes while they are empty or bikes have to be picked up while they are full.
The start_time_window feature allows you to define a time window (or multiple
time windows) for when a stop must start to be serviced. The time window is
an array of two timestamps (or array of array of two timestamps), defined
by the earliest and latest times at which a stop can start service.
Info
A vehicle may arrive before the start_time_window opens, in which case it
will have to wait to start servicing the stop. The waiting time can be limited
by using the max_wait feature.
Here is an example that defines time windows on stops. A sample output obtained after solving the problem is also shown.
{
"defaults": {
"vehicles": {
"speed": 20,
"start_time": "2023-01-01T12:00:00Z"
},
"stops": {
"duration": 300
}
},
"stops": [
{
"id": "Fushimi Inari Taisha",
"location": { "lon": 135.772695, "lat": 34.967146 },
"start_time_window": ["2023-01-01T12:00:00Z", "2023-01-01T12:05:00Z"]
},
{
"id": "Kiyomizu-dera",
"location": { "lon": 135.78506, "lat": 34.994857 },
"start_time_window": ["2023-01-01T12:05:00Z", "2023-01-01T12:10:00Z"]
},
{
"id": "Nijō Castle",
"location": { "lon": 135.748134, "lat": 35.014239 },
"start_time_window": ["2023-01-01T12:10:00Z", "2023-01-01T12:15:00Z"]
},
{
"id": "Kyoto Imperial Palace",
"location": { "lon": 135.762057, "lat": 35.025431 },
"start_time_window": ["2023-01-01T12:15:00Z", "2023-01-01T12:20:00Z"]
},
{
"id": "Gionmachi",
"location": { "lon": 135.775682, "lat": 35.002457 },
"start_time_window": ["2023-01-01T12:20:00Z", "2023-01-01T12:25:00Z"]
},
{
"id": "Kinkaku-ji",
"location": { "lon": 135.728898, "lat": 35.039705 },
"start_time_window": ["2023-01-01T12:25:00Z", "2023-01-01T12:30:00Z"]
},
{
"id": "Arashiyama Bamboo Forest",
"location": { "lon": 135.672009, "lat": 35.017209 },
"start_time_window": ["2023-01-01T12:30:00Z", "2023-01-01T12:35:00Z"]
}
],
"vehicles": [
{
"id": "v1"
},
{
"id": "v2"
}
]
}
{
"options": {
"check": {
"duration": 30000000000,
"verbosity": "off"
},
"format": {
"disable": {
"progression": true
}
},
"model": {
"constraints": {
"disable": {
"attributes": false,
"capacities": null,
"capacity": false,
"distance_limit": false,
"groups": false,
"maximum_duration": false,
"maximum_stops": false,
"maximum_wait_stop": false,
"maximum_wait_vehicle": false,
"mixing_items": false,
"precedence": false,
"start_time_windows": false,
"vehicle_end_time": false,
"vehicle_start_time": false
},
"enable": {
"cluster": false
}
},
"objectives": {
"capacities": "",
"cluster": 0,
"distance": 0,
"early_arrival_penalty": 1,
"late_arrival_penalty": 1,
"min_stops": 1,
"stop_balance": 0,
"travel_duration": 0,
"unplanned_penalty": 1,
"vehicle_activation_penalty": 1,
"vehicles_duration": 1
},
"properties": {
"disable": {
"duration_groups": false,
"durations": false,
"initial_solution": false,
"stop_duration_multipliers": false
},
"maximum_time_horizon": 15552000
},
"validate": {
"disable": {
"resources": false,
"start_time": false
},
"enable": {
"matrix": false,
"matrix_asymmetry_tolerance": 20
}
}
},
"solve": {
"duration": 10000000000,
"iterations": 50,
"parallel_runs": 1,
"plateau": {
"absolute_threshold": -1,
"delay": 0,
"duration": 0,
"iterations": 0,
"relative_threshold": 0
},
"run_deterministically": true,
"solver": {
"plan_group_size": {
"delta": 0,
"delta_after_iterations": 1000000000,
"max_value": 2,
"min_value": 2,
"snap_back_after_improvement": true,
"start_value": 2,
"zigzag": true
},
"unplan_units": {
"delta": 2,
"delta_after_iterations": 125,
"max_value": -1,
"min_value": 2,
"snap_back_after_improvement": true,
"start_value": 2,
"zigzag": true
},
"unplan_weights": "Vehicle:3,Island:1,Location:293"
},
"start_solutions": 1
}
},
"solutions": [
{
"objective": {
"name": "1 * vehicles_duration + 1 * unplanned_penalty",
"objectives": [
{
"base": 3887.616171836853,
"factor": 1,
"name": "vehicles_duration",
"value": 3887.616171836853
},
{
"factor": 1,
"name": "unplanned_penalty",
"value": 0
}
],
"value": 3887.616171836853
},
"unplanned": [],
"vehicles": [
{
"id": "v1",
"route": [
{
"arrival_time": "2023-01-01T12:00:00Z",
"cumulative_travel_duration": 0,
"duration": 300,
"end_time": "2023-01-01T12:05:00Z",
"start_time": "2023-01-01T12:00:00Z",
"stop": {
"id": "Fushimi Inari Taisha",
"location": {
"lat": 34.967146,
"lon": 135.772695
}
},
"travel_duration": 0
},
{
"arrival_time": "2023-01-01T12:07:44Z",
"cumulative_travel_distance": 3280,
"cumulative_travel_duration": 164,
"duration": 300,
"end_time": "2023-01-01T12:12:44Z",
"start_time": "2023-01-01T12:07:44Z",
"stop": {
"id": "Kiyomizu-dera",
"location": {
"lat": 34.994857,
"lon": 135.78506
}
},
"travel_distance": 3280,
"travel_duration": 164
},
{
"arrival_time": "2023-01-01T12:16:03Z",
"cumulative_travel_distance": 7273,
"cumulative_travel_duration": 363,
"duration": 300,
"end_time": "2023-01-01T12:21:03Z",
"start_time": "2023-01-01T12:16:03Z",
"stop": {
"id": "Kyoto Imperial Palace",
"location": {
"lat": 35.025431,
"lon": 135.762057
}
},
"travel_distance": 3993,
"travel_duration": 199
},
{
"arrival_time": "2023-01-01T12:23:54Z",
"cumulative_travel_distance": 10683,
"cumulative_travel_duration": 534,
"duration": 300,
"end_time": "2023-01-01T12:30:00Z",
"start_time": "2023-01-01T12:25:00Z",
"stop": {
"id": "Kinkaku-ji",
"location": {
"lat": 35.039705,
"lon": 135.728898
}
},
"travel_distance": 3410,
"travel_duration": 170,
"waiting_duration": 66
},
{
"arrival_time": "2023-01-01T12:34:47Z",
"cumulative_travel_distance": 16435,
"cumulative_travel_duration": 821,
"duration": 300,
"end_time": "2023-01-01T12:39:47Z",
"start_time": "2023-01-01T12:34:47Z",
"stop": {
"id": "Arashiyama Bamboo Forest",
"location": {
"lat": 35.017209,
"lon": 135.672009
}
},
"travel_distance": 5752,
"travel_duration": 287
}
],
"route_duration": 2387,
"route_stops_duration": 1500,
"route_travel_distance": 16435,
"route_travel_duration": 821,
"route_waiting_duration": 66
},
{
"id": "v2",
"route": [
{
"arrival_time": "2023-01-01T12:00:00Z",
"cumulative_travel_duration": 0,
"duration": 300,
"end_time": "2023-01-01T12:15:00Z",
"start_time": "2023-01-01T12:10:00Z",
"stop": {
"id": "Nijō Castle",
"location": {
"lat": 35.014239,
"lon": 135.748134
}
},
"travel_duration": 0,
"waiting_duration": 600
},
{
"arrival_time": "2023-01-01T12:17:21Z",
"cumulative_travel_distance": 2830,
"cumulative_travel_duration": 141,
"duration": 300,
"end_time": "2023-01-01T12:25:00Z",
"start_time": "2023-01-01T12:20:00Z",
"stop": {
"id": "Gionmachi",
"location": {
"lat": 35.002457,
"lon": 135.775682
}
},
"travel_distance": 2830,
"travel_duration": 141,
"waiting_duration": 159
}
],
"route_duration": 1500,
"route_stops_duration": 600,
"route_travel_distance": 2830,
"route_travel_duration": 141,
"route_waiting_duration": 759
}
]
}
],
"statistics": {
"result": {
"custom": {
"activated_vehicles": 2,
"max_duration": 0.123,
"max_stops_in_vehicle": 5,
"max_travel_duration": 0.123,
"min_duration": 0.123,
"min_stops_in_vehicle": 2,
"min_travel_duration": 0.123,
"unplanned_stops": 0
},
"duration": 0.123,
"value": 0.123
},
"run": {
"duration": 0.123,
"iterations": 50
},
"schema": "v1"
},
"version": {
"sdk": "VERSION"
}
}
Here is an example using multiple time windows on stops.
{
"defaults": {
"vehicles": {
"speed": 15,
"start_time": "2023-01-01T12:00:00Z"
},
"stops": {
"unplanned_penalty": 20000,
"duration": 600,
"start_time_window": [
["2023-01-01T12:00:00Z", "2023-01-01T12:05:00Z"],
["2023-01-01T12:30:00Z", "2023-01-01T13:35:00Z"]
]
}
},
"stops": [
{
"id": "Kyoto Imperial Palace",
"location": { "lon": 135.77159, "lat": 34.96714 }
},
{
"id": "Gionmachi",
"location": { "lon": 135.77159, "lat": 34.96714 }
},
{
"id": "Kinkaku-ji",
"location": { "lon": 135.77159, "lat": 34.96714 },
"start_time_window": ["2023-01-01T12:20:00Z", "2023-01-01T12:25:00Z"]
}
],
"vehicles": [
{
"id": "v1"
}
]
}
{
"options": {
"check": {
"duration": 30000000000,
"verbosity": "off"
},
"format": {
"disable": {
"progression": true
}
},
"model": {
"constraints": {
"disable": {
"attributes": false,
"capacities": null,
"capacity": false,
"distance_limit": false,
"groups": false,
"maximum_duration": false,
"maximum_stops": false,
"maximum_wait_stop": false,
"maximum_wait_vehicle": false,
"mixing_items": false,
"precedence": false,
"start_time_windows": false,
"vehicle_end_time": false,
"vehicle_start_time": false
},
"enable": {
"cluster": false
}
},
"objectives": {
"capacities": "",
"cluster": 0,
"distance": 0,
"early_arrival_penalty": 1,
"late_arrival_penalty": 1,
"min_stops": 1,
"stop_balance": 0,
"travel_duration": 0,
"unplanned_penalty": 1,
"vehicle_activation_penalty": 1,
"vehicles_duration": 1
},
"properties": {
"disable": {
"duration_groups": false,
"durations": false,
"initial_solution": false,
"stop_duration_multipliers": false
},
"maximum_time_horizon": 15552000
},
"validate": {
"disable": {
"resources": false,
"start_time": false
},
"enable": {
"matrix": false,
"matrix_asymmetry_tolerance": 20
}
}
},
"solve": {
"duration": 10000000000,
"iterations": 50,
"parallel_runs": 1,
"plateau": {
"absolute_threshold": -1,
"delay": 0,
"duration": 0,
"iterations": 0,
"relative_threshold": 0
},
"run_deterministically": true,
"solver": {
"plan_group_size": {
"delta": 0,
"delta_after_iterations": 1000000000,
"max_value": 2,
"min_value": 2,
"snap_back_after_improvement": true,
"start_value": 2,
"zigzag": true
},
"unplan_units": {
"delta": 2,
"delta_after_iterations": 125,
"max_value": -1,
"min_value": 2,
"snap_back_after_improvement": true,
"start_value": 2,
"zigzag": true
},
"unplan_weights": "Vehicle:3,Island:1,Location:293"
},
"start_solutions": 1
}
},
"solutions": [
{
"objective": {
"name": "1 * vehicles_duration + 1 * unplanned_penalty",
"objectives": [
{
"base": 2400,
"factor": 1,
"name": "vehicles_duration",
"value": 2400
},
{
"factor": 1,
"name": "unplanned_penalty",
"value": 0
}
],
"value": 2400
},
"unplanned": [],
"vehicles": [
{
"id": "v1",
"route": [
{
"arrival_time": "2023-01-01T12:00:00Z",
"cumulative_travel_duration": 0,
"duration": 600,
"end_time": "2023-01-01T12:10:00Z",
"start_time": "2023-01-01T12:00:00Z",
"stop": {
"id": "Gionmachi",
"location": {
"lat": 34.96714,
"lon": 135.77159
}
},
"travel_duration": 0
},
{
"arrival_time": "2023-01-01T12:10:00Z",
"cumulative_travel_duration": 0,
"duration": 600,
"end_time": "2023-01-01T12:30:00Z",
"start_time": "2023-01-01T12:20:00Z",
"stop": {
"id": "Kinkaku-ji",
"location": {
"lat": 34.96714,
"lon": 135.77159
}
},
"travel_duration": 0,
"waiting_duration": 600
},
{
"arrival_time": "2023-01-01T12:30:00Z",
"cumulative_travel_duration": 0,
"duration": 600,
"end_time": "2023-01-01T12:40:00Z",
"start_time": "2023-01-01T12:30:00Z",
"stop": {
"id": "Kyoto Imperial Palace",
"location": {
"lat": 34.96714,
"lon": 135.77159
}
},
"travel_duration": 0
}
],
"route_duration": 2400,
"route_stops_duration": 1800,
"route_travel_duration": 0,
"route_waiting_duration": 600
}
]
}
],
"statistics": {
"result": {
"custom": {
"activated_vehicles": 1,
"max_duration": 0.123,
"max_stops_in_vehicle": 3,
"max_travel_duration": 0.123,
"min_duration": 0.123,
"min_stops_in_vehicle": 3,
"min_travel_duration": 0.123,
"unplanned_stops": 0
},
"duration": 0.123,
"value": 0.123
},
"run": {
"duration": 0.123,
"iterations": 50
},
"schema": "v1"
},
"version": {
"sdk": "VERSION"
}
}