Plan multi-day long-haul tours
With the dutyRule feature, you can specify the maximum time that drivers can spend on duty during the working period. This includes the time spent driving between consecutive stops, loading or unloading goods, or performing any other work-related activities. In addition, you can schedule the fixed off-duty break duration for time spent away from work-related activities, such as sleeping, resting, or engaging in personal activities.
This feature enforces compliance with such regulatory bodies as the Federal Motor Carrier Safety Administration (FMCSA) in the USA or the Directorate-General for Mobility and Transport of the European Commission (DG MOVE) when planning tours which extend one day and ensures the driver gets sufficient rest and recovery time. For example, when a driver's tour exceeds 10 hours of driving and 14 hours of working time per working period, you can schedule a mandatory 10-hour duty break before the next working period to comply with the local regulations.
Additionally, the dutyRule feature integrates with both working and driving restTimes, enabling full compliance with regulations governing on-duty driving and working time, as well as on-duty breaks. For example, you can mandate a 30-minute break after every 4 hours of driving or 6 hours of working while the driver is on duty. This compatibility between dutyRule and working/driving restTimes ensures adherence to a wide range of regulatory requirements.
Note
This is an ALPHA feature, which means it is new or experimental and under active development. Alpha features are provided for testing and feedback purposes. They may change significantly or might not become generally available.
For more information, see Explore experimental features.
The following diagram shows how dutyRule integrates with other restTimes features to comply with a wide range regulations for driver safety during long-haul tours:
The previous figure illustrates a common scenario where a long-haul driver completes their work duties (driving and other activities such as handling goods, paperwork, etc.) during the day, with time allocated for an evening duty break. Alternatively, you can customize the shift configuration to accommodate a night shift with daytime rest periods, depending on your specific use case requirements.
The time window governing long-haul tour duration is defined by the shift start and end dates, often spanning multiple days.
Understand duty rule configuration
In a vehicle routing problem, you place the dutyRule object as part of the fleet.types.shift.restTimes object. The dutyRule object has the following settings:
-
type(required): AlwaysfixedDuration. -
minOffTime(required): The required time between consecutive duties or working days, representing the off-duty break duration, expressed in seconds. -
maxDrivingTime: The maximum allowed driving time per working period, expressed in seconds. -
maxWorkingTime: The maximum allowed working time (includes driving plus other work-related activities like pickup or delivery of goods) per working period, expressed in seconds. -
canStartEarly(optional): Set totrueto allow the optimization algorithm to start a duty break before the vehicle reaches its maximum driving or working time. It can help schedule the break during otherwise unused time and reduce waiting or accommodate jobs with tight time window constraints. The default isfalse. For a practical demonstration of this option, see Example: Rescue an unassigned job with an early duty break.Note
You must set
maxWorkingTimeforcanStartEarlyto take effect.
For more information, see the API Reference.
The following snippet shows a sample restTimes object that includes the dutyRule object in a problem adjusted for optimizing long-haul tours:
{
"restTimes": {
"working": {
"type": "fixedDuration",
"interval": 21600, // 6 hours
"breakDuration": 1800 // 30 minutes
},
"driving": {
"type": "fixedDuration",
"interval": 14400, // 4 hours
"breakDuration": 1800 // 30 minutes
},
"dutyRule": {
"type": "fixedDuration",
"minOffTime": 36000, // 10 hours
"maxDrivingTime": 36000, // 10 hours
"maxWorkingTime": 50400, // 14 hours
"canStartEarly": true
}
}
}This set-up defines the rules and restrictions for a truck driver's rest time, driving time, and working time while on tour. The following list provides a brief summary of the settings demonstrated in the previous example:
- Working time: For every six hours of work, the driver must take a break that lasts 30 minutes.
- Driving time: For every four hours of driving, the driver must take a break that lasts 30 minutes.
- Duty rule:
- Minimum off time: The driver must have at least 10 hours of off-duty time between two consecutive working periods.
- Maximum driving time: The driver is only allowed to drive for a maximum of 10 hours within a given working period.
- Maximum working time: The driver is only allowed to work (including driving, loading, unloading, and other activities) for a maximum of 14 hours within a given working period.
Example: Optimize long-haul tours spanning several days
The following sample problem consists of 15 jobs spread all across Germany. The single-vehicle fleet has to complete the tour in the maximum period of eight days, as indicated by the shift start and end values.
Problem
The following section provides the full problem configuration:
Note
In this case, the
shifts.start.timeandshift.end.timevalues limit the maximum time for the tour duration to eight days. The service might leave some jobs unassigned if this time window is too short to complete all jobs in the problem file.
Click to expand/collapse the sample JSON
{
"fleet": {
"types": [
{
"id": "vehicle_1",
"profile": "vehicle",
"costs": {
"fixed": 10.0,
"distance": 1.0,
"time": 5.5
},
"shifts": [
{
"start": {
"time": "2025-05-20T08:00:00Z",
"location": {
"lat": 52.531,
"lng": 13.38461
}
},
"end": {
"time": "2025-05-28T18:00:00Z",
"location": {
"lat": 52.531,
"lng": 13.38461
}
},
"restTimes": {
"working": {
"type": "fixedDuration",
"interval": 21600,
"breakDuration": 1800
},
"driving": {
"type": "fixedDuration",
"interval": 14400,
"breakDuration": 1800
},
"dutyRule": {
"type": "fixedDuration",
"minOffTime": 36000,
"maxDrivingTime": 36000,
"maxWorkingTime": 50400
}
}
}
],
"capacity": [
40
],
"amount": 1
}
],
"profiles": [
{
"type": "car",
"name": "vehicle"
}
]
},
"plan": {
"jobs": [
{
"id": "job_1",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 48.20729,
"lng": 11.56141
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_2",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 53.13704,
"lng": 8.75297
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_3",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 53.55504,
"lng": 10.04741
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_4",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 50.84549,
"lng": 12.90079
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_5",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 49.46332,
"lng": 11.16261
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_6",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 50.98323,
"lng": 7.03591
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_7",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 51.33373,
"lng": 12.39848
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_8",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 52.2927,
"lng": 13.62112
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_9",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 48.77252,
"lng": 9.15553
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_10",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 54.11691,
"lng": 12.2034
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_11",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 50.14514,
"lng": 8.57765
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_12",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 51.97059892253276,
"lng": 7.618889808654785
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_13",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 49.31378,
"lng": 7.073
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_14",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 51.05983,
"lng": 13.74968
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_15",
"tasks": {
"deliveries": [
{
"places": [
{
"location": {
"lat": 48.17069,
"lng": 8.61222
},
"duration": 1200
}
],
"demand": [
1
]
}
]
}
}
]
},
"configuration": {
"experimentalFeatures": [
"restTimes"
]
}
}Solution
The following snippets contains the full solution of the previously mentioned vehicle routing problem, with driving, working, and dutyRule rest times scheduled to comply with the provided constraints:
Click to expand/collapse the sample JSON
{
"statistic": {
"cost": 12.71385188888889,
"distance": 2607783,
"duration": 190924,
"times": {
"driving": 91924,
"serving": 18000,
"waiting": 0,
"stopping": 0,
"break": 81000
}
},
"tours": [
{
"vehicleId": "vehicle_1_1",
"typeId": "vehicle_1",
"stops": [
{
"time": {
"arrival": "2025-05-20T08:00:00Z",
"departure": "2025-05-20T08:00:00Z"
},
"load": [
15
],
"activities": [
{
"jobId": "departure",
"type": "departure",
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": {
"start": "2025-05-20T08:00:00Z",
"end": "2025-05-20T08:00:00Z"
}
}
],
"location": {
"lat": 52.531,
"lng": 13.38461
},
"distance": 0
},
{
"time": {
"arrival": "2025-05-20T08:39:08Z",
"departure": "2025-05-20T08:59:08Z"
},
"load": [
14
],
"activities": [
{
"jobId": "job_8",
"type": "delivery",
"location": {
"lat": 52.2927,
"lng": 13.62112
},
"time": {
"start": "2025-05-20T08:39:08Z",
"end": "2025-05-20T08:59:08Z"
}
}
],
"location": {
"lat": 52.2927,
"lng": 13.62112
},
"distance": 38586
},
{
"time": {
"arrival": "2025-05-20T10:30:26Z",
"departure": "2025-05-20T10:50:26Z"
},
"load": [
13
],
"activities": [
{
"jobId": "job_14",
"type": "delivery",
"location": {
"lat": 51.05983,
"lng": 13.74968
},
"time": {
"start": "2025-05-20T10:30:26Z",
"end": "2025-05-20T10:50:26Z"
}
}
],
"location": {
"lat": 51.05983,
"lng": 13.74968
},
"distance": 198173
},
{
"time": {
"arrival": "2025-05-20T12:04:22Z",
"departure": "2025-05-20T12:24:22Z"
},
"load": [
12
],
"activities": [
{
"jobId": "job_7",
"type": "delivery",
"location": {
"lat": 51.33373,
"lng": 12.39848
},
"time": {
"start": "2025-05-20T12:04:22Z",
"end": "2025-05-20T12:24:22Z"
}
}
],
"location": {
"lat": 51.33373,
"lng": 12.39848
},
"distance": 311718
},
{
"time": {
"arrival": "2025-05-20T13:00:00Z",
"departure": "2025-05-20T13:30:00Z"
},
"load": [
12
],
"activities": [
{
"jobId": "drivingRestTime",
"type": "drivingRestTime",
"time": {
"start": "2025-05-20T13:00:00Z",
"end": "2025-05-20T13:30:00Z"
}
}
]
},
{
"time": {
"arrival": "2025-05-20T13:47:05Z",
"departure": "2025-05-20T14:07:05Z"
},
"load": [
11
],
"activities": [
{
"jobId": "job_4",
"type": "delivery",
"location": {
"lat": 50.84549,
"lng": 12.90079
},
"time": {
"start": "2025-05-20T13:47:05Z",
"end": "2025-05-20T14:07:05Z"
}
}
],
"location": {
"lat": 50.84549,
"lng": 12.90079
},
"distance": 392833
},
{
"time": {
"arrival": "2025-05-20T16:13:23Z",
"departure": "2025-05-20T16:33:23Z"
},
"load": [
10
],
"activities": [
{
"jobId": "job_5",
"type": "delivery",
"location": {
"lat": 49.46332,
"lng": 11.16261
},
"time": {
"start": "2025-05-20T16:13:23Z",
"end": "2025-05-20T16:33:23Z"
}
}
],
"location": {
"lat": 49.46332,
"lng": 11.16261
},
"distance": 626293
},
{
"time": {
"arrival": "2025-05-20T18:03:53Z",
"departure": "2025-05-20T18:23:53Z"
},
"load": [
9
],
"activities": [
{
"jobId": "job_1",
"type": "delivery",
"location": {
"lat": 48.20729,
"lng": 11.56141
},
"time": {
"start": "2025-05-20T18:03:53Z",
"end": "2025-05-20T18:23:53Z"
}
}
],
"location": {
"lat": 48.20729,
"lng": 11.56141
},
"distance": 791650
},
{
"time": {
"arrival": "2025-05-20T18:30:00Z",
"departure": "2025-05-20T19:00:00Z"
},
"load": [
9
],
"activities": [
{
"jobId": "drivingRestTime",
"type": "drivingRestTime",
"time": {
"start": "2025-05-20T18:30:00Z",
"end": "2025-05-20T19:00:00Z"
}
}
]
},
{
"time": {
"arrival": "2025-05-20T20:55:19Z",
"departure": "2025-05-20T21:15:19Z"
},
"load": [
8
],
"activities": [
{
"jobId": "job_9",
"type": "delivery",
"location": {
"lat": 48.77252,
"lng": 9.15553
},
"time": {
"start": "2025-05-20T20:55:19Z",
"end": "2025-05-20T21:15:19Z"
}
}
],
"location": {
"lat": 48.77252,
"lng": 9.15553
},
"distance": 1012947
},
{
"time": {
"arrival": "2025-05-20T21:20:00Z",
"departure": "2025-05-21T07:20:00Z"
},
"load": [
8
],
"activities": [
{
"jobId": "dutyDrivingRestTime",
"type": "dutyDrivingRestTime",
"time": {
"start": "2025-05-20T21:20:00Z",
"end": "2025-05-21T07:20:00Z"
}
}
]
},
{
"time": {
"arrival": "2025-05-21T08:14:41Z",
"departure": "2025-05-21T08:34:41Z"
},
"load": [
7
],
"activities": [
{
"jobId": "job_15",
"type": "delivery",
"location": {
"lat": 48.17069,
"lng": 8.61222
},
"time": {
"start": "2025-05-21T08:14:41Z",
"end": "2025-05-21T08:34:41Z"
}
}
],
"location": {
"lat": 48.17069,
"lng": 8.61222
},
"distance": 1108358
},
{
"time": {
"arrival": "2025-05-21T11:25:03Z",
"departure": "2025-05-21T11:45:03Z"
},
"load": [
6
],
"activities": [
{
"jobId": "job_13",
"type": "delivery",
"location": {
"lat": 49.31378,
"lng": 7.073
},
"time": {
"start": "2025-05-21T11:25:03Z",
"end": "2025-05-21T11:45:03Z"
}
}
],
"location": {
"lat": 49.31378,
"lng": 7.073
},
"distance": 1385790
},
{
"time": {
"arrival": "2025-05-21T12:00:00Z",
"departure": "2025-05-21T12:30:00Z"
},
"load": [
6
],
"activities": [
{
"jobId": "drivingRestTime",
"type": "drivingRestTime",
"time": {
"start": "2025-05-21T12:00:00Z",
"end": "2025-05-21T12:30:00Z"
}
}
]
},
{
"time": {
"arrival": "2025-05-21T13:54:26Z",
"departure": "2025-05-21T14:14:26Z"
},
"load": [
5
],
"activities": [
{
"jobId": "job_11",
"type": "delivery",
"location": {
"lat": 50.14514,
"lng": 8.57765
},
"time": {
"start": "2025-05-21T13:54:26Z",
"end": "2025-05-21T14:14:26Z"
}
}
],
"location": {
"lat": 50.14514,
"lng": 8.57765
},
"distance": 1561522
},
{
"time": {
"arrival": "2025-05-21T15:57:24Z",
"departure": "2025-05-21T16:17:24Z"
},
"load": [
4
],
"activities": [
{
"jobId": "job_6",
"type": "delivery",
"location": {
"lat": 50.98323,
"lng": 7.03591
},
"time": {
"start": "2025-05-21T15:57:24Z",
"end": "2025-05-21T16:17:24Z"
}
}
],
"location": {
"lat": 50.98323,
"lng": 7.03591
},
"distance": 1743220
},
{
"time": {
"arrival": "2025-05-21T17:10:00Z",
"departure": "2025-05-21T17:40:00Z"
},
"load": [
4
],
"activities": [
{
"jobId": "drivingRestTime",
"type": "drivingRestTime",
"time": {
"start": "2025-05-21T17:10:00Z",
"end": "2025-05-21T17:40:00Z"
}
}
]
},
{
"time": {
"arrival": "2025-05-21T18:17:06Z",
"departure": "2025-05-21T18:37:06Z"
},
"load": [
3
],
"activities": [
{
"jobId": "job_12",
"type": "delivery",
"location": {
"lat": 51.97059892253276,
"lng": 7.618889808654785
},
"time": {
"start": "2025-05-21T18:17:06Z",
"end": "2025-05-21T18:37:06Z"
}
}
],
"location": {
"lat": 51.97059892253276,
"lng": 7.618889808654785
},
"distance": 1886871
},
{
"time": {
"arrival": "2025-05-21T20:00:00Z",
"departure": "2025-05-22T06:00:00Z"
},
"load": [
3
],
"activities": [
{
"jobId": "dutyDrivingRestTime",
"type": "dutyDrivingRestTime",
"time": {
"start": "2025-05-21T20:00:00Z",
"end": "2025-05-22T06:00:00Z"
}
}
]
},
{
"time": {
"arrival": "2025-05-22T06:27:01Z",
"departure": "2025-05-22T06:47:01Z"
},
"load": [
2
],
"activities": [
{
"jobId": "job_2",
"type": "delivery",
"location": {
"lat": 53.13704,
"lng": 8.75297
},
"time": {
"start": "2025-05-22T06:27:01Z",
"end": "2025-05-22T06:47:01Z"
}
}
],
"location": {
"lat": 53.13704,
"lng": 8.75297
},
"distance": 2064222
},
{
"time": {
"arrival": "2025-05-22T08:06:39Z",
"departure": "2025-05-22T08:26:39Z"
},
"load": [
1
],
"activities": [
{
"jobId": "job_3",
"type": "delivery",
"location": {
"lat": 53.55504,
"lng": 10.04741
},
"time": {
"start": "2025-05-22T08:06:39Z",
"end": "2025-05-22T08:26:39Z"
}
}
],
"location": {
"lat": 53.55504,
"lng": 10.04741
},
"distance": 2196590
},
{
"time": {
"arrival": "2025-05-22T10:07:23Z",
"departure": "2025-05-22T10:27:23Z"
},
"load": [
0
],
"activities": [
{
"jobId": "job_10",
"type": "delivery",
"location": {
"lat": 54.11691,
"lng": 12.2034
},
"time": {
"start": "2025-05-22T10:07:23Z",
"end": "2025-05-22T10:27:23Z"
}
}
],
"location": {
"lat": 54.11691,
"lng": 12.2034
},
"distance": 2384002
},
{
"time": {
"arrival": "2025-05-22T11:00:00Z",
"departure": "2025-05-22T11:30:00Z"
},
"load": [
0
],
"activities": [
{
"jobId": "drivingRestTime",
"type": "drivingRestTime",
"time": {
"start": "2025-05-22T11:00:00Z",
"end": "2025-05-22T11:30:00Z"
}
}
]
},
{
"time": {
"arrival": "2025-05-22T13:02:04Z",
"departure": "2025-05-22T13:02:04Z"
},
"load": [
0
],
"activities": [
{
"jobId": "arrival",
"type": "arrival",
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": {
"start": "2025-05-22T13:02:04Z",
"end": "2025-05-22T13:02:04Z"
}
}
],
"location": {
"lat": 52.531,
"lng": 13.38461
},
"distance": 2607783
}
],
"statistic": {
"cost": 12.71385188888889,
"distance": 2607783,
"duration": 190924,
"times": {
"driving": 91924,
"serving": 18000,
"waiting": 0,
"stopping": 0,
"break": 81000
}
},
"shiftIndex": 0
}
]
}The following figure provides a visualization of the tour on a map, with each scheduled rest time marked according to its type:
Note
The HERE Tour Planning API does not supply break locations for
restTimesbreaks. As a result, previous maps display each break occurring at the stop immediately preceding it. In reality, it is up to the driver to select a suitable location for the break within the time interval between departure from the stop and the scheduled break start.
Solution breakdown
In this optimization, a three-day tour is conducted, featuring two duty rest periods lasting 10 hours each. These periods occur in the evening and conclude in the morning of the next day, allowing the driver to resume their tour with another working period.
In addition to these rest periods, the service schedules a 30-minute driving rest time every four hours of driving to comply with on-duty break requirements. Due to constraints in the problem, the tour did not meet the conditions for scheduling working rest times; therefore, the optimization does not include any.
To enhance your understanding of how the HERE Tour Planning API scheduled breaks, let's analyze a single workday within the tour, starting from the departure, up to the first duty break, broken down into three segments, divided by driving rest times, as shown in the following figure:
The following table provides a detailed breakdown of the workday, divided into three distinct segments separated by scheduled driving rest breaks. Each segment includes the total time spent driving, time allocated to on-site work (for example, loading or unloading of goods), and the combined total working time:
| Segment | Time Range | Driving Time | Stop Work Time | Total Working Time |
|---|---|---|---|---|
| Segment 1 | 8:00 AM – 1:00 PM | 4 hrs (240 min) | 1 hr (60 min) | 5 hrs (300 min) |
| Segment 2 | 1:30 PM – 6:30 PM | 4 hrs (240 min) | 1 hr (60 min) | 5 hrs (300 min) |
| Segment 3 | 7:00 PM – 9:20 PM | 2 hrs (120 min) | 20 min | 2 hrs 20 min (140 min) |
| Total | 8:00 AM – 9:20 PM | 10 hrs (600 min) | 2 hrs 20 min (140 min) | 12 hrs 20 min (740 min) |
| Breaks (Driving Rest Time) | 1:00–1:30 PM, 6:30–7:00 PM | – | – | – |
Based on the date from the table, consider the following points:
- The service adhered to the
restTimes.driving.intervalsetting by scheduling adrivingrest time after four hours of driving, before the start of Segment 2 and Segment 3. - The service did not schedule
workingbreaks as the interval constraint for thedrivingrest times was always reached first. - The duration of Segment 3 was limited to the total allowed driving time for the working period (10 hours).
- At the end of Segment 3, the service scheduled the first duty break lasting 10 hours and into the following day, as the tour reached the constraint for the maximum allowed driving time per working period.
Example: Rescue an unassigned job with an early duty break
The following example use case demonstrates the impact the canStartEarly option can have on planning long-haul tours with strict time windows for job completion.
The use case focuses on comparing the outcomes of two problems for a multi-day tour. In that tour, a vehicle leaves Berlin and must serve a delivery in Strasbourg during a narrow time window during the next day. Both problems use the same vehicle, duty limits, and jobs. The baseline omits the canStartEarly option. The second problem sets it to true.
The aim of this comparison is to show that allowing an early duty break can make a time-window-constrained job feasible.
Baseline scenario - canStartEarly omitted
The baseline scenario uses the following restTimes configuration, omitting the canStartEarly option:
"restTimes": {
"dutyRule": {
"maxDrivingTime": 39600,
"maxWorkingTime": 50400,
"minOffTime": 36000,
"type": "fixedDuration"
}
}The following section contains the full problem JSON:
Click to expand/collapse the sample JSON
{
"fleet": {
"types": [
{
"profile": "vehicle",
"amount": 1,
"capacity": [
50
],
"costs": {
"time": 0.002,
"distance": 0.001
},
"id": "vehicle_1",
"shifts": [
{
"start": {
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": "2024-06-24T08:00:00+02:00"
},
"end": {
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": "2024-06-28T20:00:00+02:00"
},
"restTimes": {
"dutyRule": {
"maxDrivingTime": 39600,
"maxWorkingTime": 50400,
"minOffTime": 36000,
"type": "fixedDuration"
}
}
}
]
}
],
"profiles": [
{
"name": "vehicle",
"type": "car"
}
]
},
"plan": {
"jobs": [
{
"id": "job_berlin",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": {
"lat": 52.51043282746496,
"lng": 13.371997583570897
},
"times": [
[
"2024-06-24T06:00:00Z",
"2024-06-24T06:30:00Z"
]
]
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_strasbourg",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": {
"lat": 48.5734,
"lng": 7.7521
},
"times": [
[
"2024-06-25T00:30:00Z",
"2024-06-25T01:30:00Z"
]
]
}
],
"demand": [
1
]
}
]
}
}
]
},
"configuration": {
"experimentalFeatures": [
"restTimes"
]
}
}Solution interpretation
In the baseline solution, the optimization algorithm left job_strasbourg unassigned with a TIME_WINDOW_CONSTRAINT reason. Without the canStartEarly option enabled, it could not schedule the 10-hour duty break early enough to serve Strasbourg within its time window while adhering to the duty rule. The following figure shows the tour visualisation:
The following section provides the full problem JSON:
Click to expand/collapse the sample JSON
{
"statistic": {
"cost": 10.097999999999999,
"distance": 7790,
"intraStopDistance": 0,
"duration": 1154,
"times": {
"driving": 854,
"serving": 300,
"waiting": 0,
"break": 0,
"stopping": 0,
"intraStop": 0
}
},
"tours": [
{
"vehicleId": "vehicle_1_1",
"typeId": "vehicle_1",
"shiftIndex": 0,
"stops": [
{
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": {
"arrival": "2024-06-24T06:00:00Z",
"departure": "2024-06-24T06:00:00Z"
},
"distance": 0,
"load": [1],
"activities": [
{
"jobId": "departure",
"type": "departure",
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": {
"arrival": "2024-06-24T06:00:00Z",
"start": "2024-06-24T06:00:00Z",
"end": "2024-06-24T06:00:00Z"
}
}
]
},
{
"location": {
"lat": 52.51043282746496,
"lng": 13.371997583570897
},
"time": {
"arrival": "2024-06-24T06:08:50Z",
"departure": "2024-06-24T06:13:50Z"
},
"distance": 4664,
"load": [0],
"activities": [
{
"jobId": "job_berlin",
"type": "delivery",
"location": {
"lat": 52.51043282746496,
"lng": 13.371997583570897
},
"time": {
"arrival": "2024-06-24T06:08:50Z",
"start": "2024-06-24T06:08:50Z",
"end": "2024-06-24T06:13:50Z"
}
}
]
},
{
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": {
"arrival": "2024-06-24T06:19:14Z",
"departure": "2024-06-24T06:19:14Z"
},
"distance": 7790,
"load": [0],
"activities": [
{
"jobId": "arrival",
"type": "arrival",
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": {
"arrival": "2024-06-24T06:19:14Z",
"start": "2024-06-24T06:19:14Z",
"end": "2024-06-24T06:19:14Z"
}
}
]
}
],
"statistic": {
"cost": 10.097999999999999,
"distance": 7790,
"intraStopDistance": 0,
"duration": 1154,
"times": {
"driving": 854,
"serving": 300,
"waiting": 0,
"break": 0,
"stopping": 0,
"intraStop": 0
}
}
}
],
"unassigned": [
{
"jobId": "job_strasbourg",
"reasons": [
{
"code": "TIME_WINDOW_CONSTRAINT",
"description": "cannot be assigned due to violation of time window"
}
]
}
]
}Scenario with canStartEarly enabled
The following problem has the same configuration as the previous one, with the exception that now, the restTime configuration sets the canStartEarly option to true, as shown in the following snippet:
"restTimes": {
"dutyRule": {
"maxDrivingTime": 39600,
"maxWorkingTime": 50400,
"minOffTime": 36000,
"type": "fixedDuration",
"canStartEarly": true
}
}The following section shows the updated problem JSON:
Click to expand/collapse the sample JSON
{
"fleet": {
"types": [
{
"profile": "vehicle",
"amount": 1,
"capacity": [
50
],
"costs": {
"time": 0.002,
"distance": 0.001
},
"id": "vehicle_1",
"shifts": [
{
"start": {
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": "2024-06-24T08:00:00+02:00"
},
"end": {
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": "2024-06-28T20:00:00+02:00"
},
"restTimes": {
"dutyRule": {
"maxDrivingTime": 39600,
"maxWorkingTime": 50400,
"minOffTime": 36000,
"type": "fixedDuration",
"canStartEarly": true
}
}
}
]
}
],
"profiles": [
{
"name": "vehicle",
"type": "car"
}
]
},
"plan": {
"jobs": [
{
"id": "job_berlin",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": {
"lat": 52.51043282746496,
"lng": 13.371997583570897
},
"times": [
[
"2024-06-24T06:00:00Z",
"2024-06-24T06:30:00Z"
]
]
}
],
"demand": [
1
]
}
]
}
},
{
"id": "job_strasbourg",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": {
"lat": 48.5734,
"lng": 7.7521
},
"times": [
[
"2024-06-25T00:30:00Z",
"2024-06-25T01:30:00Z"
]
]
}
],
"demand": [
1
]
}
]
}
}
]
},
"configuration": {
"experimentalFeatures": [
"restTimes"
]
}
}Solution interpretation
In this case, the optimization algorithm assigns job_strasbourg by scheduling the 10-hour duty break from 14:30 UTC on June 24 to 00:30 UTC on June 25, when the delivery time window opens. The following figure shows the resulting tour:
The following section provides the full solution JSON:
Click to expand/collapse the sample JSON
{
"statistic": {
"cost": 1695.9470000000001,
"distance": 1514981,
"duration": 90483,
"times": {
"break": 36000,
"driving": 50141,
"serving": 600,
"stopping": 0,
"waiting": 3742
},
"costs": {
"distance": 1514.981,
"time": 180.966
},
"intraStopDistance": 0
},
"tours": [
{
"shiftIndex": 0,
"statistic": {
"cost": 1695.9470000000001,
"distance": 1514981,
"duration": 90483,
"times": {
"break": 36000,
"driving": 50141,
"serving": 600,
"stopping": 0,
"waiting": 3742
},
"costs": {
"distance": 1514.981,
"time": 180.966
},
"intraStopDistance": 0
},
"stops": [
{
"activities": [
{
"jobId": "departure",
"type": "departure",
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": {
"arrival": "2024-06-24T06:00:00Z",
"start": "2024-06-24T06:00:00Z",
"end": "2024-06-24T06:20:15Z"
}
}
],
"load": [
2
],
"time": {
"arrival": "2024-06-24T06:00:00Z",
"departure": "2024-06-24T06:20:15Z"
},
"distance": 0,
"location": {
"lat": 52.531,
"lng": 13.38461
}
},
{
"activities": [
{
"jobId": "job_berlin",
"type": "delivery",
"location": {
"lat": 52.51043282746496,
"lng": 13.371997583570897
},
"time": {
"arrival": "2024-06-24T06:30:00Z",
"start": "2024-06-24T06:30:00Z",
"end": "2024-06-24T06:35:00Z"
}
}
],
"load": [
1
],
"time": {
"arrival": "2024-06-24T06:30:00Z",
"departure": "2024-06-24T06:35:00Z"
},
"distance": 4983,
"location": {
"lat": 52.51043282746496,
"lng": 13.371997583570897
}
},
{
"activities": [
{
"jobId": "dutyWorkingRestTime",
"type": "dutyWorkingRestTime",
"location": {
"lat": 48.5734,
"lng": 7.7521
},
"time": {
"start": "2024-06-24T14:30:00Z",
"end": "2024-06-25T00:30:00Z"
}
},
{
"jobId": "job_strasbourg",
"type": "delivery",
"location": {
"lat": 48.5734,
"lng": 7.7521
},
"time": {
"arrival": "2024-06-24T13:27:38Z",
"start": "2024-06-25T00:30:00Z",
"end": "2024-06-25T00:35:00Z"
}
}
],
"load": [
0
],
"time": {
"arrival": "2024-06-24T13:27:38Z",
"departure": "2024-06-25T00:35:00Z"
},
"distance": 760567,
"location": {
"lat": 48.5734,
"lng": 7.7521
}
},
{
"activities": [
{
"jobId": "arrival",
"type": "arrival",
"location": {
"lat": 52.531,
"lng": 13.38461
},
"time": {
"arrival": "2024-06-25T07:28:18Z",
"start": "2024-06-25T07:28:18Z",
"end": "2024-06-25T07:28:18Z"
}
}
],
"load": [
0
],
"time": {
"arrival": "2024-06-25T07:28:18Z",
"departure": "2024-06-25T07:28:18Z"
},
"distance": 1514981,
"location": {
"lat": 52.531,
"lng": 13.38461
}
}
],
"typeId": "vehicle_1",
"vehicleId": "vehicle_1_1"
}
]
}Next steps
For more information about other break or rest-related features, see:
Updated 2 days ago