[Canonical page](<https://docs.dhtmlx.com/planning-engine/java/api/data/worktime/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Worktime

The working time of a calendar: daily hours, working weekdays and per-date exceptions. It's set as [`CalendarData.worktime`](<https://docs.dhtmlx.com/planning-engine/java/api/data/calendar-data.md#fields>). Create one with `new Worktime()` and set fields with the fluent `withX` setters. A field left at `null` keeps its built-in default.

## Declaration

```java
public class Worktime extends ValueRecord implements DeepCloneable<Worktime>
```

The engine validates a `Worktime` when the data is passed to [`Project#solve(data, …)`](<https://docs.dhtmlx.com/planning-engine/java/api/project-solve.md>) or [`Engine.schedule`](<https://docs.dhtmlx.com/planning-engine/java/api/engine-schedule.md>). Invalid values throw an unchecked [`InputException`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/input-exception.md>) whose `path` starts with `calendars[i].worktime`.

## Constructors

### Worktime()

```java
public Worktime()
```

Creates a worktime with every field at its default: `hours` and `days` are `null`, `dates` is an empty map.

## Fields

### hours

```java
public Vec<TimeRange> hours = null;
```

The working ranges of a regular working day, as [`TimeRange`](<https://docs.dhtmlx.com/planning-engine/java/api/data/worktime.md#timerange>) values. `null` means 08:00-12:00 and 13:00-17:00. An empty list means no working hours on regular days. Ranges don't have to be sorted.

Throws `InputException` at `calendars[i].worktime.hours` when a range is outside 00:00-24:00.

### days

```java
public boolean[] days = null;
```

Which weekdays are working days, one flag per day. Index 0 is Sunday, index 6 is Saturday. `null` means Monday to Friday.

Throws `InputException` at `calendars[i].worktime.days` when the array doesn't have exactly 7 entries.

### dates

```java
public SortedDict<Moment, DayRule> dates = new SortedDict<Moment, DayRule>();
```

Date exceptions: a [`DayRule`](<https://docs.dhtmlx.com/planning-engine/java/api/data/worktime.md#dayrule>) per date, applied instead of `hours` and `days` on that date. A rule can make a weekend date working or a weekday off. Default: an empty [`SortedDict`](<https://docs.dhtmlx.com/planning-engine/java/api/support/sorted-dict.md>), which you can fill in place with `dates.put(...)`. Must not be `null`.

Only the date part of the [`Moment`](<https://docs.dhtmlx.com/planning-engine/java/api/data/moment.md>) key counts. Use the date's midnight as the key. Two keys on the same date collide: the rule with the later `Moment` replaces the other, without an error.

A worktime whose `hours`, `days` and `dates` give no working time at all throws `InputException` at `calendars[i]` (`calendar has no working time`).

## Methods

### withHours

```java
public Worktime withHours(Vec<TimeRange> value)
public Worktime withHours(java.util.Collection<? extends TimeRange> value)
```

Sets `hours` and returns this instance. The `Collection` overload copies the items into a new `Vec`, so `List.of(...)` works. `null` restores the default hours.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `value` | [`Vec<TimeRange>`](<https://docs.dhtmlx.com/planning-engine/java/api/support/vec.md>) or `Collection<? extends TimeRange>` | The working ranges, or `null` |

**Returns** - this `Worktime`.

### withDays

```java
public Worktime withDays(boolean[] value)
```

Sets `days` and returns this instance. The array is stored as given, not copied. `null` restores Monday to Friday.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `value` | `boolean[]` | Seven flags, Sunday first, or `null` |

**Returns** - this `Worktime`.

### withDates

```java
public Worktime withDates(SortedDict<Moment, DayRule> value)
```

Sets `dates` and returns this instance. The map is stored as given, not copied.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `value` | [`SortedDict<Moment, DayRule>`](<https://docs.dhtmlx.com/planning-engine/java/api/support/sorted-dict.md>) | The date exceptions; not `null` |

**Returns** - this `Worktime`.

### deepClone

```java
public Worktime deepClone()
```

Returns a copy that shares no list, array or map with this instance. Each `TimeRange` and `DayRule` is copied too.

**Returns** - a new `Worktime` equal to this one.

### copy

```java
public Worktime copy()
```

Returns a shallow copy. The copy shares the `hours` list, the `days` array and the `dates` map with this instance.

**Returns** - a new `Worktime` with the same field references.

### equals, hashCode, toString

```java
public boolean equals(Object other)
public int hashCode()
public String toString()
```

Inherited from [`ValueRecord`](<https://docs.dhtmlx.com/planning-engine/java/api/support/value-record.md>). Two `Worktime` values are equal when `hours`, `days` (by content) and `dates` are equal.

## TimeRange

A working range within one day, in minutes since midnight.

```java
public class TimeRange extends ValueRecord
```

| Member | Type | Description |
|---|---|---|
| `TimeRange(int start, int end)` | constructor | Creates a range from `start` to `end` |
| `start` | `int` | Start, in minutes since midnight. Must be below 1440 |
| `end` | `int` | End, in minutes since midnight, up to 1440 (24:00) |
| `copy()` | `TimeRange` | Returns a copy with the same values |

A range with `end` less than or equal to `start` crosses midnight and belongs to the day it starts on: `new TimeRange(22 * 60, 6 * 60)` is 22:00 to 06:00 the next morning. Equal `start` and `end` give a 24-hour range.

## DayRule

The rule for one date in [`dates`](<https://docs.dhtmlx.com/planning-engine/java/api/data/worktime.md#dates>). `DayRule` is an abstract class with a closed set of nested subclasses. Match on them with `instanceof` or a `switch` pattern.

```java
public abstract class DayRule extends ValueRecord implements DeepCloneable<DayRule>
```

| Subclass | Constructor | Effect on the date |
|---|---|---|
| `DayRule.Off` | `new DayRule.Off()` | Non-working |
| `DayRule.On` | `new DayRule.On()` | Working, with the worktime's `hours` |
| `DayRule.Hours` | `new DayRule.Hours(Vec<TimeRange> ranges)`, `new DayRule.Hours(Collection<? extends TimeRange> ranges)` | Working, with these ranges instead of `hours`; field `ranges` (`Vec<TimeRange>`) |

`DayRule.Hours` ranges follow the same rules as [`TimeRange`](<https://docs.dhtmlx.com/planning-engine/java/api/data/worktime.md#timerange>). A range outside 00:00-24:00 throws `InputException` at `calendars[i].worktime.dates[YYYY-MM-DD]`.

| Method | Returns | Description |
|---|---|---|
| `deepClone()` | `DayRule` | A copy that shares no list with this rule. `Off` and `On` hold no data and return themselves |
| `copy()` | the subclass | A shallow copy |

## Example

```java
import org.dhtmlx.plen.*;
import java.util.List;

public class ShiftCalendar {
    public static void main(String[] args) throws Exception {
        Moment holiday = Moment.fromYmdHm(2026, 8, 14, 0, 0);  // Friday
        Moment saturday = Moment.fromYmdHm(2026, 8, 15, 0, 0);
        Moment start = Moment.fromYmdHm(2026, 8, 13, 7, 0);    // Thursday

        Worktime worktime = new Worktime()
            .withHours(List.of(new TimeRange(7 * 60, 11 * 60), new TimeRange(12 * 60, 16 * 60)))
            .withDays(new boolean[] {false, true, true, true, true, true, false}); // Sun..Sat
        worktime.dates.put(holiday, new DayRule.Off());
        worktime.dates.put(saturday, new DayRule.Hours(List.of(new TimeRange(8 * 60, 12 * 60))));

        ProjectData data = new ProjectData()
            .withConfig(new SchedulingConfig().withDurationUnit(TimeUnit.HOUR))
            .withCalendars(List.of(new CalendarData().withId(Id.str("global")).withWorktime(worktime)))
            .withTasks(List.of(new TaskData(Id.str("pour")).withStartDate(start).withDuration(14.0)));

        ScheduleResult result = Engine.schedule(data, new SolveOptions().withIncludeUnchanged(true));
        for (Mutation update : result.updates) {
            System.out.println(update.id + ": " + update.startDate + " -> " + update.endDate);
        }
    }
}
```

Output:

```text
pour: 2026-08-13 07:00 -> 2026-08-17 09:00
```

The 14 hours are Thursday (8 h), Saturday (4 h) and Monday 07:00-09:00 (2 h). Friday is off. For how tasks and resources pick a calendar, see [Working time and calendars](<https://docs.dhtmlx.com/planning-engine/java/scheduling/working-time-calendars.md>).

## Related

- [`CalendarData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/calendar-data.md>) - the calendar that holds it
- [`Moment`](<https://docs.dhtmlx.com/planning-engine/java/api/data/moment.md>) - dates of exceptions
- [Defining calendars](<https://docs.dhtmlx.com/planning-engine/java/scheduling/working-time-calendars.md#defining-calendars>) - hours, weekdays and exceptions
- [Date exception keys](<https://docs.dhtmlx.com/planning-engine/java/scheduling/working-time-calendars.md#date-exception-keys>) - how date exceptions are keyed
