---
title: Scheduling internals
description: How Pyn turns a trigger and a reference date into enrollments and send times, including trigger windows, reference date adjustment, recurrence years, cadence, minimums and time zones.
sidebar:
  order: 3
area: flows
feature: automations
appPath: /flows/home
lastVerified: 2026-10-22
version: "2026-10-16"
audience: admin
related:
  - flows/automations/trigger-catalogue
  - flows/automations/configure-a-date-trigger
  - flows/automations/prevent-repeat-enrollments
  - flows/steps
intercom:
  - id: "8279902"
    title: "Editing Enrollment Rule: Timing"
    url: https://intercom.help/pyn/en/articles/8279902-editing-enrollment-rule-timing
    note: Pyn 1 article
---

For the person who wants to know exactly when something will fire. The trigger and step pages describe the same rules from the task side.

## When triggers are evaluated

| Trigger kind | Evaluated | Reference date |
| --- | --- | --- |
| Date, Employee Property (date, text, yes/no) | On every HRIS or Employee File refresh for the employees that changed, and on a background pass for everyone roughly every six hours (at 7 minutes past 00:00, 06:00, 12:00 and 18:00 UTC) | The matched date, or for text and yes/no the current day in the employee's time zone |
| Recurring | Hourly at 14 minutes past | The run's date |
| Group Change, Will be joining | The moment a group membership is added or removed | The current day |
| Buddy Assigned, Promoted to Manager, Change of Manager, Change of Location, Connected to Slack | The moment the relation is set | The current day |
| Form Submission | The moment a submission completes | The current day in the submitter's time zone |

Relation and group triggers are suppressed until the first HRIS load has finished, and relation triggers on messaging sources until the first messaging load has finished. When the workspace becomes ready, each published relation trigger is stamped with a "from" date of the following day and ignores changes before it.

## Date triggers

A date trigger has five settings. The editor exposes two (**This flow starts** and the recurrence); templates can set the rest.

| Setting | Default | Effect |
| --- | --- | --- |
| Trigger date adjustment (**This flow starts**) | 0 days (**on the day of**) | Shifts the day the trigger fires relative to the reference date. Never moves the reference date. |
| Recurrence (year modulo) | None (**just once**) | Which anniversary years fire. |
| Excluded years | None | Exact years that never fire; **every year after the first** excludes year 1. |
| Trigger date window | On-edge | On-edge fires on exactly one day, the adjusted date. Within-window fires on every day between the reference date and the adjusted date, inclusive. **Pre-onboarding** uses within-window with a one-week adjustment, so it catches records that arrive late. |
| Reference date adjustment | 0 days | Shifts the reference date itself away from the employee's date. The **90-day check-in** template sets 90 days, so its steps schedule around day 90. |

The order of operations: reference date = employee's date + reference date adjustment; fire day = reference date + trigger date adjustment (or the window ending there); recurrence decides which years count. Time of day plays no part; a matching day fires whether the check runs at 00:00 or 23:59.

### Recurrence years

With years counted from the employee's date (year 0 is the date itself):

| Option | Years |
| --- | --- |
| just once | Only the original date, in its own year |
| every year | 1, 2, 3, ... |
| every year after the first | 2, 3, 4, ... |
| every other year | 1, 3, 5, ... |
| every 2 years | 2, 4, 6, ... |
| every 5 years | 5, 10, 15, ... |
| every 10 years | 10, 20, 30, ... |

Year 0 never fires for a recurring option, which is why an anniversary flow and a start-date flow never coincide. A recurring trigger looks at the anniversary in the current year and one year either side, so adjustments on a recurring trigger must total less than a year. Birthdays are stored as month and day, with no year to count from, so they offer **every year** only.

### Leap days

A 29 February date fires on 28 February in non-leap years and on 29 February in leap years, for every recurrence option.

## Re-enrollment timeouts

Each trigger carries **Prevent repeat enrollments**. When a trigger fires for someone it has fired for before, Pyn skips them unless the timeout has passed since the last time.

| Rule | Detail |
| --- | --- |
| Always reenroll | Every firing enrols. Default for Form Submission and Custom trigger. |
| Never reenroll | One enrollment per person, ever, including rehires. Default for the onboarding triggers, text and yes/no properties and No trigger. |
| Duration | 1 hour, 1 to 7 days, 1, 3, 6 or 12 months. |
| One-day minimum | Date and property triggers are re-checked several times a day, so Always reenroll and 1 hour are raised to 1 day for them and hidden from the list. |
| Manual enrollments | Ignore the trigger's timeout. The same person cannot be manually enrolled in the same automation twice within five minutes unless **Flag as Test** is on. |

The "has fired before" record is written even when the automation is in Manual or Inactive mode and nobody is enrolled. Switching such an automation to Automated later does not enrol the people whose dates passed while it was switched off.

## From enrollment to send time

1. The enrollment is created with its reference date (a calendar date, no time or zone).
2. For each **Enabled** step in the version, an enrollment step is created: as draft in a paused enrollment, otherwise scheduled. A **Disabled** step is skipped. A step with **Skip if overdue at enrollment** whose send time is already past is created complete.
3. Send time = reference date + the step's offset, at the step's hour and minute, in the step's time zone: an explicit zone, or **Recipient Timezone** (the recipient's profile time zone, falling back to the workspace zone). For a Slack channel, the channel has no zone and the workspace zone applies.
4. If the resulting day is not one of the step's **Deliver on** weekdays, the skipped-day rule applies: deliver anyway, move to the previous delivery day, or move to the next delivery day.
5. A send time already in the past is sent on the next delivery pass.
6. When a delivery is sent, its reminders and escalations are created as children of the delivery and scheduled from the send time.

Updating an enrollment to a new version repeats step 2 for new steps, recalculates steps still in draft or scheduled, and removes steps the version no longer has.

## Related

- [Trigger catalogue](https://support.pynhq.com/flows/automations/trigger-catalogue/) for each trigger's defaults.
- [Configure a date trigger](https://support.pynhq.com/flows/automations/configure-a-date-trigger/) for the two settings you edit.
- [Prevent repeat enrollments](https://support.pynhq.com/flows/automations/prevent-repeat-enrollments/) for the timeout.
- [Steps and messages](https://support.pynhq.com/flows/steps/) for Deliver on, skipped days and time zones on a step.

## Related Intercom articles

- [Editing Enrollment Rule: Timing](https://intercom.help/pyn/en/articles/8279902-editing-enrollment-rule-timing) — Pyn 1 article
