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


# TaskUpdate

An edit to one existing task of a live project. It goes in the `update` list of [`SchedulingChanges.tasks`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/scheduling-changes.md#tasks>), which [`Project#apply`](<https://docs.dhtmlx.com/planning-engine/java/api/project-apply.md>) and [`Project#preview`](<https://docs.dhtmlx.com/planning-engine/java/api/project-preview.md>) take. Create it with `new TaskUpdate(id)` and chain a `withX(...)` setter for each field to change.

## Declaration

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

## Constructors

### TaskUpdate(Id)

```java
public TaskUpdate(Id id)
```

Creates an update for the task with the given id. Every other field is [`Patch.missing()`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/patch.md#missing>), so the update changes nothing until a field is set.

| Name | Type | Description |
|---|---|---|
| `id` | [`Id`](<https://docs.dhtmlx.com/planning-engine/java/api/data/id.md>) | Id of the task to edit. |

## Fields

Every field except `id` is a [`Patch<T>`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/patch.md>). `Patch.missing()` (the default) keeps the stored value, `Patch.of(value)` sets it, and `Patch.nullValue()` clears it. The **On `nullValue()`** column shows what a cleared field holds afterwards. For the meaning of each value, see the field of the same name on [`TaskData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/task-data.md#fields>).

Each field has a fluent setter of the same name, `withX(Patch<T> value)`, that returns this update.

| Field | Type | On `nullValue()` | Description |
|---|---|---|---|
| `id` | [`Id`](<https://docs.dhtmlx.com/planning-engine/java/api/data/id.md>) | required | Id of the task to edit. |
| `parent` | `Patch<Id>` | root level | Moves the task under another parent. A value equal to [`SchedulingConfig.rootId`](<https://docs.dhtmlx.com/planning-engine/java/api/data/scheduling-config.md#rootid>) is read as `nullValue()`. |
| `startDate` | `Patch<`[`Moment`](<https://docs.dhtmlx.com/planning-engine/java/api/data/moment.md>)`>` | `null` | New start, for example after a drag. |
| `endDate` | `Patch<Moment>` | `null` | New end. |
| `duration` | `Patch<Double>` | `null` | New working time in the task's `durationUnit`, for example after a resize. |
| `constraintType` | `Patch<`[`ConstraintType`](<https://docs.dhtmlx.com/planning-engine/java/api/data/task-data.md#constrainttype>)`>` | `null` | New scheduling constraint. |
| `constraintDate` | `Patch<Moment>` | `null` | New constraint date. |
| `autoScheduling` | `Patch<Boolean>` | `true` | `false` makes the task fixed. |
| `unscheduled` | `Patch<Boolean>` | `false` | `true` takes the task out of the plan. |
| `progress` | `Patch<Double>` | `0.0` | New completed fraction. |
| `calendarId` | `Patch<Id>` | `null` | New working calendar. `Patch.of(null)` also clears it. |
| `priority` | `Patch<Integer>` | `500` | New leveling priority, 0..1000. |
| `levelingDelay` | `Patch<Double>` | `0.0` | New leveling delay, as elapsed time in the task's `durationUnit`. |
| `pauses` | `Patch<Vec<`[`Pause`](<https://docs.dhtmlx.com/planning-engine/java/api/data/pause.md>)`>>` | empty | Replaces the whole pause list. The task gets a deep copy of the list. |

`Patch.of(null)` holds a `null` value, which isn't the same as `Patch.nullValue()`. On `parent`, `pauses`, `autoScheduling`, `unscheduled`, `progress`, `priority` and `levelingDelay` it throws `NullPointerException` when the update is applied. Use `Patch.nullValue()` to clear these fields.

## Dates after an update

An update starts from the task's current scheduled start, end and duration. On a leaf task ([`TaskType.TASK`](<https://docs.dhtmlx.com/planning-engine/java/api/data/task-data.md#tasktype>)), the fields set in the update decide which of the three is kept and which is derived again:

| Set in the update | Kept | Derived again |
|---|---|---|
| `startDate`, no `endDate` | start, duration | end |
| `endDate` only | end, start | duration |
| `duration`, no `endDate` | start, duration | end |
| `startDate` + `endDate`, no `duration` | start, end | duration |
| `calendarId`, or `parent` under [`CalendarMode.TASK_INHERITED`](<https://docs.dhtmlx.com/planning-engine/java/api/data/calendar-mode.md>), no date field | start, duration | end |
| `pauses` or `levelingDelay`, no date field | start, duration | end |

- A `levelingDelay` update with neither `startDate` nor `endDate` also moves the stored dates by the change in delay (elapsed time) and snaps them onto working time.
- When a task works on several calendars in a project with [`scheduleFromEnd`](<https://docs.dhtmlx.com/planning-engine/java/api/data/scheduling-config.md#schedulefromend>) on, a `pauses` or `levelingDelay` update without dates keeps the end and derives the start instead.
- Under `CalendarMode.TASK_INHERITED`, a `calendarId` or `parent` update also re-derives the end of each descendant leaf task that has no `calendarId` of its own. Its start and duration stay.
- An explicit start on non-working time stays unsnapped when the task has no predecessor.

To write a result entry back as an update, see [`Mutation`](<https://docs.dhtmlx.com/planning-engine/java/api/results/mutation.md>).

## Methods

### deepClone

```java
public TaskUpdate deepClone()
```

Returns a copy that shares no list with this update, including the `pauses` value.

**Returns**: a new `TaskUpdate` with the same values.

### copy

```java
public TaskUpdate copy()
```

Returns a shallow copy. The `pauses` list, if set, is shared with this update.

**Returns**: a new `TaskUpdate` with the same field values.

`equals`, `hashCode` and `toString` come from [`ValueRecord`](<https://docs.dhtmlx.com/planning-engine/java/api/support/value-record.md>) and work over the public fields, e.g. `TaskUpdate{id=a, parent=Patch{kind=MISSING}, …}`.

## Errors

An update is rejected as a single operation, at path `tasks.update[i]`. [`Project#apply`](<https://docs.dhtmlx.com/planning-engine/java/api/project-apply.md>) and [`Project#preview`](<https://docs.dhtmlx.com/planning-engine/java/api/project-preview.md>) describe how a rejection is reported.

| Message | When it occurs |
|---|---|
| `unknown task id` | No task has `id`. |
| a validation message | The edited task breaks a [`TaskData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/task-data.md>) rule or a [`ProjectData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/project-data.md>) rule, for example an unknown `calendarId` or `parent`. |

## Example

Move a task to a new start and make it one day longer:

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

public class MoveTask {
  public static void main(String[] args) throws Exception {
    Moment monday = Moment.fromYmdHm(2026, 4, 6, 8, 0);
    Moment wednesday = Moment.fromYmdHm(2026, 4, 8, 8, 0);

    ProjectData data = new ProjectData()
        .withTasks(List.of(new TaskData(Id.str("design")).withStartDate(monday).withDuration(2.0)));

    Project project = new Project();
    project.solve(data, new SolveOptions());

    SchedulingChanges changes = new SchedulingChanges();
    changes.tasks.update.add(new TaskUpdate(Id.str("design"))
        .withStartDate(Patch.of(wednesday))
        .withDuration(Patch.of(3.0)));

    ApplyReport report = project.apply(changes);
    if (report.rejected.isEmpty()) {
      ScheduleResult result = project.solve(null, new SolveOptions());
      for (Mutation task : result.updates) {
        System.out.println(task.id + ": " + task.startDate + " - " + task.endDate);
      }
    }
  }
}
```

## Related

- [`TaskData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/task-data.md>) - the stored task and the meaning of each field
- [`Patch<T>`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/patch.md>) - the three-state type of every editable field
- [`Mutation`](<https://docs.dhtmlx.com/planning-engine/java/api/results/mutation.md>) - result entries to write back as updates
- [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/scheduling-changes.md#tasks>) - the change set that carries the update
- [Data Updates](<https://docs.dhtmlx.com/planning-engine/java/live-projects/editing-a-project.md#which-dates-a-task-update-keeps>) - which dates a task update keeps
