Skip to content

On-Time Events

Schedule Python functions to execute automatically based on time, repeating intervals, or specific datetimes — directly from the IDE's ⏱️ Timers panel.

Overview

On-time events let you run Python code on a schedule, independently of any Excel user action. Unlike regular Excel events (which fire when a user interacts with a workbook), on-time events are timer-based and are managed entirely by XPyCode.

Key characteristics:

  • Three scheduling types — daily time, repeating interval, or one-shot datetime
  • Per-workbook configuration — each workbook stores its own set of on-time events
  • Persistent across sessions — the schedule is saved in the workbook and restored automatically on reconnect
  • Managed from the IDE — use the ⏱️ Timers panel to add, edit, and delete events without touching code

Comparison with Excel Events

Regular Excel events (see Events Guide) fire in response to user actions such as cell edits or worksheet activation. On-time events fire based on the clock, regardless of what the user is doing.


Scheduling Types

XPyCode supports three scheduling types, each suited to a different use case.

Time — Daily Recurring

type="time" fires every day at a specific HH:MM time. You can optionally restrict it to certain weekdays.

Field Example Description
value "14:30" Time of day in 24-hour format (HH:MM)
time_type "utc" or "local" Whether the time is interpreted as UTC or local clock
days ["Monday", "Friday"] Optional weekday filter — empty array means every day

Example: Run at 14:30 every Monday and Friday

{
    "type": "time",
    "value": "14:30",
    "time_type": "local",
    "days": ["Monday", "Friday"],
    "module_name": "reports",
    "function_name": "generate_weekly_summary"
}

Delay — Repeating Interval

type="delay" fires repeatedly every N seconds. The interval restarts each time the handler completes.

Field Example Description
value 60 Interval in seconds between each execution
time_type "utc" or "local" Timezone context for the trigger timestamp

Example: Refresh data every 60 seconds

{
    "type": "delay",
    "value": 60,
    "time_type": "local",
    "days": [],
    "module_name": "data_feed",
    "function_name": "refresh_prices"
}

DateTime — One-Shot

type="datetime" fires once at a specific date and time, then does not repeat.

Field Example Description
value "2026-03-15T14:30:00" ISO 8601 datetime string
time_type "utc" or "local" Whether the datetime is UTC or local

Example: Send a report on 15 March 2026 at 09:00

{
    "type": "datetime",
    "value": "2026-03-15T09:00:00",
    "time_type": "local",
    "days": [],
    "module_name": "reports",
    "function_name": "send_scheduled_report"
}

DateTime Events

A datetime event whose scheduled time has already passed when the workbook connects will not fire. Ensure the configured datetime is in the future.


Time Type

The time_type field controls how the scheduled value is interpreted:

Value Behaviour
"utc" Fires at the same absolute moment worldwide, regardless of the local system clock
"local" Fires when the local system clock shows the specified time

Use "utc" for server-side or cross-timezone consistency. Use "local" when the schedule should follow the user's local timezone.


Timer Manager Panel

The ⏱️ Timers dock panel in the IDE lets you manage all on-time events for a workbook without editing code or configuration files directly.

Opening the Panel

  1. In the IDE, locate the right-side dock area
  2. Click the ⏱️ Timers tab

Panel Layout

  • Workbook dropdown — select the workbook whose events you want to manage
  • Events table — lists all configured on-time events with columns:

    Column Description
    Type time, delay, or datetime
    Value The scheduled value (e.g. "14:30", 60, "2026-03-15T09:00:00")
    Time Type utc or local
    Days Weekday filter (for type="time" only)
    Module Python module containing the handler
    Function Handler function name
  • Add / Edit / Delete buttons — manage events below the table

Adding an Event

  1. Select the target workbook from the dropdown
  2. Click Add
  3. Fill in the dialog form:
    • Type — choose time, delay, or datetime
    • Value — enter HH:MM, an integer (seconds), or an ISO datetime
    • Time Type — choose utc or local
    • Days — tick weekdays (only available for type="time")
    • Module — the Python module name containing your handler
    • Function — the handler function name
  4. Click OK to save

Editing an Event

  • Select the row in the table and click Edit, or
  • Double-click the row directly

The dialog opens pre-filled with the current values. Update fields as needed and click OK.

Deleting an Event

  1. Select the row in the table
  2. Click Delete

The event is removed immediately and will no longer fire.


Writing a Handler

On-time event handlers are regular Python functions that accept a single event argument (a dict).

Function Signature

def my_handler(event: dict) -> None:
    ...

Event Dictionary Keys

Key Type Description
event_id str UUID of the on-time event that fired
event_type str "time", "delay", or "datetime"
trigger_time str ISO 8601 timestamp when the event fired
scheduled_value str \| int The configured value (e.g. "14:30", 60)

Example Handler

import xpycode

def on_timer_refresh(event):
    """Handler for periodic data refresh.

    Args:
        event: Dict with keys:
            - event_id: The on-time event UUID
            - event_type: "time", "delay", or "datetime"
            - trigger_time: ISO timestamp when the event fired
            - scheduled_value: The configured value (e.g., "14:30", 60)
    """
    ws = xpycode.workbook.worksheets.getActiveWorksheet()
    # Your logic here...
    print(f"Timer fired at {event['trigger_time']}")

Execution Context

On-time event handlers execute inside the workbook's Python kernel, exactly like regular Excel event handlers. Long-running or blocking code will delay subsequent timer firings. Use asynchronous patterns or offload heavy work to background threads where possible.


Examples

Use Case 1 — Periodic Data Refresh

Refresh a live data feed every 30 seconds:

import xpycode
import requests

def refresh_live_data(event):
    """Fetch latest prices and write to the worksheet."""
    response = requests.get("https://api.example.com/prices")
    data = response.json()

    ws = xpycode.workbook.worksheets.getWorksheet("LiveData")
    ws.getRange("B2").values = [[data["AAPL"]]]
    ws.getRange("B3").values = [[data["MSFT"]]]

    print(f"Data refreshed at {event['trigger_time']}")

Timer Manager configuration:

Field Value
Type delay
Value 30
Time Type local
Module data_feed
Function refresh_live_data

Use Case 2 — Daily Report Generation

Generate a summary report every weekday morning at 09:00:

import xpycode

def generate_daily_report(event):
    """Compile and format the daily summary report."""
    wb = xpycode.workbook
    ws_data = wb.worksheets.getWorksheet("Data")
    ws_report = wb.worksheets.getWorksheet("Report")

    # Read source data
    data_range = ws_data.getUsedRange()
    values = data_range.values

    # Write summary header
    ws_report.getRange("A1").values = [[f"Report generated: {event['trigger_time']}"]]

    print(f"Daily report complete ({event['trigger_time']})")

Timer Manager configuration:

Field Value
Type time
Value 09:00
Time Type local
Days Monday, Tuesday, Wednesday, Thursday, Friday
Module reports
Function generate_daily_report

Use Case 3 — One-Shot Scheduled Alert

Send a one-time notification at a specific date and time:

import xpycode

def send_deadline_alert(event):
    """Highlight deadline row and log the alert."""
    ws = xpycode.workbook.worksheets.getWorksheet("Projects")
    # Highlight the deadline row
    ws.getRange("A5:F5").format.fill.color = "#FF0000"
    print(f"Deadline alert fired at {event['trigger_time']}")

Timer Manager configuration:

Field Value
Type datetime
Value 2026-03-15T09:00:00
Time Type local
Module alerts
Function send_deadline_alert

Delay Intervals

Avoid very short delay intervals (less than 5 seconds). Rapid repeated executions can impact Excel performance and may cause handlers to queue up if they take longer than the interval to complete.


Next Steps