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


# Worktime

The working time of one calendar: daily hours, working weekdays and per-date exceptions. It's the `Worktime` property of [`CalendarData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/calendar-data.md>). Create it with `new Worktime()` and an object initializer. A `Worktime` with no properties set is the built-in schedule: Monday-Friday, 08:00-12:00 and 13:00-17:00.

This page also documents [`TimeRange`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/worktime.md#timerange>) and [`DayRule`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/worktime.md#dayrule>), the types its properties hold.

## Declaration

```csharp
public sealed class Worktime : IDeepCloneable<Worktime>
```

## Properties

| Property | Type | Default | Description |
|---|---|---|---|
| `Hours` | `List<TimeRange>?` | `null` = 08:00-12:00, 13:00-17:00 | Working hours of every working weekday. |
| `Days` | `bool[]?` | `null` = Monday-Friday | Working weekdays, exactly 7 entries. |
| `Dates` | `SortedDictionary<Moment, DayRule>` | empty | Date exceptions. An entry replaces the weekday rule for that date. |

### Hours

```csharp
public List<TimeRange>? Hours { get; set; }
```

Each [`TimeRange`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/worktime.md#timerange>) is one working interval of the day. All working weekdays share these hours. The order of the ranges doesn't matter. An empty list means no working hours on any weekday, so only `Dates` entries can add working time.

### Days

```csharp
public bool[]? Days { get; set; }
```

Index `0` is Sunday, index `6` is Saturday. `true` marks a working day. A weekday marked `false` has no working time unless a `Dates` entry overrides it.

### Dates

```csharp
public SortedDictionary<Moment, DayRule> Dates { get; set; }
```

Per-date overrides. The [`DayRule`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/worktime.md#dayrule>) for a date wins over `Days` and `Hours`. The key is a [`Moment`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/moment.md>), but only its date counts, so use the date's midnight. Two keys on the same date don't raise an error: the later one replaces the earlier one.

## Methods

### DeepClone

```csharp
public Worktime DeepClone()
```

Returns a copy that shares no list, array or `DayRule` with this one.

`Worktime` doesn't implement `IEquatable<Worktime>`, so `Equals` compares references.

## Validation

`Worktime` is checked when the project data is loaded. Invalid values throw [`InputException`](<https://docs.dhtmlx.com/planning-engine/net/api/core/errors/input-exception.md>) with one of these paths:

| Problem | `Path` |
|---|---|
| `Days` doesn't have exactly 7 entries | `calendars[i].worktime.days` |
| A range in `Hours` is outside 00:00-24:00 | `calendars[i].worktime.hours` |
| A range in a `DayRule.Hours` entry is outside 00:00-24:00 | `calendars[i].worktime.dates[YYYY-MM-DD]` |

A calendar whose worktime adds up to no working time at all is rejected too; see [`CalendarData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/calendar-data.md>).

## TimeRange

One working interval of a day, in minutes from midnight.

```csharp
public record struct TimeRange(ushort Start, ushort End)
```

| Property | Type | Description |
|---|---|---|
| `Start` | `ushort` | Start minute, `0`-`1439`. |
| `End` | `ushort` | End minute, up to `1440` (24:00). When `End <= Start`, the range crosses midnight and belongs to the day it starts on. |

`new TimeRange(9 * 60, 18 * 60)` is 09:00-18:00. `new TimeRange(22 * 60, 6 * 60)` is a night shift from 22:00 to 06:00 the next morning.

## DayRule

The working time of one date in [`Dates`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/worktime.md#dates>). On that date the rule replaces the weekday rule, in both directions: it can turn a working weekday off or a weekend day on.

```csharp
public abstract record DayRule : IDeepCloneable<DayRule>
{
    public sealed record Off : DayRule;
    public sealed record On : DayRule;
    public sealed record Hours(List<TimeRange> Ranges) : DayRule;

    public abstract DayRule DeepClone();
}
```

The set of variants is closed: the constructor is private, so only these three exist.

| Variant | Description |
|---|---|
| `DayRule.Off` | Non-working date, such as a holiday. |
| `DayRule.On` | Working date with the calendar's regular [`Hours`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/worktime.md#hours>). |
| `DayRule.Hours(List<TimeRange> Ranges)` | Working date with these ranges instead of the regular hours. An empty list works like `Off`. |

`DeepClone()` returns a rule with its own copy of `Ranges`. Equality of two `DayRule.Hours` values compares the `Ranges` lists by reference, not by content.

## Example

```csharp
using Plen;

static Moment Day(int year, int month, int day) =>
    Moment.FromYmdHm(year, month, day, 0, 0) ?? throw new ArgumentException("invalid date");

var calendar = new CalendarData
{
    Id = "office",
    Worktime = new Worktime
    {
        // 09:00-18:00, minutes from midnight.
        Hours = [new TimeRange(9 * 60, 18 * 60)],
        // Sunday..Saturday: Monday-Friday.
        Days = [false, true, true, true, true, true, false],
        Dates =
        {
            // Public holiday.
            [Day(2026, 12, 25)] = new DayRule.Off(),
            // Short working Saturday, 09:00-13:00.
            [Day(2026, 12, 19)] = new DayRule.Hours([new TimeRange(9 * 60, 13 * 60)]),
        },
    },
};

Console.WriteLine(calendar);
```

## Related

- [`CalendarData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/calendar-data.md>) - the calendar that holds the working time
- [`Moment`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/moment.md>) - the key of date exceptions
- [Working time and calendars](<https://docs.dhtmlx.com/planning-engine/net/scheduling/working-time-calendars.md>) - hours, weekdays and holidays
