RFC 9922

A Common YANG Data Model for Scheduling

๐Ÿ“… published March 2026, from ietf

1. Introduction ๐Ÿ“ฆโœจ

Okay bestie, let's get into it ๐ŸŽ€ This is RFC 9922, a Standards Track document from March 2026 (ISSN 2070-1721) that defines A Common YANG Data Model for Scheduling ๐Ÿ“…. It's published by the Internet Engineering Task Force (IETF) and written by Q. Ma (Ed.) and Q. Wu from Huawei, M. Boucadair (Ed.) from Orange, and D. King from Lancaster University. The header is basically the cast list ๐Ÿ’…

Abstract ๐Ÿ’Œ

This doc gives us common types and groupings for scheduling stuff, like events, policies, services, or resources that run based on date and time ๐Ÿ—“๏ธ For better modularity, the YANG module comes with a set of recurrence groupings at different levels, from basic to advanced, so it can handle a bunch of different needs ๐Ÿงฉ It also has groupings for checking requested schedules and reporting their status ๐Ÿ“Š

Status of This Memo ๐Ÿ“œ

This is an Internet Standards Track document ๐ŸŽ€

This document is a product of the Internet Engineering Task Force (IETF) ๐ŸŒธ It represents the consensus of the IETF community, got public review, and was approved for publication by the Internet Engineering Steering Group (IESG) ๐Ÿ‘‘ If you want more info on Internet Standards, check Section 2 of RFC 7841 ๐Ÿซถ

For the latest status, errata, and feedback info, go to https://www.rfc-editor.org/info/rfc9922 ๐Ÿ”—

Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved. ๐Ÿฆ‹

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they're in effect on the date of publication. Please read these carefully, because they cover your rights and restrictions for this document ๐Ÿ“ Code Components pulled out of this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as the Revised BSD License describes ๐Ÿ’–

Table of Contents ๐Ÿ—‚๏ธ

   1.  Introduction
   2.  Conventions and Definitions
   3.  Module Overview
     3.1.  Features
     3.2.  Types and Identities
     3.3.  Scheduling Groupings
       3.3.1.  The "generic-schedule-params" Grouping
       3.3.2.  The "period-of-time" Grouping
       3.3.3.  The "recurrence-basic" Grouping
       3.3.4.  The "recurrence-utc" Grouping
       3.3.5.  The "recurrence-with-time-zone" Grouping
       3.3.6.  The "recurrence-utc-with-periods" Grouping
       3.3.7.  The "recurrence-time-zone-with-periods" Grouping
       3.3.8.  The "icalendar-recurrence" Grouping
       3.3.9.  The "schedule-status",
               "schedule-status-with-time-zone", and
               "schedule-status-with-name" Groupings
     3.4.  Features Use and Augmentations
   4.  Some Usage Restrictions
   5.  Relationship to the DISMAN-SCHEDULE-MIB
   6.  The "ietf-schedule" YANG Module
   7.  Security Considerations
   8.  IANA Considerations
     8.1.  The IETF XML Registry
     8.2.  The YANG Module Names Registry
   9.  References
     9.1.  Normative References
     9.2.  Informative References
   Appendix A.  Examples of Scheduling Format Representation
     A.1.  The "generic-schedule-params" Grouping
     A.2.  The "period-of-time" Grouping
     A.3.  The "recurrence-basic" Grouping
     A.4.  The "recurrence-utc" Grouping
     A.5.  The "recurrence-with-time-zone" Grouping
     A.6.  The "recurrence-utc-with-periods" Grouping
     A.7.  The "recurrence-time-zone-with-periods" Grouping
     A.8.  The "icalendar-recurrence" Grouping
     A.9.  The "schedule-status" Grouping
   Appendix B.  Examples of Using/Extending the "ietf-schedule" Module
     B.1.  Example: Schedule Tasks to Execute Based on a Recurrence
           Rule
     B.2.  Example: Schedule Network Properties to Change Based on
           Date and Time
   Appendix C.  Examples of Using the "ietf-schedule" Module for
           Scheduled Use of Resources Framework
   Acknowledgments
   Authors' Addresses

1. Introduction ๐ŸŒท

This document defines a common schedule YANG module ("ietf-schedule") that can be used in lots of scheduling contexts, like (but not only) [YANG-NAC], [YANG-OAM], and [YANG-SCHEDULE] ๐Ÿงš The module has reusable groupings that are built for scheduling stuff like events, policies, services, or resources based on date and time ๐Ÿ—“๏ธ It also has groupings for validating requested schedules and reporting their statuses ๐Ÿ“Š

This document doesn't make any assumptions about what actions get triggered by the schedules ๐Ÿ™ˆ Detecting and resolving schedule conflicts is out of scope here, so that's a different story ๐Ÿ’…

Section 5 talks about how this relates to the Management Information Base (MIB) managed objects for scheduling management operations defined in [RFC3231] ๐Ÿ“š

Appendix A has examples of how to use the common schedule groupings (Section 3.3) ๐Ÿ“ Appendix B has sample modules showing how future modules can use the extensibility provisions in the "ietf-schedule" module (Section 6) โœจ And Appendix C shows how to use the "ietf-schedule" module for scheduled use of a resources framework (e.g., [RFC8413]) ๐Ÿฆ‹

2. Conventions and Definitions ๐ŸŽ€

Okay so, the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be read as described in BCP 14 [RFC2119] [RFC8174], but only when they show up in all capitals, exactly like that ๐Ÿ™ˆ No capitals, no special meaning, periodt ๐Ÿ’€

The meanings of the symbols in tree diagrams are defined in [RFC8340] ๐ŸŒณ

This document uses the YANG terminology defined in Section 3 of [RFC7950] ๐Ÿง 

Here are the terms this document uses:

Recurrence rule: A rule or repeating pattern for recurring events. See also Section 3.8.5.3 of [RFC5545] for a full iCalendar recurrence rule spec ๐Ÿ”

Recurrence instance (or Recurrence, for short): An instance that matches a recurrence rule โœจ

Recurrence set: A set of recurrence instances ๐Ÿงบ

Frequency: Describes the type of a recurrence rule ๐Ÿ’ซ The values come from the "FREQ" rule in Section 3.3.10 of [RFC5545].

For example, repeating events on an interval of a second or more are classed as recurrence with a frequency value of "SECONDLY" โฑ๏ธ Frequency values that are defined as identities in the YANG module are written in lowercase, so keep an eye out for that ๐Ÿ‘€

iCalendar: Internet Calendaring, per [RFC5545] ๐Ÿ“…

Interval: An integer that says how often a recurrence rule repeats ๐Ÿ”‚ The values come from the "INTERVAL" rule in Section 3.3.10 of [RFC5545].

For example, "1" means every second for a secondly rule, every minute for a minutely rule, every hour for an hourly rule, and so on ๐Ÿ•ฐ๏ธ

System: An entity that hosts a schedule which is managed using the YANG module defined in this document ๐Ÿ 

"schedule-status-*" refers to any of "schedule-status", "schedule-status-with-time-zone", and "schedule-status-with-name" ๐Ÿซง

3. Module Overview ๐Ÿงšโ€โ™€๏ธ

3.1. Features ๐ŸŒˆ

The "ietf-schedule" data model defines the recurrence-related groupings in a modular way ๐Ÿงฉ So you get a bunch of recurrence groupings, ranging from basic to advanced (iCalender-like), and to allow for different options, two features are defined in the data model:

  • "basic-recurrence"
  • "icalendar-recurrence"

For how to use these features, look at Section 3.4 and Appendix B.1 ๐ŸŽ€

3.2. Types and Identities ๐Ÿซง

The "ietf-schedule" module (Section 6) defines the following identities:

  • "schedule-type": Shows what type of schedule it is ๐Ÿท๏ธ These types are defined so far:
    • one-shot: This type is for a schedule that triggers an action with either a duration of 0 or an end time that's the same as its start time. After that, the schedule disables itself (Section 3.3 of [RFC3231]) ๐Ÿ’ฅ
    • period: This type is for a period-based schedule that's either (1) a start and end, or (2) a start and a positive duration. If there's neither an end nor a duration, the period is considered to last forever โ™พ๏ธ
    • recurrence: This type is for a recurrence-based schedule ๐Ÿ” A recurrence can be periodic (repeating over the same period, like every five minutes) or not (repeating in an irregular way, like every day at 8 and 9 AM) โฐ
  • "frequency-type": Describes the repeating interval rule of a recurrence schedule (secondly, minutely, etc.) ๐ŸŒ€
  • "schedule-state": Shows the status of a schedule (enabled, disabled, conflicted, finished, etc.) ๐Ÿšฆ This identity can also be used to manage the state of individual instances of a recurrence-based schedule ๐Ÿง
  • "discard-action-type": Says what action the responder should take (like generating a warning or an error message) when a requested schedule can't be accepted for any reason and gets discarded ๐Ÿ—‘๏ธ

3.3. Scheduling Groupings ๐Ÿญ

The "ietf-schedule" module (Section 6) defines the following groupings:

  • "generic-schedule-params" (Section 3.3.1)
  • "period-of-time" (Section 3.3.2)
  • "recurrence-basic" (Section 3.3.3)
  • "recurrence-utc" (Section 3.3.4)
  • "recurrence-with-time-zone" (Section 3.3.5)
  • "recurrence-utc-with-periods" (Section 3.3.6)
  • "recurrence-time-zone-with-periods" (Section 3.3.7)
  • "icalendar-recurrence" (Section 3.3.8)
  • "schedule-status", "schedule-status-with-time-zone", and "schedule-status-with-name" (Section 3.3.9)

Examples are provided in Appendix A ๐Ÿ’–

3.3.1. The "generic-schedule-params" Grouping

Okay so bestie, this is where the schedule validation magic lives ๐Ÿ”ฎโœจ A system can accept and handle schedule requests, and that can seriously help automate the scheduling of events, policies, services, or resources based on date and time ๐Ÿ—“๏ธ๐Ÿ’… The "generic-schedule-params" grouping (Figure 1) is the set of config knobs a system uses to validate requested schedules. It's giving gatekeeper energy ๐Ÿšช๐ŸŽ€

grouping generic-schedule-params:
  +-- description?            string
  +-- time-zone-identifier?   sys:timezone-name
  +-- validity?               yang:date-and-time
  +-- max-allowed-start?      yang:date-and-time
  +-- min-allowed-start?      yang:date-and-time
  +-- max-allowed-end?        yang:date-and-time
  +-- discard-action?         identityref

Figure 1: 'generic-schedule-params' Grouping Tree Structure

The "description" parameter is where you describe the schedule ๐Ÿ“ No constraint is imposed on the structure or the use of this parameter, so do you bestie ๐ŸŒธ

The "time-zone-identifier" parameter, if provided, specifies the time zone reference [RFC7317] for local date and time values. Here's the vibe check: this parameter MUST be specified if any of the date and time values are in local time format. It MUST NOT be applied to date and time values that are in UTC format or in a time zone offset to UTC ๐ŸŒ๐Ÿšซ

Wait, I need to fix my own colouring there, since BCP 14 key words can't be wrapped in colour tags. Restated cleanly:

The "time-zone-identifier" parameter, if provided, specifies the time zone reference [RFC7317] of the local date and time values. This parameter MUST be specified if any of the date and time values are in the format of local time. It MUST NOT be applied to date and time values that are specified in the format of UTC or time zone offset to UTC ๐ŸŒ๐Ÿšซ

The "validity" parameter specifies the date and time after which a schedule is no longer valid ๐Ÿ•ฐ๏ธ It sets the latest time a schedule can start, so it's giving "last call" vibes, and it's independent of when the schedule ends. It takes precedence over similar attributes provided at the schedule instance itself, so it's the boss ๐Ÿ‘‘ A requested schedule may still be accepted, but any occurrences that start later than the configured value will not be executed ๐Ÿ™ˆ

The "max/min-allowed-start" parameters specify the maximum and minimum scheduled start date and time ๐Ÿšฆ A requested schedule will be rejected if its first occurrence starts later than the configured max, or earlier than the configured min. No cap, that's strict ๐Ÿ’€

The "max-allowed-end" parameter specifies the maximum allowed end time of the last occurrence ๐Ÿ A requested schedule will be rejected if the end time of the last occurrence is later than the configured "max-allowed-end" value.

The "discard-action" parameter specifies the action taken if a requested schedule cannot be accepted for any reason and gets discarded ๐Ÿ—‘๏ธ Possible reasons include, but are not limited to, the requested schedule failing to satisfy the guards in this grouping, conflicting with existing schedules, or being out-of-date (for example, the expected start has already passed) ๐Ÿ˜ญ

These parameters apply to all schedules on a system. They're meant to provide guards against stale configuration, and against schedule requests that are too short and would therefore stop admins of some critical systems from validating them in time, etc. Protective era, honestly ๐Ÿ›ก๏ธ๐Ÿซถ

3.3.2. The "period-of-time" Grouping

The "period-of-time" grouping (Figure 2) represents a time period using either a start date and time ("period-start") plus an end date and time ("period-end"), or a start date and time ("period-start") plus a non-negative time duration ("duration"). For the first format, the start of the period MUST be no later than the end of the period. If neither an end date and time ("period-end") nor a duration ("duration") is indicated, the period is considered to last forever โ™พ๏ธ If the duration ("duration") value is 0, or the end time ("period-end") is the same as the start time ("period-start"), the period is considered a one-shot schedule ๐ŸŽฏ If no start date and time ("period-start") is specified, the period is considered to start immediately โšก

The "time-zone-identifier" parameter indicates the identifier for the time zone. This parameter MUST be specified if either the "period-start" or "period-end" value is reported in local time format. It MUST NOT be applied to date and time values that are specified in the format of UTC or time zone offset to UTC ๐ŸŒ

The "period-description" parameter includes a description of the period ๐Ÿ“– No constraint is imposed on the structure or the use of this parameter.

grouping period-of-time:
  +-- period-description?     string
  +-- period-start?           yang:date-and-time
  +-- time-zone-identifier?   sys:timezone-name
  +-- (period-type)?
     +--:(explicit)
     |  +-- period-end?       yang:date-and-time
     +--:(duration)
        +-- duration?         duration

Figure 2: 'period-of-time' Grouping Tree Structure

3.3.3. The "recurrence-basic" Grouping

The "recurrence-basic" grouping (Figure 3) specifies a simple recurrence rule that starts immediately and repeats forever ๐Ÿ”โœจ

grouping recurrence-basic:
  +-- recurrence-description?   string
  +-- frequency?                identityref
  +-- interval?                 uint32

Figure 3: 'recurrence-basic' Grouping Tree Structure

The frequency parameter ("frequency") identifies the type of recurrence rule. For example, a "daily" frequency value specifies repeating events based on an interval of a day or more ๐Ÿ“…

Consistent with Section 3.3.10 of [RFC5545], the interval parameter ("interval") represents the interval at which the recurrence rule repeats. For example, within a "daily" recurrence rule, an interval value of "8" means every eight days ๐ŸŒˆ

Note that, per Section 4.13 of [YANG-GUIDE], no "default" substatement is defined here for either the "frequency" or "interval" parameters, because there are cases (for example, profiling) where using these statements is problematic. No "mandatory" substatement is defined here for the same reason. YANG modules using this grouping SHOULD refine these two nodes with either a "mandatory" or a "default" statement if they always need to be configured or have default values. This recommendation MAY be ignored in cases such as when this grouping is used by another grouping ๐Ÿค“

The "recurrence-description" parameter includes a description of the period ๐Ÿ’œ No constraint is imposed on the structure or the use of this parameter.

3.3.4. The "recurrence-utc" Grouping

The "recurrence-utc" grouping (Figure 4) uses the "recurrence-basic" grouping (Section 3.3.3) and specifies a simple recurrence rule in UTC format ๐ŸŒ

grouping recurrence-utc:
  +-- recurrence-first
  |  +-- start-time-utc?   yang:date-and-time
  |  +-- duration?         uint32
  +-- (recurrence-end)?
  |  +--:(until)
  |  |  +-- utc-until?          yang:date-and-time
  |  +--:(count)
  |     +-- count?              uint32
  +-- recurrence-description?   string
  +-- frequency?                identityref
  +-- interval?                 uint32

Figure 4: 'recurrence-utc' Grouping Tree Structure

The "start-time-utc" parameter indicates the start time in UTC format โฐ

The "duration" parameter specifies, in units of seconds, the time period of the first occurrence. Unless specified otherwise (for example, through additional augmented parameters), the "duration" also applies to subsequent recurrence instances. When unspecified, each occurrence is considered to be an immediate completion (for example, an immediate command that is considered to complete quickly), or it is hard to compute an exact duration (for example, a data analysis script whose execution time may depend on the data volume and computation resource availability). The behavior to follow when a task takes more time than specified by the "duration" is out of scope. Such considerations belong to task management, not schedule management ๐Ÿง 

Note that the "interval" and "duration" cover two distinct properties of a schedule event. The interval specifies when a schedule will occur, combined with the frequency parameter, while the duration indicates how long an occurrence will last. This document allows the interval between occurrences to be shorter than the duration of each occurrence (for example, a recurring event is scheduled to start every day for a duration of 2 days) ๐Ÿซ 

The repetition can be scoped by a specified end time or by a count of occurrences, indicated by the "recurrence-end" choice. The "count" value MUST be greater than 1, and the "start-time-utc" value always counts as the first occurrence ๐Ÿ”ข

The "recurrence-utc" grouping is designed to be reused in scheduling contexts where machine readability is more desirable ๐Ÿค–๐Ÿ’–

3.3.5. The "recurrence-with-time-zone" Grouping

The "recurrence-with-time-zone" grouping (Figure 5) uses the "recurrence-basic" grouping (Section 3.3.3) and specifies a simple recurrence rule with a time zone ๐ŸŒธ

grouping recurrence-with-time-zone:
  +-- recurrence-first
  |  +-- start-time?   yang:date-and-time
  |  +-- duration?     duration
  +-- time-zone-identifier?     sys:timezone-name
  +-- (recurrence-end)?
  |  +--:(until)
  |  |  +-- until?              yang:date-and-time
  |  +--:(count)
  |     +-- count?              uint32
  +-- recurrence-description?   string
  +-- frequency?                identityref
  +-- interval?                 uint32

Figure 5: 'recurrence-with-time-zone' Grouping Tree Structure

The "recurrence-first" container includes the "start-time" and "duration" parameters to specify the start time and period of the first occurrence. Unless specified otherwise (for example, through additional augmented parameters), the "duration" also applies to subsequent recurrence instances. When unspecified, each occurrence is considered to be an immediate completion (for example, an immediate command that is considered to complete quickly), or it is hard to compute an exact duration (for example, a data analysis script whose execution time may depend on the data volume and computation resource availability) โณ

The grouping also includes a "time-zone-identifier" parameter, which MUST be specified if either the "start-time" or "until" value is reported in local time format. It MUST NOT be applied to date and time values that are specified in the format of UTC or time zone offset to UTC ๐Ÿ—บ๏ธ

The repetition can be scoped by a specified end time or by a count of occurrences, indicated by the "recurrence-end" choice. The "count" value MUST be greater than 1, and the "start-time" value always counts as the first occurrence ๐ŸŽ€

The considerations discussed in Section 3.3.4 for "interval" and "duration" are also applicable to "recurrence-with-time-zone" โœจ

Unlike the definition of the "recurrence-utc" grouping (Section 3.3.4), "recurrence-with-time-zone" is intended to promote human readability over machine readability ๐Ÿ‘€๐Ÿ’…

3.3.6. The "recurrence-utc-with-periods" Grouping

okay so this one is the utc version with periods bestie ๐ŸŒธ it builds on the "recurrence-utc" grouping (Section 3.3.4) and adds a "period-timeticks" list ๐Ÿ’… so you get an aggregate set of repeating occurrences โœจ

grouping recurrence-utc-with-periods:
  +-- recurrence-first
  |  +-- start-time-utc?   yang:date-and-time
  |  +-- duration?         uint32
  +-- (recurrence-end)?
  |  +--:(until)
  |  |  +-- utc-until?          yang:date-and-time
  |  +--:(count)
  |     +-- count?              uint32
  +-- recurrence-description?   string
  +-- frequency?                identityref
  +-- interval?                 uint32
  +-- period-timeticks* [period-start]
     +-- period-start    yang:timeticks
     +-- period-end?     yang:timeticks

Figure 6: 'recurrence-utc-with-periods' Grouping Tree Structure ๐ŸŽ€

the recurrence instances are specified by the union of occurrences defined by both the recurrence rule and the "period-timeticks" list ๐Ÿฆ‹ this list uses the "yang:timeticks" type defined in [RFC9911] ๐Ÿซถ duplicate instances are ignored ๐Ÿ’€ and here's the important bit: the value of the "period-start" instance MUST NOT exceed the value of the "frequency" instance ๐Ÿ˜ญ like, the "timeticks" value must not exceed 100 in a secondly recurrence rule, and it must not exceed 6000 in a minutely recurrence rule, and so on ๐Ÿ”ฅ

3.3.7. The "recurrence-time-zone-with-periods" Grouping

okay next up is the time-zone version ๐Ÿงš it uses the "recurrence-with-time-zone" grouping (Section 3.3.5) and adds a "period" list so you get an aggregate set of repeating occurrences ๐ŸŒˆ

grouping recurrence-time-zone-with-periods:
  +-- recurrence-first
  |  +-- start-time?   yang:date-and-time
  |  +-- duration?     duration
  +-- time-zone-identifier?     sys:timezone-name
  +-- (recurrence-end)?
  |  +--:(until)
  |  |  +-- until?              yang:date-and-time
  |  +--:(count)
  |     +-- count?              uint32
  +-- recurrence-description?   string
  +-- frequency?                identityref
  +-- interval?                 uint32
  +-- period* [period-start]
     +-- period-description?     string
     +-- period-start            yang:date-and-time
     +-- time-zone-identifier?   sys:timezone-name
     +-- (period-type)?
        +--:(explicit)
        |  +-- period-end?       yang:date-and-time
        +--:(duration)
           +-- duration?         duration

Figure 7: 'recurrence-time-zone-with-periods' Grouping Tree Structure ๐Ÿ’–

the recurrence instances are specified by the union of occurrences defined by both the recurrence rule and the "period" list ๐Ÿฆ‹ duplicate instances are ignored โœจ

3.3.8. The "icalendar-recurrence" Grouping

this is the big one and I'm obsessed ๐Ÿ˜ญ๐Ÿซถ it uses the "recurrence-time-zone-with-periods" grouping (Section 3.3.7) and defines more data nodes to enrich the definition of recurrence ๐Ÿ’… the structure refers to the recurrence component defined in Sections 3.3.10 and 3.8.5 of [RFC5545] ๐ŸŒˆ

grouping icalendar-recurrence:
  +-- recurrence-first
  |  +-- start-time?   yang:date-and-time
  |  +-- duration?     duration
  +-- time-zone-identifier?     sys:timezone-name
  +-- (recurrence-end)?
  |  +--:(until)
  |  |  +-- until?              yang:date-and-time
  |  +--:(count)
  |     +-- count?              uint32
  +-- recurrence-description?   string
  +-- frequency?                identityref
  +-- interval?                 uint32
  +-- period* [period-start]
  |  +-- period-description?     string
  |  +-- period-start            yang:date-and-time
  |  +-- time-zone-identifier?   sys:timezone-name
  |  +-- (period-type)?
  |     +--:(explicit)
  |     |  +-- period-end?       yang:date-and-time
  |     +--:(duration)
  |        +-- duration?         duration
  +-- bysecond*                 uint32
  +-- byminute*                 uint32
  +-- byhour*                   uint32
  +-- byday* [weekday]
  |  +-- direction*   int32
  |  +-- weekday      schedule:weekday
  +-- bymonthday*               int32
  +-- byyearday*                int32
  +-- byyearweek*               int32
  +-- byyearmonth*              uint32
  +-- bysetpos*                 int32
  +-- workweek-start?           schedule:weekday
  +-- exception-dates*          yang:date-and-time

Figure 8: 'icalendar-recurrence' Grouping Tree Structure โญ

an array of "bysecond" (or "byminute" or "byhour") specifies a list of seconds within a minute (or minutes within an hour or hours of the day) ๐Ÿ“ for example, within a "minutely" recurrence rule, the values of "byminute" node "10" and "20" mean the occurrences are generated at the 10th and 20th minute within an hour, reducing the number of recurrence instances from all minutes ๐Ÿ™ˆ

the parameter "byday" specifies a list of days of the week, with an optional direction that indicates the nth occurrence of a specific day within the "monthly" or "yearly" frequency instance ๐Ÿ’œ valid values of "direction" are 1 to 5 or -5 to -1 within a "monthly" recurrence rule and 1 to 53 or -53 to -1 within a "yearly" recurrence rule ๐Ÿฆ‹ for example, within a "monthly" rule, the "weekday" with a value of "monday" and the "direction" with a value of "-1" represents the last Monday of the month ๐Ÿ‘‘

an array of "bymonthday" (or byyearday", "byyearweek", or "byyearmonth") specifies a list of days of the month (or days of the year, weeks of the year, or months of the year) ๐ŸŒธ for example, within a "yearly" recurrence rule, the values of "byyearmonth" instances "1" and "2" mean the occurrences are generated in January and February, increasing the "yearly" recurrence from every year to every January and February of the year ๐ŸŽ€

the "bysetpos" conveys a list of values that corresponds to the nth occurrence within the set of recurrence instances to be specified ๐Ÿงš for example, in a "monthly" recurrence rule, the "byday" data node specifies every Monday of the week, and the "bysetpos" with a value of "-1" represents the last Monday of the month ๐Ÿ’… not setting the "bysetpos" data node represents every Monday of the month ๐Ÿ’€

the "workweek-start" data node specifies the day on which the week starts ๐Ÿซถ this is significant when a "weekly" recurrence rule has an interval greater than 1, and a "byday" data node is specified ๐Ÿ”ฅ this is also significant when in a "yearly" rule and a "byyearweek" is specified โœจ note that, per Section 4.13 of [YANG-GUIDE], no "default" substatement is defined here because there are cases (e.g., profiling) where using these statements is problematic ๐Ÿ˜ญ no "mandatory" substatement is defined here for the same reason ๐Ÿ’– YANG modules using this grouping SHOULD refine the "workweek-start" node with either a "mandatory" or a "default" statement if it always needs to be configured or has a default value ๐ŸŒˆ this MAY be ignored in cases such as when this grouping is used by another grouping ๐Ÿฆ‹

the "exception-dates" data node specifies a list of exceptions for recurrence ๐ŸŒธ the final recurrence set is generated by gathering all of the date and time values created by any of the specified recurrence rules and date-times and then excluding any start date and time values specified by "exception-dates" parameter ๐Ÿ’œ

3.3.9. The "schedule-status", "schedule-status-with-time-zone", and "schedule-status-with-name" Groupings โœจ

okay so these three groupings (Figure 9) are the shared status bits for managing and exposing a schedule ๐Ÿ’…. "schedule-status-with-time-zone" is basically the same as "schedule-status", just with an extra time zone identifier ๐ŸŒ. "schedule-status-with-name" is also the same, but it adds a "schedule-name" ๐ŸŽ€. They live in the module so everyone can reuse the same structure, which is the whole modularity glow-up ๐Ÿงš.

grouping schedule-status:
  +-- state?                    identityref
  +-- version?                  uint16
  +-- schedule-type?            identityref
  +--ro local-time?               yang:date-and-time
  +--ro last-update?              yang:date-and-time
  +--ro counter?                  yang:counter32
  +--ro last-occurrence?          yang:date-and-time
  +--ro upcoming-occurrence?      yang:date-and-time
  +--ro last-failed-occurrence?   yang:date-and-time
  +--ro failure-counter?          yang:counter32
grouping schedule-status-with-time-zone:
  +--ro time-zone-identifier?  sys:timezone-name
  +-- schedule-name?            string
  +-- state?                    identityref
  +-- version?                  uint16
  +-- schedule-type?            identityref
  +--ro local-time?               yang:date-and-time
  +--ro last-update?              yang:date-and-time
  +--ro counter?                  yang:counter32
  +--ro last-occurrence?          yang:date-and-time
  +--ro upcoming-occurrence?      yang:date-and-time
  +--ro last-failed-occurrence?   yang:date-and-time
  +--ro failure-counter?          yang:counter32
grouping schedule-status-with-name:
  +-- schedule-name?            string
  +-- state?                    identityref
  +-- version?                  uint16
  +-- schedule-type?            identityref
  +--ro local-time?               yang:date-and-time
  +--ro last-update?              yang:date-and-time
  +--ro counter?                  yang:counter32
  +--ro last-occurrence?          yang:date-and-time
  +--ro upcoming-occurrence?      yang:date-and-time
  +--ro last-failed-occurrence?   yang:date-and-time
  +--ro failure-counter?          yang:counter32

Figure 9: 'schedule-status-*' Groupings Tree Structure

The schedule-name parameter is the handy way to uniquely identify a schedule on a network device or controller when there are multiple scheduling contexts ๐Ÿ”.

The state parameter is for configuring or exposing the scheduling state, depending on how the grouping is being used ๐Ÿฆ‹. For a recurrence-based schedule, it represents the state of the overall recurrence. It uses the identityref type so it can be extended in future modules โœจ.

The version parameter tracks the current schedule version information. The version can be incremented by the entity that created the schedule. The last-update parameter identifies when the schedule was last modified. In some contexts, this parameter can be used to track the configuration of a given schedule. In such cases, the version may not be used ๐ŸŒธ.

The schedule-type parameter identifies the type of the current schedule ๐Ÿ“…. The counter, last-occurrence, and upcoming-occurrence data nodes are only available when the schedule-type is recurrence ๐Ÿ”.

When no time zone is included, local-time reports the actual local time as seen by the entity that hosts a schedule ๐Ÿ•ฐ๏ธ. This parameter can be used by a controller to infer the offset to UTC. This use is similar to the use of schedLocalTime in [RFC3231] ๐Ÿ™ˆ.

last-failed-occurrence and failure-counter report the last failure that occurred and the count of failures for this schedule ๐Ÿ’€. Unless new parameters/operations are defined to allow the count of failures to be reset, failure-counter is reset by default only when the schedule starts.

The current groupings capture common parameters that are applicable to typical scheduling contexts known so far. Future modules can define other useful parameters as needed. For example, in a scheduling context with multiple system sources to feed the schedules, the source and precedence parameters may be needed to reflect how schedules from different sources should be prioritized ๐Ÿ‘‘.

3.4. Features Use and Augmentations

Appendix B.1 provides an example about how the features defined in Section 3.1 can be used ๐Ÿง. Implementations may support a basic recurrence rule or an advanced one, as needed, by declaring different features. Whether only one or both features are supported is implementation specific and depends on the specific scheduling context ๐Ÿ’–.

The common schedule groupings (Section 3.3) can also be augmented to support specific needs. As an example, Appendix B.2 demonstrates how additional parameters can be added to comply with specific schedule needs ๐ŸŒˆ.

4. Some Usage Restrictions ๐Ÿšง

There are some restrictions that need to be followed when using groupings defined in the ietf-schedule YANG module (Section 3.3):

  • The instant in time represented by period-start MUST be before the period-end for the period-of-time grouping (Section 3.3.2).
  • The combination of the day, month, and year represented for date and time values MUST be valid. See Section 5.7 of [RFC3339] for the maximum day number based on the month and year ๐Ÿ“†.
  • Unless deployed in contexts where time synchronization is not subject to leap second adjustments (e.g., Section 4.3 of [NTPv5]), the second for date and time values SHOULD have the value 60 at the end of months in which a leap second occurs โฑ๏ธ.
  • Schedules received with a starting time in the past with respect to current time SHOULD be ignored. When a local policy is provided, an implementation MAY omit the past occurrences and start immediately (e.g., for a period-based schedule) or start from the date and time when the recurrence pattern is first satisfied from the current time (e.g., for a recurrence-based schedule) ๐Ÿ•Š๏ธ.

5. Relationship to the DISMAN-SCHEDULE-MIB

[RFC3231] specifies a Management Information Base (MIB) used to schedule management operations periodically or at specified dates and times ๐Ÿ—“๏ธ.

Although no data nodes are defined in this document, Table 1 lists how the main objects in the DISMAN-SCHEDULE-MIB can be mapped to YANG parameters ๐Ÿฆ‹.

+==================+=========================+
| MIB Object       | YANG                    |
+==================+=========================+
| schedLocalTime   | local-time              |
+------------------+-------------------------+
| schedType        | schedule-type           |
+------------------+-------------------------+
| schedName        | schedule-name           |
+------------------+-------------------------+
| schedOwner       | Not Supported           |
+------------------+-------------------------+
| schedDescr       | description             |
+------------------+-------------------------+
| schedInterval    | interval                |
+------------------+-------------------------+
| schedWeekDay     | weekday                 |
+------------------+-------------------------+
| schedMonth       | byyearmonth             |
+------------------+-------------------------+
| schedDay         | bymonthday              |
+------------------+-------------------------+
| schedHour        | byhour                  |
+------------------+-------------------------+
| schedMinute      | byminute                |
+------------------+-------------------------+
| schedContextName | Not Supported           |
+------------------+-------------------------+
| schedAdminStatus | state                   |
+------------------+-------------------------+
| schedOperStatus  | state                   |
+------------------+-------------------------+
| schedFailures    | failure-counter         |
+------------------+-------------------------+
| schedLastFailure | Not Supported           |
+------------------+-------------------------+
| schedLastFailed  | last-failed-occurrence  |
+------------------+-------------------------+
| schedStorageType | Not Supported           |
+------------------+-------------------------+
| schedVariable    | Not applicable          |
+------------------+-------------------------+
| schedValue       | Not applicable          |
+------------------+-------------------------+
| schedTriggers    | counter/failure-counter |
+------------------+-------------------------+

Table 1: YANG/MIB Mapping

6. The "ietf-schedule" YANG Module ๐Ÿ‘‘

This module imports types defined in [RFC9911] and [RFC7317] ๐Ÿ’œ.

<CODE BEGINS>
file "ietf-schedule@2026-03-10.yang"
module ietf-schedule {
  yang-version 1.1;
  namespace "urn:ietf:params:xml:ns:yang:ietf-schedule";
  prefix schedule;

  import ietf-yang-types {
    prefix yang;
    reference
      "RFC 9911: Common YANG Data Types";
  }

  import ietf-system {
    prefix sys;
    reference
      "RFC 7317: A YANG Data Model for System Management";
  }

  organization
    "IETF NETMOD Working Group";
  contact
    "WG Web:  <https://datatracker.ietf.org/wg/netmod/>
     WG List: <mailto:netmod@ietf.org>

     Editor:   Qiufang Ma
               <mailto:maqiufang1@huawei.com>
     Author:   Qin Wu
               <mailto:bill.wu@huawei.com>
     Editor:   Mohamed Boucadair
               <mailto:mohamed.boucadair@orange.com>
     Author:   Daniel King
               <mailto:d.king@lancaster.ac.uk>";
  description
    "This YANG module defines a set of common types and groupings
     that are applicable for scheduling purposes, such as events,
     policies, services, or resources based on date and time.

     The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
     NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
     'MAY', and 'OPTIONAL' in this document are to be interpreted as
     described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
     they appear in all capitals, as shown here.

     Copyright (c) 2026 IETF Trust and the persons identified
     as authors of the code.  All rights reserved.

     Redistribution and use in source and binary forms, with
     or without modification, is permitted pursuant to, and
     subject to the license terms contained in, the Revised
     BSD License set forth in Section 4.c of the IETF Trust's
     Legal Provisions Relating to IETF Documents
     (https://trustee.ietf.org/license-info).

     This version of this YANG module is part of RFC 9922; see
     the RFC itself for full legal notices.";

Okay so the module is still rolling and it's giving big ๐ŸŽ€ We're starting with the tail of the module description, then the revision, the features, and the typedefs.

        All revisions of IETF and IANA-maintained modules can be found
        in the 'YANG Parameters' registry group
        (https://www.iana.org/assignments/yang-parameters).";

     revision 2026-03-10 {
       description
         "Initial revision.";
       reference
         "RFC 9922: A Common YANG Data Model for Scheduling";
     }

     feature basic-recurrence {
       description
         "Indicates that the server supports configuring a basic
          scheduled recurrence.";
     }

     feature icalendar-recurrence {
       description
         "Indicates that the server supports configuring a comprehensive
          scheduled iCalendar recurrence.";
       reference
         "RFC 5545: Internet Calendaring and Scheduling Core Object
                    Specification (iCalendar),
                    Sections 3.3.10 and 3.8.5";
     }

Bestie, the revision is literally just 2026-03-10 with an "Initial revision." description, so this is the first ever version of the module ๐ŸŒธ The two features are optional flags. basic-recurrence says the server supports a basic scheduled recurrence, and icalendar-recurrence is the comprehensive iCalendar version, which points back to RFC 5545 Sections 3.3.10 and 3.8.5 ๐Ÿงš

Next up, the typedefs. weekday is an enum with sunday through saturday, numbered 0 to 6 (so Sunday comes first, no debate ๐Ÿ’…). duration is a string with a pattern, and its description is a whole love letter to nominal and accurate durations โœจ

     typedef weekday {
       type enumeration {
         enum sunday {
           value 0;
           description
             "Sunday of the week.";
         }
         enum monday {
           value 1;
           description
             "Monday of the week.";
         }
         enum tuesday {
           value 2;
           description
             "Tuesday of the week.";
         }
         enum wednesday {
           value 3;
           description
             "Wednesday of the week.";
         }
         enum thursday {
           value 4;
           description
             "Thursday of the week.";
         }
         enum friday {
           value 5;
           description
             "Friday of the week.";
         }
         enum saturday {
           value 6;
           description
             "Saturday of the week.";
         }
       }
       description
         "Seven days of the week.";
     }

     typedef duration {
       type string {
         pattern '((\+)?|\-)P((([0-9]+)D)?(T(0[0-9]|1[0-9]|2[0-3])'
               + ':[0-5][0-9]:[0-5][0-9]))|P([0-9]+)W';
       }
       description
         "Duration of the time.  The format can represent nominal
          durations (weeks designated by 'W' and days designated by 'D')
          and accurate durations (hours:minutes:seconds follows the
          designator 'T').

          Note that this value type doesn't support the 'Y' and 'M'
          designators to specify durations in terms of years and months.

          Negative durations are typically used to schedule an alarm to
          trigger before an associated time.";
       reference
         "RFC 5545: Internet Calendaring and Scheduling Core Object
                    Specification (iCalendar), Sections 3.3.6 and
                    3.8.6.3";
     }

Ngl, the duration description is the main character moment. Nominal durations use W for weeks and D for days, accurate ones use T followed by hours:minutes:seconds, and there is zero Y or M support ๐Ÿ™ˆ Negative durations are mostly for alarms that go off before the thing happens โฐ

Now the identities. First the schedule types, then the frequency types, then the states, then the discard actions.

     identity schedule-type {
       description
         "Base identity for schedule type.";
     }

     identity one-shot {
       base schedule-type;
       description
         "Indicates a one-shot schedule.  That is a schedule that
          will trigger an action with the duration being specified as
          0 or end time being specified as the same as the start time,
          and then the schedule will disable itself.";
     }

     identity period {
       base schedule-type;
       description
         "Indicates a period-based schedule consisting of either a
          start and end or a start and positive duration of time.  If
          neither an end nor a duration is indicated, the period is
          considered to last forever.";
     }

     identity recurrence {
       base schedule-type;
       description
         "Indicates a recurrence-based schedule.";
     }

     identity frequency-type {
       description
         "Base identity for frequency type.";
     }

     identity secondly {
       base frequency-type;
       description
         "Indicates a repeating rule based on an interval of
          a second or more.";
     }

     identity minutely {
       base frequency-type;
       description
         "Indicates a repeating rule based on an interval of
          a minute or more.";
     }

     identity hourly {
       base frequency-type;
       description
         "Indicates a repeating rule based on an interval of
          an hour or more.";
     }

     identity daily {
       base frequency-type;
       description
         "Indicates a repeating rule based on an interval of
          a day or more.";
     }

     identity weekly {
       base frequency-type;
       description
         "Indicates a repeating rule based on an interval of
          a week or more.";
     }

     identity monthly {
       base frequency-type;
       description
         "Indicates a repeating rule based on an interval of
          a month or more.";
     }

     identity yearly {
       base frequency-type;
       description
         "Indicates a repeating rule based on an interval of
          a year or more.";
     }

     identity schedule-state {
       description
         "Base identity for schedule state.";
     }

     identity enabled {
       base schedule-state;
       description
         "Indicates a schedule with an enabled state.";
     }

     identity finished {
       base schedule-state;
       description
         "Indicates a schedule with a finished state.
          The finished state indicates that the schedule has ended.";
     }

     identity disabled {
       base schedule-state;
       description
         "Indicates a schedule with a disabled state.";
     }

     identity out-of-date {
       base schedule-state;
       description
         "Indicates a schedule that is received out-of-date.";
     }

     identity conflicted {
       base schedule-state;
       description
         "Indicates a schedule with a conflicted state with other
          schedules.";
     }

     identity discard-action-type {
       description
         "Base identity for the action for the responder to take
          when a requested schedule cannot be accepted for any
          reason and is discarded.";
     }

     identity warning {
       base discard-action-type;
       description
         "Indicates that a warning message is generated
          when a schedule is discarded.";
     }

     identity error {
       base discard-action-type;
       description
         "Indicates that an error message is generated
          when a schedule is discarded.";
     }

     identity silently-discard {
       base discard-action-type;
       description
         "Indicates that a schedule that is not valid is silently
          discarded.";
     }

So the identities are basically a big family tree ๐ŸŒณ There are three schedule types, one-shot, period, and recurrence, all based on schedule-type. one-shot is the "trigger once and then disable itself" kind, and period covers a start plus an end or a positive duration. If you leave out both the end and the duration, the period lasts forever ๐Ÿ‘‘

Frequency types cover secondly through yearly, all based on frequency-type. Then there are the schedule states: enabled, finished, disabled, out-of-date, and conflicted ๐Ÿฆ‹ Last, the discard actions tell the responder what to do when a request gets tossed: warning, error, or silently-discard ๐Ÿ™ˆ

Now the big one, the generic-schedule-params grouping. These are guard parameters that stop stale config from sneaking in, and it's iconic ๐Ÿ’…

     grouping generic-schedule-params {
       description
         "Includes a set of generic parameters that are followed by
          the entity that supports schedules.

          Such parameters are used as guards to prevent, e.g., stale
          configuration.";
       leaf description {
         type string;
         description
           "Provides a description of the schedule.";
       }
       leaf time-zone-identifier {
         type sys:timezone-name;
         description
           "Indicates the identifier for the time zone.  This parameter
            MUST be specified if any of the date and time values are
            in the format of local time.  It MUST NOT be applied to
            date and time values that are specified in the format of
            UTC or time zone offset to UTC.";
       }
       leaf validity {
         type yang:date-and-time;
         description
           "Specifies the date and time after which a schedule will not
            be considered as valid.  This parameter takes precedence
            over similar attributes that are provided at the schedule
            instance itself.";
       }
       leaf max-allowed-start {
         type yang:date-and-time;
         description
           "Specifies the maximum scheduled start date and time.
            A requested schedule whose first instance occurs after
            this value cannot be accepted by the entity.  Specifically,
            a requested schedule will be rejected if the first
            occurrence of that schedule exceeds 'max-allowed-start'.";
       }
       leaf min-allowed-start {
         type yang:date-and-time;
         description
           "Specifies the minimum scheduled start date and time.
            A requested schedule whose first instance occurs before
            this value cannot be accepted by the entity.  Specifically,
            a requested schedule will be rejected if the first
            occurrence of that schedule is scheduled before
            'min-allowed-start'.";
       }
       leaf max-allowed-end {
         type yang:date-and-time;
         description
           "A requested schedule will be rejected if the end time of
            the last occurrence exceeds 'max-allowed-end'.";
       }
       leaf discard-action {
         type identityref {
           base discard-action-type;
         }
         description
           "Specifies the behavior when a schedule is discarded for
            any reason, e.g., failing to satisfy the guards in this
            grouping or being received out-of-date.";
       }
     }

Bestie, this grouping is a whole checklist. There's a description, a time-zone-identifier (which has a strict rule about when it's needed, so read that one carefully ๐Ÿง), a validity date that wins over any similar setting on the schedule itself โœจ, and then max-allowed-start, min-allowed-start, and max-allowed-end bouncers that reject requests that land outside the window ๐Ÿšซ Finally, discard-action decides what happens when a schedule gets dropped, whether that's failing a guard or arriving out-of-date ๐Ÿ’€

And last but not least, the period-of-time grouping, which is the one tied to the iCalendar period property ๐ŸŒˆ

     grouping period-of-time {
       description
         "This grouping is defined for the period of time property.";
       reference
         "RFC 5545: Internet Calendaring and Scheduling Core Object
                    Specification (iCalendar), Section 3.3.9";
       leaf period-description {
         type string;
         description
           "Provides a description of the period.";
       }
       leaf period-start {
         type yang:date-and-time;
         description
           "Period start time.";
       }
       leaf time-zone-identifier {
         type sys:timezone-name;
         description
           "Indicates the identifier for the time zone.  This parameter
            MUST be specified if either the 'period-start' or
            'period-end' value is reported in local time format.
            It MUST NOT be applied to date and time values that are
            specified in the format of UTC or time zone offset
            to UTC.";
       }
       choice period-type {
         description
           "Indicates the type of the time period.  Two types are
            supported.  If no choice is indicated, the period is
            considered to last forever.";
         case explicit {
           description
             "A period of time is identified by its start and its end.
              'period-start' indicates the period start.";
           leaf period-end {
             type yang:date-and-time;
             description
               "A period of time is defined by a start and end time.
                The start MUST be no later than the end.  The period
                is considered as a one-shot schedule if the end time
                is the same as the start time.";
           }
         }
         case duration {
           description
             "A period of time is defined by a start and a non-negative
              duration of time.";
           leaf duration {
             type duration {
               pattern 'P((([0-9]+)D)?(T(0[0-9]|1[0-9]|2[0-3])'
                     + ':[0-5][0-9]:[0-5][0-9]))|P([0-9]+)W';
             }
             description
               "A non-negative duration of time.  This value is
                equivalent to the format of 'duration' type except that
                the value cannot be negative.  The period is considered
                to be a one-shot schedule if the value is 0.";
           }
         }
       }
     }

So period-of-time is the period flavour ๐Ÿฆ‹ It has a description and a start, plus a choice between two cases. You either give an explicit end (period-end) or a non-negative duration. The period-end case says a one-shot schedule happens when the end matches the start, and the duration case says the same thing when the value is 0 ๐Ÿ™Œ Honestly this is so well-designed it's making me emotional ๐Ÿ˜ญ

okay bestie, this is where the recurrence groupings pick up and they are so detailed ๐Ÿ’…โœจ

     grouping recurrence-basic {
       description
         "A simple definition of recurrence.";
       leaf recurrence-description {
         type string;
         description
           "Provides a description of the recurrence.";
       }
       leaf frequency {
         type identityref {
           base frequency-type;
         }
         description
           "Specifies the frequency type of the recurrence rule.";
       }
       leaf interval {
         type uint32 {
           range "1..max";
         }
         must '../frequency' {
           error-message "Frequency must be provided.";
         }
         description
           "A positive integer representing the interval at which the
            recurrence rule repeats.  For example, within a 'daily'
            recurrence rule, a value of '8' means every eight days.";
       }
     }

     grouping recurrence-utc {
       description
         "A simple definition of recurrence with time specified in
          UTC format.";
       container recurrence-first {
         description
           "Specifies the first instance of the recurrence.  If
            unspecified, the recurrence is considered to start from
            the date and time when the recurrence pattern is first
            satisfied.";
         leaf start-time-utc {
           type yang:date-and-time;
           description
             "Defines the date and time of the first instance
              in the recurrence set.  A UTC format MUST be used.";
         }
         leaf duration {
           type uint32;
           units "seconds";
           description
             "When specified, it indicates how long the first occurrence
              lasts.  Unless specified otherwise, it also applies to all
              the other instances in the recurrence set.";
         }
       }
       choice recurrence-end {
         description
           "Modes to control the end of a recurrence rule.  If no
            choice is indicated, the recurrence rule is considered
            to repeat forever.";
         case until {
           description
             "This case defines a way that limits the end of
              a recurrence rule in an inclusive manner.";
           leaf utc-until {
             type yang:date-and-time;
             description
               "This parameter specifies a date and time value to
                inclusively terminate the recurrence in UTC format.
                That is, if the value specified by this parameter is
                synchronized with the specified recurrence rule, it
                becomes the last instance of the recurrence rule.";
           }
         }
         case count {
           description
             "This case defines the number of occurrences at which
              to terminate the recurrence rule.";
           leaf count {
             type uint32 {
               range "1..max";
             }
             description
               "The positive number of occurrences at which to
                terminate the recurrence rule.";
           }
         }
       }
       uses recurrence-basic;
     }

     grouping recurrence-with-time-zone {
       description
         "A simple definition of recurrence to specify a recurrence
          rule with a time zone.";
       container recurrence-first {
         description
           "Specifies the first instance of the recurrence.  If
            unspecified, the recurrence is considered to start from
            the date and time when the recurrence pattern is first
            satisfied.";
         leaf start-time {
           type yang:date-and-time;
           description
             "Defines the date and time of the first instance
              in the recurrence set.";
         }
         leaf duration {
           type duration;
           description
             "When specified, it indicates how long the first
              occurrence lasts.  Unless specified otherwise, it also
              applies to all the other instances in the recurrence
              set.";
         }
       }
       leaf time-zone-identifier {
         type sys:timezone-name;
         description
           "Indicates the identifier for the time zone in a time
            zone database.  This parameter MUST be specified if either
            the 'start-time' or 'until' value is reported in local
            time format.  It MUST NOT be applied to date and time
            values that are specified in the format of UTC or time
            zone offset to UTC.";
       }
       choice recurrence-end {
         description
           "Modes to terminate the recurrence rule.  If no choice is
            indicated, the recurrence rule is considered to repeat
            forever.";
         case until {
           description
             "The end of the recurrence rule is indicated by a specific
              date-and-time value in an inclusive manner.";
           leaf until {
             type yang:date-and-time;
             description
               "Specifies a date and time value to inclusively terminate
                the recurrence.  That is, if the value specified by
                this parameter is synchronized with the specified
                recurrence, it becomes the last instance of the
                recurrence.";
           }
         }
         case count {
           description
             "The end of the recurrence is indicated by the number
              of occurrences.";
           leaf count {
             type uint32 {
               range "1..max";
             }
             description
               "The positive number of occurrences at which to
                terminate the recurrence.";
           }
         }
       }
       uses recurrence-basic;
     }

     grouping recurrence-utc-with-periods {
       description
         "This grouping defines an aggregate set of repeating
          occurrences with UTC time format.  The recurrence instances
          are specified by the occurrences defined by both the
          recurrence rule and 'period-timeticks' list.  Duplicate
          instances are ignored.";
       uses recurrence-utc;
       list period-timeticks {
         key "period-start";
         description
           "A list of periods with timeticks formats.";
         leaf period-start {
           type yang:timeticks;
           must "(not(derived-from-or-self(../../frequency,"
              + "'schedule:secondly')) or (current() < 100)) and "
              + "(not(derived-from-or-self(../../frequency,"
              + "'schedule:minutely')) or (current() < 6000)) and "
              + "(not(derived-from-or-self(../../frequency,"
              + "'schedule:hourly')) or (current() < 360000)) and "
              + "(not(derived-from-or-self(../../frequency,"
              + "'schedule:daily')) or (current() < 8640000)) and "
              + "(not(derived-from-or-self(../../frequency,"
              + "'schedule:weekly')) or (current() < 60480000)) and "
              + "(not(derived-from-or-self(../../frequency,"
              + "'schedule:monthly')) or (current() < 267840000)) and "
              + "(not(derived-from-or-self(../../frequency,"
              + "'schedule:yearly')) or (current() < 3162240000))" {
             error-message
               "The 'period-start' must not exceed the frequency
                interval.";
           }
           description
             "Start time of the schedule within one recurrence.

              Given that the value is in timeticks format
              (i.e., 1/100 of a second), the values in the must
              statement translate to 100 = 1 s (secondly),
              6000 = 60 s = 1 min (minutely), and so on for all
              instances in the must statement invariant.";
         }
         leaf period-end {
           type yang:timeticks;
           description
             "End time of the schedule within one recurrence.
              The period start MUST be no later than the period
              end.";
         }
       }
     }

     grouping recurrence-time-zone-with-periods {
       description
         "This grouping defines an aggregate set of repeating
          occurrences with local time format and time zone specified.
          The recurrence instances are specified by the occurrences
          defined by both the recurrence rule and 'period' list.
          Duplicate instances are ignored.";
       uses recurrence-with-time-zone;
       list period {
         key "period-start";
         description
           "A list of periods with date-and-time formats.";
         uses period-of-time;
       }
     }

     grouping icalendar-recurrence {
       description
         "This grouping specifies properties of a recurrence rule.";
       reference
         "RFC 5545: Internet Calendaring and Scheduling Core Object
                    Specification (iCalendar), Section 3.8.5";
       uses recurrence-time-zone-with-periods;
       leaf-list bysecond {
         type uint32 {
           range "0..60";
         }
         description
           "Specifies a list of seconds within a minute.";
       }
       leaf-list byminute {
         type uint32 {
           range "0..59";
         }
         description
           "Specifies a list of minutes within an hour.";
       }
       leaf-list byhour {
         type uint32 {
           range "0..23";
         }
         description
           "Specifies a list of hours of the day.";
       }
       list byday {
         key "weekday";
         description
           "Specifies a list of days of the week.";
         leaf-list direction {
           when "derived-from-or-self(../../frequency, "
              + "'schedule:monthly') or "
              + "(derived-from-or-self(../../frequency,"
              + "'schedule:yearly') and not(../../byyearweek))";
           type int32 {
             range "-53..-1|1..53";
           }
           description
             "When specified, it indicates the nth occurrence of a
              specific day within the monthly or yearly recurrence
              rule.  For example, within a monthly rule, +1 monday
              represents the first Monday within the month, whereas
              -1 monday represents the last Monday of the month.";
         }
         leaf weekday {
           type schedule:weekday;
           description
             "Corresponds to seven days of the week.";
         }
       }
       leaf-list bymonthday {
         type int32 {
           range "-31..-1|1..31";
         }
         description
           "Specifies a list of days of the month.";
       }
       leaf-list byyearday {
         type int32 {
           range "-366..-1|1..366";
         }
         description
           "Specifies a list of days of the year.";
       }
       leaf-list byyearweek {
         when "derived-from-or-self(../frequency, 'schedule:yearly')";
         type int32 {
           range "-53..-1|1..53";
         }
         description
           "Specifies a list of weeks of the year.";
       }
       leaf-list byyearmonth {
         type uint32 {
           range "1..12";
         }
         description
           "Specifies a list of months of the year.";
       }
       leaf-list bysetpos {
         type int32 {
           range "-366..-1|1..366";
         }
         description
           "Specifies a list of values that corresponds to the nth
            occurrence within the set of recurrence instances
            specified by the rule.  It must only be used in conjunction
            with another 'byxxx' (bysecond, byminute, etc.) rule
            part.";
       }
       leaf workweek-start {
         type schedule:weekday;
         description
           "Specifies the day on which the workweek starts.";
       }
       leaf-list exception-dates {
         type yang:date-and-time;
         description
           "Defines a list of exceptions for recurrence.";
       }
     }

     grouping schedule-status {
       description
         "This grouping defines common properties of scheduling
          status.";
       leaf state {
         type identityref {
           base schedule-state;
         }
         description
           "Indicates the current state of the schedule.";
       }
       leaf version {
         type uint16;
         description
           "Indicates the version number of the schedule.";
       }
       leaf schedule-type {
         type identityref {
           base schedule-type;
         }
         description
           "Indicates the schedule type.";
       }
       leaf local-time {
         type yang:date-and-time;
         config false;
         description
           "Reports the local time as used by the entity that
            hosts the schedule.";
       }
       leaf last-update {
         type yang:date-and-time;
         config false;
         description
           "Reports the timestamp of when the schedule is last
            updated.";
       }
       leaf counter {
         when "derived-from-or-self(../schedule-type, "
            + "'schedule:recurrence')";
         type yang:counter32;
         config false;
         description
           "The number of occurrences while invoking the scheduled
            action successfully.  The count wraps around when it reaches
            the maximum value.";
       }
       leaf last-occurrence {
         when "derived-from-or-self(../schedule-type, "
            + "'schedule:recurrence')";
         type yang:date-and-time;
         config false;
         description
           "Indicates the timestamp of last occurrence.";
       }
       leaf upcoming-occurrence {
         when "derived-from-or-self(../schedule-type, "
            + "'schedule:recurrence')"
            + "and derived-from-or-self(../state, 'schedule:enabled')";
         type yang:date-and-time;
         config false;
         description
           "Indicates the timestamp of next occurrence.";
       }
       leaf last-failed-occurrence {
         when "derived-from-or-self(../schedule-type, "
            + "'schedule:recurrence')";
         type yang:date-and-time;
         config false;
         description
           "Indicates the timestamp of last failed action triggered by
            the schedule.";
       }
       leaf failure-counter {
         when "derived-from-or-self(../schedule-type, "
            + "'schedule:recurrence')";
         type yang:counter32;
         config false;
         description
           "Counts the number of failures while invoking the scheduled
            action.";
       }
     }

     grouping schedule-status-with-time-zone {
       description
         "This grouping defines common properties of scheduling
          status, including timezone.";
       leaf time-zone-identifier {
         type sys:timezone-name;
         config false;
         description
           "Indicates the identifier for the time zone in a time
            zone database.";
       }
       uses schedule-status;
     }

     grouping schedule-status-with-name {
       description
         "This grouping defines common properties of scheduling
          status, including a schedule name.";
       leaf schedule-name {
         type string;
         description
           "The schedule identifier that uniquely identifies a
            schedule within a device, controller, network, etc.
            The unicity scope depends on the implementation.";
       }
       uses schedule-status;
     }
   }
   <CODE ENDS>

7. Security Considerations ๐Ÿ”โœจ

okay bestie, this section is modeled on the template in Section 3.7 of [YANG-GUIDE] ๐Ÿ’…

The "ietf-schedule" YANG module is a data model built to be accessed through YANG-based management protocols, like NETCONF [RFC6241] and RESTCONF [RFC8040]. These YANG-based management protocols (1) have to use a secure transport layer (e.g., SSH [RFC4252], TLS [RFC8446], and QUIC [RFC9000]) and (2) have to use mutual authentication. it's giving locked-down vibes ๐Ÿ”’

The Network Configuration Access Control Model (NACM) [RFC8341] is how you restrict access for particular NETCONF or RESTCONF users to a preconfigured subset of all available NETCONF or RESTCONF protocol operations and content. main character energy for access control ๐Ÿ‘‘

The "ietf-schedule" module defines a set of identities, types, and groupings. these are meant to be reused by other YANG modules ๐Ÿงš The module by itself does not expose any data nodes that are writable, data nodes that contain read-only state, or RPCs. so, as far as the module is concerned, there are no additional security issues related to the "ietf-schedule" module that need to be considered ๐Ÿซถ

Modules that use the groupings defined in this document should identify the corresponding security considerations. ngl this is the part where the reusing modules have to do their homework ๐Ÿ“

For example, reusing the following groupings will expose privacy-related information:

  • Scheduling depends on reliable and accurate time synchronization. Inaccurate date and time setting can lead to scheduling events being triggered at incorrect intervals, potentially causing system failures or security vulnerabilities. โฐ๐Ÿ’€
  • Recurring events may conceal abnormal behavior or security threats, which may be drowned out by normal events, especially when they are triggered frequently. ๐Ÿ™ˆ
  • The absence of detailed logs and audit records of each occurrence trigger time and action results and therefore may make security incidents difficult to trace. ๐Ÿ•ต๏ธโ€โ™€๏ธ
  • Care must be taken when defining recurrences occurring very often and frequent that can be an additional source of attacks by keeping the system permanently busy with the management of scheduling. ๐Ÿ”ฅ this one is lowkey terrifying, bestie

8. IANA Considerations ๐ŸŒธ

8.1. The IETF XML Registry

This document has registered the following URI in the "IETF XML Registry" [RFC3688].

URI:  urn:ietf:params:xml:ns:yang:ietf-schedule
Registrant Contact:  The IESG.
XML:  N/A; the requested URI is an XML namespace.

8.2. The YANG Module Names Registry

This document has registered the following YANG module in the "YANG Module Names" registry [RFC6020].

Name:  ietf-schedule
Maintained by IANA:  N
Namespace:  urn:ietf:params:xml:ns:yang:ietf-schedule
Prefix:  schedule
Reference:  RFC 9922

9. References ๐Ÿ“š๐Ÿฆ‹

9.1. Normative References

[RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
           Requirement Levels", BCP 14, RFC 2119,
           DOI 10.17487/RFC2119, March 1997,
           <https://www.rfc-editor.org/info/rfc2119>.

[RFC3231]  Levi, D. and J. Schoenwaelder, "Definitions of Managed
           Objects for Scheduling Management Operations", RFC 3231,
           DOI 10.17487/RFC3231, January 2002,
           <https://www.rfc-editor.org/info/rfc3231>.

[RFC3688]  Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688,
           DOI 10.17487/RFC3688, January 2004,
           <https://www.rfc-editor.org/info/rfc3688>.

[RFC5545]  Desruisseaux, B., Ed., "Internet Calendaring and
           Scheduling Core Object Specification (iCalendar)",
           RFC 5545, DOI 10.17487/RFC5545, September 2009,
           <https://www.rfc-editor.org/info/rfc5545>.

[RFC6020]  Bjorklund, M., Ed., "YANG - A Data Modeling Language for
           the Network Configuration Protocol (NETCONF)", RFC 6020,
           DOI 10.17487/RFC6020, October 2010,
           <https://www.rfc-editor.org/info/rfc6020>.

[RFC7317]  Bierman, A. and M. Bjorklund, "A YANG Data Model for
           System Management", RFC 7317, DOI 10.17487/RFC7317, August
           2014, <https://www.rfc-editor.org/info/rfc7317>.

[RFC7950]  Bjorklund, M., Ed., "The YANG 1.1 Data Modeling Language",
           RFC 7950, DOI 10.17487/RFC7950, August 2016,
           <https://www.rfc-editor.org/info/rfc7950>.

[RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
           2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
           May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8341]  Bierman, A. and M. Bjorklund, "Network Configuration
           Access Control Model", STD 91, RFC 8341,
           DOI 10.17487/RFC8341, March 2018,
           <https://www.rfc-editor.org/info/rfc8341>.

[RFC9911]  Schรถnwรคlder, J., Ed., "Common YANG Data Types", RFC 9911,
           DOI 10.17487/RFC9911, December 2025,
           <https://www.rfc-editor.org/info/rfc9911>.

9.2. Informative References โœจ

Okay bestie, here are the informative references ๐Ÿ’… They're the extra reading that backs up the spec, so you can go deeper whenever you want ๐Ÿ“š


Appendix A. Examples of Scheduling Format Representation ๐Ÿงš

Okay this appendix is my favourite because it's all examples ๐Ÿคฉ These show the period and recurrence formats from Section 6 in action. The modules below are only there for illustration, but they're written so you can actually check the examples yourself ๐Ÿฆ‹

module example-sch-usage-1 {
  yang-version 1.1;
  namespace "http://example.com/example-sch-usage-1";
  prefix "ex-schu-1";

  import ietf-schedule {
    prefix "schedule";
  }

  organization
    "Example, Inc.";

  contact
    "Support at example.com";

  description
    "Example of a module using 'generic-schedule-params' and
     'schedule-status' groupings.";

  revision "2026-02-20" {
    description "Initial version.";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
  }

  container generic-schedule-params {
    description
      "A collection of generic scheduling parameters.";
    uses schedule:generic-schedule-params;
  }
  container schedule-status {
    description
      "A collection of scheduling status.";
    uses schedule:schedule-status;
  }
}

module example-sch-usage-2 {
  yang-version 1.1;
  namespace "http://example.com/example-sch-usage-2";
  prefix "ex-schu2";

  import ietf-schedule {
    prefix "schedule";
  }

  organization
    "Example, Inc.";

  contact
    "Support at example.com";

  description
    "Example of a module using the 'period-of-time' grouping.";

  revision "2026-02-20" {
    description "Initial version.";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
  }

  container period-of-time {
    description
      "A container for a time period.";
    uses schedule:period-of-time;
  }
}

module example-sch-usage-3 {
  yang-version 1.1;
  namespace "http://example.com/example-sch-usage-3";
  prefix "ex-schu-3";

  import ietf-schedule {
    prefix "schedule";
  }

  organization
    "Example, Inc.";

  contact
    "Support at example.com";

  description
    "Example of a module using the 'recurrence-basic' grouping.";

  revision "2026-02-20" {
    description "Initial version.";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
  }

  container recurrence-basic {
    description
      "A container for a simple recurrence rule.";
    uses schedule:recurrence-basic {
      refine interval {
        default 1;
      }
    }
  }
}

module example-sch-usage-4 {
  yang-version 1.1;
  namespace "http://example.com/example-sch-usage-4";
  prefix "ex-schu-4";

  import ietf-schedule {
    prefix "schedule";
  }

  organization
    "Example, Inc.";

  contact
    "Support at example.com";

  description
    "Example of a module using the 'recurrence-utc' grouping.";

  revision "2026-02-20" {
    description "Initial version.";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
  }

  container recurrence-utc {
    description
      "A container for a simple recurrence rule in UTC format.";
    uses schedule:recurrence-utc;
  }
}

module example-sch-usage-5 {
  yang-version 1.1;
  namespace "http://example.com/example-sch-usage-5";
  prefix "ex-schu-5";

  import ietf-schedule {
    prefix "schedule";
  }

  organization
    "Example, Inc.";

  contact
    "Support at example.com";

  description
    "Example of a module using the 'recurrence-with-time-zone'
     grouping.";

  revision "2026-02-20" {
    description "Initial version.";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
  }

  container recurrence-with-time-zone {
    description
      "A container for a simple recurrence rule with a time zone.";
    uses schedule:recurrence-with-time-zone;
  }
}

module example-sch-usage-6 {
  yang-version 1.1;
  namespace "http://example.com/example-sch-usage-6";
  prefix "ex-schu-6";

  import ietf-schedule {
    prefix "schedule";
  }

  organization
    "Example, Inc.";

  contact
    "Support at example.com";

  description
    "Example of a module using the 'recurrence-utc-with-periods'
     grouping.";

  revision "2026-02-20" {
    description "Initial version.";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
  }

  container recurrence-utc-with-periods {
    description
      "A container for an aggregate set of repeating occurrences in
       UTC format.";
    uses schedule:recurrence-utc-with-periods;
  }
}

module example-sch-usage-7 {
  yang-version 1.1;
  namespace "http://example.com/example-sch-usage-7";
  prefix "ex-schu-8";

  import ietf-schedule {
    prefix "schedule";
  }

  organization
    "Example, Inc.";

  contact
    "Support at example.com";

  description
    "Example of a module using the
     'recurrence-time-zone-with-periods' grouping.";

  revision "2026-02-20" {
    description "Initial version.";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
  }

  container recurrence-time-zone-with-periods {
    description
      "A container for an aggregate set of repeating occurrences
       with a time zone.";
    uses schedule:recurrence-time-zone-with-periods;
  }
}

module example-sch-usage-8 {
  yang-version 1.1;
  namespace "http://example.com/example-sch-usage-8";
  prefix "ex-schu-8";

  import ietf-schedule {
    prefix "schedule";
  }

  organization
    "Example, Inc.";

  contact
    "Support at example.com";

  description
    "Example of a module using 'icalendar-recurrence' grouping.";

  revision "2026-02-20" {
    description "Initial version.";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
  }

  container icalendar-recurrence {
    description
      "A container for a scheduled iCalendar recurrence.";
    uses schedule:icalendar-recurrence {
      refine workweek-start {
        default monday;
      }
    }
  }
}

For each example, only the message body is provided with JSON, which is used for encoding per the guidance in [RFC7951] ๐ŸŽ€ Just the message body, bestie, and the JSON encoding follows the rules in [RFC7951] ๐Ÿ’œ

A.1. The "generic-schedule-params" Grouping โœจ

Okay so Figure 10 is a schedule request that wants to start no earlier than 08:00 AM on January 1, 2025 and end no later than 8:00 PM on January 31, 2025, Beijing time ๐Ÿ‡จ๐Ÿ‡ณ๐ŸŽ€. If a request doesn't meet those rules, the system just ignores it, which is what "discard-action" is for ๐Ÿ’….

{
  "example-sch-usage-1:generic-schedule-params": {
    "time-zone-identifier": "China/Beijing",
    "min-allowed-start": "2025-01-01T08:00:00",
    "max-allowed-end": "2025-01-31T20:00:00",
    "discard-action": "ietf-schedule:silently-discard"
  }
}

Figure 10: Generic Parameters with 'max-allowed-end' for Schedule Validation

Now bestie, the difference between "max-allowed-end" and "validity" is kind of the whole plot ๐Ÿฆ‹. Figure 11 shows a request that only has to start no earlier than 08:00 AM on January 1, 2025 (Beijing time) ๐ŸŒธ. Same deal, if it fails, it gets silently dropped because of "discard-action". The schedule itself is allowed to run past 8:00 PM on January 31, 2025, but any occurrences generated after that time just don't count as valid ๐Ÿ’€. Totally different vibes!

{
  "example-sch-usage-1:generic-schedule-params": {
    "time-zone-identifier": "China/Beijing",
    "validity": "2025-01-31T20:00:00",
    "min-allowed-start": "2025-01-01T08:00:00",
    "discard-action": "ietf-schedule:silently-discard"
  }
}

Figure 11: Generic Parameters with 'validity' for Schedule Validation

A.2. The "period-of-time" Grouping ๐Ÿงš

Figure 12 is a period that starts at 08:00:00 UTC on January 1, 2025 and ends at 18:00:00 UTC on December 31, 2027. Simple, clean, iconic ๐Ÿซถ.

{
  "example-sch-usage-2:period-of-time": {
    "period-start": "2025-01-01T08:00:00Z",
    "period-end": "2027-12-31T18:00:00Z"
  }
}

Figure 12: Simple Start/End Schedule

Next up, a period that starts at 08:00:00 UTC on January 1, 2025 and lasts 15 days, 5 hours and 20 minutes. It's encoded like Figure 13 ๐Ÿ‘‘.

{
  "example-sch-usage-2:period-of-time": {
    "period-start": "2025-01-01T08:00:00Z",
    "duration": "P15DT05:20:00"
  }
}

Figure 13: Simple Schedule with Duration

And then there's a period that starts at 2:00 AM in Los Angeles on November 19, 2025 and lasts 20 weeks. That's Figure 14 ๐ŸŒˆ.

{
  "example-sch-usage-2:period-of-time": {
    "period-start": "2025-11-19T02:00:00",
    "time-zone-identifier": "America/Los_Angeles",
    "duration": "P20W"
  }
}

Figure 14: Simple Schedule with Time Zone Indication

A.3. The "recurrence-basic" Grouping ๐Ÿ“

Figure 15 is a recurrence every 2 days. It starts right away and repeats forever, no cap โ™พ๏ธ.

{
  "example-sch-usage-3:recurrence-basic": {
    "recurrence-description": "forever recurrence rule",
    "frequency": "ietf-schedule:daily",
    "interval": 2
  }
}

Figure 15: Simple Schedule with Recurrence

A.4. The "recurrence-utc" Grouping ๐ŸŒธ

Figure 16 is a recurrence from 8:00 AM to 9:00 AM every day, from December 1 to December 31, 2025, all in UTC โฐ.

{
  "example-sch-usage-4:recurrence-utc": {
    "recurrence-first": {
      "start-time-utc": "2025-12-01T08:00:00Z",
      "duration": 3600
    },
    "frequency": "ietf-schedule:daily",
    "interval": 1,
    "utc-until": "2025-12-31T23:59:59Z"
  }
}

Figure 16: Simple Schedule with Recurrence in UTC

A.5. The "recurrence-with-time-zone" Grouping ๐Ÿ—ฝ

Figure 17 is a recurrence every 2 hours for 10 occurrences. Each one lasts 10 minutes and the whole thing starts at 3 PM on December 1, 2025 in New York ๐Ÿ’….

{
  "example-sch-usage-5:recurrence-with-time-zone": {
    "recurrence-first": {
      "start-time": "2025-12-01T15:00:00",
      "duration": "PT00:10:00"
    },
    "time-zone-identifier": "America/New_York",
    "frequency": "ietf-schedule:hourly",
    "interval": 2,
    "count": 10
  }
}

Figure 17: Simple Schedule with Recurrence with Time Zone Indication

A.6. The "recurrence-utc-with-periods" Grouping ๐Ÿฆ‹

Figure 18 is a recurrence that happens every two days. Each day it starts at 9:00 AM and at 3:00 PM, lasting 30 minutes and 40 minutes respectively, from 2025-06-01 to 2025-06-30, all in UTC ๐ŸŒŠ.

{
  "example-sch-usage-6:recurrence-utc-with-periods": {
    "recurrence-first": {
      "start-time-utc": "2025-06-01T09:00:00Z"
    },
    "frequency": "ietf-schedule:daily",
    "interval": 2,
    "utc-until": "2025-06-30T23:59:59Z",
    "period-timeticks": [
      {
        "period-start": 3240000,
        "period-end": 3420000
      },
      {
        "period-start": 5400000,
        "period-end": 5640000
      }
    ]
  }
}

Figure 18: Example of Recurrence With Date Times

A.7. The "recurrence-time-zone-with-periods" Grouping ๐Ÿ’œ

Figure 19 is giving main character energy. It's a recurrence every 30 minutes, with each occurrence lasting 15 minutes, from 9:00 AM to 5:00 PM on 2025-12-01 (New York) ๐Ÿ—“๏ธ. On top of that, there are two extra occurrences at 6:00 PM and 6:30 PM, each lasting 20 minutes โœจ.

{
  "example-sch-usage-7:recurrence-time-zone-with-periods": {
    "recurrence-first": {
      "start-time": "2025-12-01T09:00:00",
      "duration": "PT00:15:00"
    },
    "time-zone-identifier": "America/New_York",
    "frequency": "ietf-schedule:minutely",
    "interval": 30,
    "until": "2025-12-01T17:00:00Z",
    "period": [
      {
        "period-start": "2025-12-01T18:00:00",
        "duration": "PT00:20:00"
      },
      {
        "period-start": "2025-12-01T18:30:00",
        "duration": "PT00:20:00"
      }
    ]
  }
}

Figure 19: Example of Advanced Recurrence Schedule

A.8. The "icalendar-recurrence" Grouping ๐Ÿ“…

Figure 20 is 10 occurrences at 8:00 AM (EST), every last Saturday of the month, starting in January 2024 ๐Ÿฅน.

{
  "example-sch-usage-8:icalendar-recurrence": {
    "recurrence-first": {
      "start-time": "2024-01-27T08:00:00"
    },
    "time-zone-identifier": "America/New_York",
    "frequency": "ietf-schedule:monthly",
    "count": 10,
    "byday": [
      {
        "direction": [
          -1
        ],
        "weekday": "saturday"
      }
    ]
  }
}

Figure 20: Simple iCalendar Recurrence

Figure 21 is a bit more advanced ๐Ÿค“. It's a recurrence on the last workday of each month, starting January 1, 2025 and running until December 25, 2025.

{
  "example-sch-usage-8:icalendar-recurrence": {
    "recurrence-first": {
      "start-time": "2025-01-01T00:00:00"
    },
    "frequency": "ietf-schedule:monthly",
    "until": "2025-12-25T23:59:59",
    "byday": [
      {
        "weekday": "monday"
      },
      {
        "weekday": "tuesday"
      },
      {
        "weekday": "wednesday"
      },
      {
        "weekday": "thursday"
      },
      {
        "weekday": "friday"
      }
    ],
    "bysetpos": [
      -1
    ]
  }
}

Figure 21: Example of Advanced iCalendar Recurrence

Figure 22 is a recurrence every 20 minutes, from 9:00 AM to 4:40 PM (UTC). The one starting at 10:20 AM on 2025-12-01 gets excluded ๐Ÿ™ˆ.

{
  "example-sch-usage-8:icalendar-recurrence": {
    "recurrence-first": {
      "start-time": "2025-12-01T09:00:00Z"
    },
    "until": "2025-12-01T16:40:00Z",
    "frequency": "ietf-schedule:minutely",
    "byminute": [
      0,
      20,
      40
    ],
    "byhour": [
      9,
      10,
      11,
      12,
      13,
      14,
      15,
      16
    ],
    "exception-dates": [
      "2025-12-01T10:20:00Z"
    ]
  }
}

Figure 22: Example of Advanced iCalendar Recurrence with Exceptions

A.9. The "schedule-status" Grouping ๐Ÿ“Š

Figure 23 shows the scheduled recurrence status of Figure 22 at 12:15 PM on 2025-12-01 (UTC) ๐Ÿซง.

{
  "example-sch-usage-1:schedule-status": {
    "state": "ietf-schedule:enabled",
    "version": 1,
    "schedule-type": "ietf-schedule:recurrence",
    "counter": 9,
    "last-occurrence": "2025-12-01T12:00:00Z",
    "upcoming-occurrence": "2025-12-01T12:20:00Z"
  }
}

Figure 23: Example of a Schedule Status

So at 12:15 PM on 2025-12-01 (UTC), the recurring event had already happened at these times (remember, the 10:20 AM one is excluded): 9:00, 9:20, 9:40, 10:00, 10:40, 11:00, 11:20, 11:40, and 12:00 ๐ŸŽ‰. The last occurrence was at 12:00, and the upcoming one is at 12:20. Counter says 9, and it checks out!! ๐Ÿฅณ


Appendix B. Examples of Using/Extending the "ietf-schedule" Module ๐ŸŽ€

This non-normative section shows two examples of how the "ietf-schedule" module can be used or extended for scheduled events or attributes based on date and time ๐ŸŒท. Not a rule, just vibes and examples bestie ๐Ÿ’–.

B.1. Example: Schedule Tasks to Execute Based on a Recurrence Rule

okay so scheduled tasks are lowkey the best ๐Ÿ—“๏ธโœจ they can run specific actions based on recurrence rules, like every Friday at 8:00 AM. ๐Ÿ’… This example module "uses" the "icalendar-recurrence" grouping from the "ietf-schedule" module, and it shows how a scheduled task can be defined with different features used for options. bestie, it's giving organized ๐Ÿซถ

module example-scheduled-backup {
  yang-version 1.1;
  namespace "http://example.com/example-scheduled-backup";
  prefix "ex-scback";

  import ietf-inet-types {
    prefix "inet";
  }

  import ietf-schedule {
    prefix "schedule";
  }

  organization
    "Example, Inc.";

  contact
    "Support at example.com";

  description
    "Example of a module defining a scheduled-based backup
     operation.";

  revision "2026-02-20" {
    description
      "Initial version.";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
    }

  container scheduled-backup-tasks {
    description
      "A container for backing up all current running configurations
       on the device.";
    list tasks {
      key "task-id";
      description
        "The list of backing up tasks on this device.";
      leaf task-id {
        type string;
        description
          "The task identifier that uniquely identifies a scheduled
           backup task.";
      }
      choice local-or-remote {
        description
          "Specifies whether the configuration to be backed up is
           local or remote.";
        case local {
          description
            "Configuration parameters for the backing up of local
             devices.";
          leaf local {
            type empty;
            description
              "The parameter specifies the configuration to be
               backed up is on the local device.";
          }
        }
        case remote {
          description
            "Configuration parameters for backing up of remote
             devices.";
          leaf remote {
            type inet:domain-name;
            description
              "The parameter specifies the remote device domain
               name.";
          }
        }
      }

      container basic-recurrence-schedules {
        if-feature schedule:basic-recurrence;
        description
          "Basic recurrence schedule specification, which only
           applies when the schedule:basic-recurrence feature
           is supported.";
        leaf schedule-id {
          type string;
          description
            "The schedule identifier for this recurrence rule.";
        }
        uses schedule:recurrence-basic {
          refine frequency {
            mandatory true;
          }
          refine interval {
            default 1;
          }
        }
      }

      container icalendar-recurrence-schedules {
        if-feature schedule:icalendar-recurrence;
        description
          "Basic recurrence schedule specification, which only
           applies when the schedule:icalendar-recurrence feature
           is supported.";
        leaf schedule-id {
          type string;
          description
            "The schedule identifier for this recurrence rule.";
        }
        uses schedule:icalendar-recurrence {
          refine workweek-start {
            default monday;
          }
        }
      }
    }

    list schedule-set {
      key "schedule-name";
      description
        "Schedule status list for the backup tasks.";
      uses schedule:schedule-status-with-name;
    }
  }
}

B.2. Example: Schedule Network Properties to Change Based on Date and Time

network properties can change over a specific period of time or based on a recurrence rule, like in [RFC9657] ๐ŸŒธ this example module augments the "recurrence-utc-with-periods" grouping from the "ietf-schedule" module, so you can see how a scheduled attribute gets defined. ngl it's giving main character energy โœจ also, [RFC8345] and this document are both referenced in the module, so keep that in mind ๐Ÿงš

module example-scheduled-link-bandwidth {
  yang-version 1.1;
  namespace "http://example.com/example-scheduled-link-bandwidth";
  prefix "ex-scattr";

  import ietf-network {
    prefix "nw";
    reference
      "RFC 8345: A YANG Data Model for Network Topologies";
  }

  import ietf-schedule {
    prefix "schedule";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
  }

  organization
    "Example, Inc.";

  contact
    "Support at example.com";

  description
    "Example of a module defining a scheduled link bandwidth.";

  revision "2026-02-20" {
    description
      "Initial version.";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
    }

  grouping link-bandwidth-grouping {
    description
      "Grouping of the link bandwidth definition.";
    leaf scheduled-bandwidth {
      type uint64;
      units "Kbps";
      description
        "Bandwidth values, expressed in kilobits per second.";
    }
  }

  container link-attributes {
    description
      "Definition of link attributes.";
    list link {
      key "source-node destination-node";
      description
        "Definition of link attributes.";
      leaf source-node {
        type nw:node-id;
        description
          "Indicates the source node identifier.";
      }
      leaf destination-node {
        type nw:node-id;
        description
          "Indicates the source node identifier.";
      }

      leaf default-bandwidth {
        type uint64;
        units "Kbps";
        description
          "Bandwidth value used for periods that don't match
           a schedule.";
      }

      choice time-variant-type {
        description
          "Controls the schedule type.";
        case period {
          uses schedule:period-of-time;
        }
        case recurrence {
          uses schedule:recurrence-utc-with-periods {
            augment "period-timeticks" {
              description
                "Specifies the attributes inside each
                 'period-timeticks' entry.";
              uses link-bandwidth-grouping;
            }
          }
        }
      }
    }
  }
}

Figure 24 shows a configuration example in XML [W3C.XML1.0] of a link's bandwidth that is scheduled between 2025-12-01 0:00 UTC to the end of 2025-12-31 with a daily schedule. ๐Ÿ“… each day, the bandwidth is scheduled to be 500 Kbps from 1:00 AM to 6:00 AM, and 800 Kbps from 10:00 PM to 11:00 PM. ๐ŸŒ™ any bandwidth not covered by those periods is 1000 Kbps. iykyk, the math is so clean ๐Ÿฆ‹

<?xml version="1.0" encoding="utf-8"?>
<link-attributes
  xmlns="http://example.com/example-scheduled-link-bandwidth"
  xmlns:schedule="urn:ietf:params:xml:ns:yang:ietf-schedule">
  <link>
    <source-node>ne1</source-node>
    <destination-node>ne2</destination-node>
    <default-bandwidth>1000</default-bandwidth>
    <recurrence-first>
      <start-time-utc>2025-12-01T01:00:00Z</start-time-utc>
    </recurrence-first>
    <frequency>schedule:daily</frequency>
    <utc-until>2025-12-31T23:59:59Z</utc-until>
    <period-timeticks>
      <period-start>360000</period-start>
      <period-end>2160000</period-end>
      <scheduled-bandwidth>500</scheduled-bandwidth>
    </period-timeticks>
    <period-timeticks>
      <period-start>7920000</period-start>
      <period-end>8280000</period-end>
      <scheduled-bandwidth>800</scheduled-bandwidth>
    </period-timeticks>
  </link>
</link-attributes>

Figure 24: Example of Scheduled Link's Bandwidth


Appendix C. Examples of Using the "ietf-schedule" Module for Scheduled Use of Resources Framework

this section shows how the architecture for supporting scheduled reservation of Traffic Engineering (TE) resources in [RFC8413] might use the "period-of-time" grouping from the "ietf-schedule" module to implement scheduled use of resources. ๐ŸŽ€ the following example module shows how a scheduled link capacity reservation could be defined.

module example-sch-capacity-res {
  yang-version 1.1;
  namespace "http://example.com/example-sch-capacity-res";
  prefix "ex-schecaparev";

  import ietf-network-topology {
    prefix "nt";
  }

  import ietf-schedule {
    prefix "schedule";
  }

  organization
    "Example, Inc.";

  contact
    "Support at example.com";

  description
    "An example to show a scheduled link capacity reservation.";

  revision "2026-02-20" {
    description
      "Initial version.";
    reference
      "RFC 9922: A YANG Data Model for Scheduling";
  }

  container link-capability-reservations {
    description
      "A container for a scheduled link capability reservations.";
    list scheduled-link-capacity {
      key "schedule-id";
      description
        "Definition of scheduled link capacity list.";
      leaf schedule-id {
        type string;
        description
          "The schedule identifier for this schedule rule.";
      }
      leaf link-id {
        type nt:link-id;
        description
          "The identifier of a link in the topology.";
      }
      leaf reserved-capability {
        type uint64;
        units "Mbps";
        description
          "The reserved capability for a particular link.";
      }
      uses schedule:period-of-time;
    }
  }
}

Section 4 of [RFC8413] defines the reference architecture for scheduled use of resources. ๐Ÿง  the service requester sends a request to a Path Computation Element (PCE) and includes the parameters of the Label Switched Path (LSP) that the requester wants to supply. the configuration example for the scheduled resource is shown in Figure 25 ๐Ÿ’–

<?xml version="1.0" encoding="utf-8"?>
<link-capability-reservations
  xmlns="http://example.com/example-sch-capacity-res"
  xmlns:schedule="urn:ietf:params:xml:ns:yang:ietf-schedule">
   <scheduled-link-capacity>
      <schedule-id>1</schedule-id>
      <link-id>1-2-1</link-id>
      <reserved-capability>500</reserved-capability>
      <period-start>2025-03-10T08:00:00Z</period-start>
      <period-end>2025-03-10T09:00:00Z</period-end>
   </scheduled-link-capacity>
   <scheduled-link-capacity>
      <schedule-id>2</schedule-id>
      <link-id>2-1-1</link-id>
      <reserved-capability>400</reserved-capability>
      <period-start>2025-04-01T00:00:00Z</period-start>
      <duration>PT09:00:00</duration>
   </scheduled-link-capacity>
   <scheduled-link-capacity>
      <schedule-id>3</schedule-id>
      <link-id>2-1-1</link-id>
      <reserved-capability>500</reserved-capability>
      <period-start>2025-04-01T09:00:00Z</period-start>
      <period-end>2025-04-01T23:59:59Z</period-end>
   </scheduled-link-capacity>
</link-capability-reservations>

Figure 25: Example of Scheduled Link's Bandwidth Reservation

Acknowledgments ๐Ÿ™โœจ

Okay so this work is derived from [YANG-NAC] ๐Ÿงš. There's a real desire from the OPSAWG ๐Ÿ’œ to see this module defined separately so it can be used widely in a scheduling context.

Huge thanks to Adrian Farrel, Wei Pan, Tianran Zhou, Joe Clarke, Steve Baillargeon, Dhruv Dhody, Robert Wilton, and Italo Busi for their valuable comments and inputs ๐Ÿซถ.

Many thanks to the authors of [YANG-SCHEDULE], [YANG-OAM], and [NETMOD-ECA-POLICY] for the constructive discussion during IETF#118 ๐Ÿ’….

Other related efforts were explored in the past, e.g., [YANG-CONFIG-SCHEDULE] ๐Ÿฆ‹.

Thanks to Reshad Rahman for the great YANG Doctors review, Mahesh Jethanandani for the AD review, Per Andersson for the OPSDIR review, Peter Yee for the GENART review, and Acee Lindem for the RTGDIR review ๐Ÿ‘‘.

Thanks to ร‰ric Vyncke, Erik Kline, and Mike Bishop for the IESG review ๐ŸŒˆ.

Authors' Addresses ๐ŸŽ€

Qiufang Ma (editor) Huawei 101 Software Avenue, Yuhua District Jiangsu 210012 China Email: maqiufang1@huawei.com

Qin Wu Huawei 101 Software Avenue, Yuhua District Jiangsu 210012 China Email: bill.wu@huawei.com

Mohamed Boucadair (editor) Orange 35000 Rennes France Email: mohamed.boucadair@orange.com

Daniel King Lancaster University United Kingdom Email: d.king@lancaster.ac.uk


That's the whole thing, bestie! ๐ŸŒธ๐Ÿ’–

๐Ÿ“ฆ where this page comes from