Overnight stay

Illustration on a dark street grid: a truck follows a lime route from a start pin to a hotel with a moon sign, and the route goes on from the hotel to a second pin

This feature guide covers overnight stays in JOpt.TourOptimizer: a resource ends a working day at a stay node, such as a hotel, and starts the next working day from there instead of from home. It is for developers who plan multi-day routes with JOpt in Java. It assumes that you know nodes, resources and working hours from Basic elements.

Timeline of the resource John on two days: on Monday he starts at home, visits two nodes and a CapturedNode and ends the day at a hotel; on Tuesday he starts at the hotel and drives home after three nodes

Figure: A resource stays at a hotel instead of returning home. The next day starts from the overnight position.

Table of contents

What it does

The optimizer decides where a resource stays, on which nights, and for how long. It makes these decisions in the optimization run itself, together with the routing, the scheduling and all other constraints.

Overnight stays have two sides:

Node side: stay nodes. A node can be marked as eligible for overnight positioning. The resource may then end its working day at this node and continue from that position the next morning. Not every node should be a stay node. Typical candidates are hotels, depots, service bases, partner hubs and safe parking areas.

Resource side: policies and restrictions. The resource controls whether, when and how often it may stay out. Three mechanisms work together:

  1. a per-day allowance on each WorkingHours;
  2. a distance and time threshold that decides when staying out is justified;
  3. limits on consecutive nights out and a mandatory recovery time at home.

What changes in the plan

Without overnight stays, a Europe-wide tour would violate working time limits, force unrealistic scheduling, or require the resource to "teleport" home each evening. The optimizer either produces an infeasible result or drops nodes that cannot be reached in a single day.

With overnight stays enabled:

  • the optimizer splits the tour across several days;
  • a day can end at a stay node (a hotel, depot or service base);
  • the next day starts from the overnight position, not from home;
  • working hours and opening hours are respected across the days;
  • the stay-out policy prevents unnecessary hotel stays for short tours;
  • consecutive-night limits and recovery rules are enforced automatically.

When to use it

Use overnight stays when a resource cannot cover its work in day trips from home, for example:

  • field service across large regions;
  • multi-day deliveries;
  • seasonal campaigns;
  • long-haul tours.

A resource that works 30 minutes from home should return home and not check into a hotel. The stay-out policy keeps such local tours at home.

How to use it

Stay nodes

A node becomes a stay node by calling setIsStayNode(true):

TimeWindowGeoNode hotel = new TimeWindowGeoNode(
    "Hotel Innsbruck", 47.2654, 11.3927, openingHours, Duration.ofHours(1), 1);
hotel.setIsStayNode(true);

Stay nodes are regular nodes in every other respect: they have opening hours, visit durations, qualifications and constraints. The stay flag only adds the eligibility for overnight positioning.

A node can be both a stay node and an optional node. Use this for a hotel node that the optimizer should visit only if staying out is beneficial: if the tour does not justify an overnight stay, the optional hotel node is skipped.

The optimizer uses the stay nodes as candidate overnight positions and selects the one that produces the best multi-day plan. If no stay node is reachable or beneficial, the resource returns home as usual.

Per-day control via WorkingHours

By default, a WorkingHours is not available for an overnight stay. This opt-in default is intentional: an overnight stay is an operational decision that you enable consciously, so that no working day inherits it by accident.

To allow staying out on a day, call setIsAvailableForStay(true) on its WorkingHours:

// Enable overnight stay for all working days
workingHours.forEach(w -> w.setIsAvailableForStay(true));

// But forbid it on Friday (resource must return home for the weekend)
workingHoursFriday.setIsAvailableForStay(false);

With per-day control you can model:

  • stays allowed on weekdays and a mandatory return for the weekend;
  • days blocked for maintenance, rest or depot duties;
  • seasonal patterns that allow stays only during campaign periods;
  • individual agreements per resource (some drivers stay out, some do not).

The setting belongs to each WorkingHours, not to the resource. A resource with six working days can have stays enabled on four of them and disabled on two, without any custom constraint logic.

Stay-out policy: distance and time thresholds

Not every tour justifies an overnight stay. The stay-out policy sets minimum thresholds for the connection back to the home location. The values below are samples:

Quantity<Length> minDistance = Quantities.getQuantity(100, KILO(METRE));
Duration minTime = Duration.ofHours(2);

resource.setStayOutPolicy(minDistance, minTime);
resource.setStayOutPolicyReturnDistanceActive(true);

The policy says: allow overnight stays only if the resource's current position is at least 100 km away from home or the driving time back to the home location would be at least 2 hours. In other words, if the resource needs more than 2 hours of driving to get home, staying out is permitted. The ReturnDistanceActive flag tells the optimizer to consider the return distance/time as part of the stay-out decision.

The thresholds keep local tours free of hotel costs and allow stays where a tour needs several days.

Consecutive nights and recovery

For employee wellbeing and regulatory compliance, a resource can limit how many nights in a row it stays out and how long the recovery period at home must be:

int totalStaysOut = -1;   // unlimited total nights out (-1 = no limit)
int staysOutInRow = 4;    // after 3 consecutive nights out, return is required
int minRecoverHours = 2;  // recovery at home must last at least 2 nights

resource.setStaysOut(totalStaysOut, staysOutInRow, minRecoverHours);

The three parameters:

Total stays out. The maximum number of overnight stays across the entire planning horizon. Set to -1 for unlimited. Use a positive value to cap the total hotel budget.

Stays out in a row. The maximum number of consecutive nights out before the resource must return home. In the example, staysOutInRow = 4 means after 3 consecutive nights away, the 4th night must be at home. This models weekly return policies common in field service and long-haul transport.

Minimum recovery hours. The minimum duration the resource must spend at home before being allowed to stay out again. In the example, minRecoverHours = 2 requires at least 2 consecutive nights at home before the next multi-day tour can begin. This models mandatory rest periods required by labor regulations or company policy.

These restrictions work together with the per-day setting. A day with setIsAvailableForStay(false) forces a return home, whatever the consecutive-night counter says. Use WorkingHours for calendar rules and setStaysOut for sequence rules.

The example: a multi-day tour across Europe

The example OvernightStayExample.java models a multi-day field service tour across Europe. The resource Jack starts from his home location near Aachen and visits nodes in Zagreb, Venice (optional), Innsbruck, Vienna and Stuttgart. The sample data has six working days, May 6 to 11.

The configuration:

  • all six WorkingHours are enabled for overnight stays;
  • stay-out policy: at least 100 km distance or 4 hours of travel time from home;
  • consecutive nights: unlimited in total, at most 3 in a row, 2 nights of recovery;
  • all nodes are stay nodes;
  • Venice is both optional and a stay node.

The optimizer produces a multi-day plan where Jack visits nodes in geographic order, stays at hotel locations between days, and returns home after the consecutive-night limit is reached.

The code below is a simplified form of the resource setup, not a copy of the example: it uses a time threshold of 2 hours where the example uses 4 hours:

// Multi-day working hours
List<IWorkingHours> workingHours = new ArrayList<>();
for (int day = 6; day <= 11; day++) {
    workingHours.add(new WorkingHours(
        ZonedDateTime.of(2020, MAY.getValue(), day, 8, 0, 0, 0, ZoneId.of("Europe/Berlin")),
        ZonedDateTime.of(2020, MAY.getValue(), day, 20, 0, 0, 0, ZoneId.of("Europe/Berlin"))));
}

// Enable overnight stays for all days
workingHours.forEach(w -> w.setIsAvailableForStay(true));

// Create resource with policies
CapacityResource jack = new CapacityResource(
    "Jack", 50.775346, 6.083887, maxWorkingTime, maxDistance, workingHours);

// Stay-out policy
jack.setStayOutPolicy(
    Quantities.getQuantity(100, KILO(METRE)),
    Duration.ofHours(2));
jack.setStayOutPolicyReturnDistanceActive(true);

// Consecutive-night restrictions
jack.setStaysOut(-1, 4, 2);

Modeling guidance

Mark realistic overnight points as stay nodes. Do not mark every customer node as a stay node. Typical candidates are hotels, depots, service bases, partner hubs and safe parking areas. Unrealistic stay nodes produce plans that look good on paper but cannot be carried out.

Use policy thresholds to avoid unnecessary stays. Calibrate the minimum distance and time thresholds on your real operations. If your drivers typically return home for tours under 150 km, set the threshold accordingly.

Enforce consecutive-night limits for compliance. Labor regulations in many industries limit how many nights a worker can spend away from home. Model these rules with setStaysOut instead of checking compliance after the run.

Control stay availability per day. Use setIsAvailableForStay(false) on specific working hours to enforce calendar rules for the return home (weekends, rest days, maintenance days). This is simpler and more explicit than modeling the same behavior with time window constraints.

Give stay nodes realistic time windows. Stay nodes still use opening hours. If their time windows are too strict, the optimizer may not be able to use them as overnight positions. Hotels and depots typically have wide windows.

Consider downstream systems. Multi-day routing needs support in route execution apps, reporting and dispatch communication. Make sure that your workflow handles day boundaries, overnight locations and per-day route segments.

Authors

DNA Evolutions GmbH


Added: 2026-03-29 (JOpt core 7.5.3-j17) | Last updated: 2026-10-19