diff --git a/gtfs-realtime/best-practices/best-practices.md b/gtfs-realtime/best-practices/best-practices.md index 3e577946..4956a1b5 100644 --- a/gtfs-realtime/best-practices/best-practices.md +++ b/gtfs-realtime/best-practices/best-practices.md @@ -71,6 +71,10 @@ If separate `VehiclePosition` and `TripUpdate` feeds are provided, [TripDescript For example, a `VehiclePosition` entity has `vehicle_id:A` and `trip_id:4`, then the corresponding `TripUpdate` entity should also have `vehicle_id:A` and `trip_id:4`. +| Field Name | Recommendation | +| --- | --- | +| `schedule_relationship` | The behavior of `ADDED` trips are unspecified and the use of this enumeration is not recommended. | + ### VehicleDescriptor If separate `VehiclePosition` and `TripUpdate` feeds are provided, [TripDescriptor](#TripDescriptor) and [VehicleDescriptor](#VehicleDescriptor) ID values pairing should match between the two feeds. diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index 4563e5a9..28684a3b 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -190,7 +190,7 @@ message TripUpdate { // To specify a completely certain prediction, set its uncertainty to 0. optional int32 uncertainty = 3; - // Scheduled time for an added or replacement trip. + // Scheduled time for a new or replacement trip. // In Unix time (i.e., number of seconds since January 1st 1970 00:00:00 // UTC). optional int64 scheduled_time = 4; @@ -832,8 +832,10 @@ message TripDescriptor { // enough to the scheduled trip to be associated with it. SCHEDULED = 0; - // An extra trip unrelated to any existing trips, for example, to respond to sudden passenger load. - ADDED = 1; + // This value has been deprecated as the behavior was unspecified. + // Use DUPLICATED for an extra trip that is the same as a scheduled trip except the start date or time, + // or NEW for an extra trip that is unrelated to an existing trip. + ADDED = 1 [deprecated = true]; // A trip that is running with no schedule associated to it (GTFS frequencies.txt exact_times=0). // Trips with ScheduleRelationship=UNSCHEDULED must also set all StopTimeUpdates.ScheduleRelationship=UNSCHEDULED. @@ -873,6 +875,10 @@ message TripDescriptor { // real-time predictions. // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. DELETED = 7; + + // An extra trip unrelated to any existing trips, for example, to respond to sudden passenger load. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. + NEW = 8; } optional ScheduleRelationship schedule_relationship = 4; diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 24328383..1503b428 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -165,7 +165,7 @@ Note that the update can describe a trip that has already completed.To this end, |------------------|------------|----------------|-------------------|-------------------| | **trip** | [TripDescriptor](#message-tripdescriptor) | Required | One | The Trip that this message applies to. There can be at most one TripUpdate entity for each actual trip instance. If there is none, that means there is no prediction information available. It does *not* mean that the trip is progressing according to schedule. | | **vehicle** | [VehicleDescriptor](#message-vehicledescriptor) | Optional | One | Additional information on the vehicle that is serving this trip. | -| **stop_time_update** | [StopTimeUpdate](#message-stoptimeupdate) | Conditionally required | Many | Updates to StopTimes for the trip (both future, i.e., predictions, and in some cases, past ones, i.e., those that already happened). The updates must be sorted by stop_sequence, and apply for all the following stops of the trip up to the next specified stop_time_update.
If trip.schedule_relationship is SCHEDULED, at least one stop_time_update must be provided for the trip.
If trip.schedule_relationship is ADDED or REPLACEMENT, stop_time_updates must be provided for all stops in the added or replacement trip, including stops with times in the past, and the stop times in the static GTFS are not used.
If the trip is canceled or deleted, no stop_time_updates need to be provided. If stop_time_updates are provided for a canceled or deleted trip then the trip.schedule_relationship takes precedence over any stop_time_updates and their associated schedule_relationship. If the trip is duplicated, stop_time_updates may be provided to indicate real-time information for the new trip. | +| **stop_time_update** | [StopTimeUpdate](#message-stoptimeupdate) | Conditionally required | Many | Updates to StopTimes for the trip (both future, i.e., predictions, and in some cases, past ones, i.e., those that already happened). The updates must be sorted by stop_sequence, and apply for all the following stops of the trip up to the next specified stop_time_update.
If trip.schedule_relationship is SCHEDULED, at least one stop_time_update must be provided for the trip.
If trip.schedule_relationship is NEW or REPLACEMENT, stop_time_updates must be provided for all stops in the new or replacement trip, including stops with times in the past, and the stop times in the static GTFS are not used.
If the trip is canceled or deleted, no stop_time_updates need to be provided. If stop_time_updates are provided for a canceled or deleted trip then the trip.schedule_relationship takes precedence over any stop_time_updates and their associated schedule_relationship. If the trip is duplicated, stop_time_updates may be provided to indicate real-time information for the new trip. | | **timestamp** | [uint64](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The most recent moment at which the vehicle's real-time progress was measured to estimate StopTimes in the future. When StopTimes in the past are provided, arrival/departure times may be earlier than this value. In POSIX time (i.e., the number of seconds since January 1st 1970 00:00:00 UTC). | | **delay** | [int32](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The current schedule deviation for the trip. Delay should only be specified when the prediction is given relative to some existing schedule in GTFS.
Delay (in seconds) can be positive (meaning that the vehicle is late) or negative (meaning that the vehicle is ahead of schedule). Delay of 0 means that the vehicle is exactly on time.
Delay information in StopTimeUpdates take precedent of trip-level delay information, such that trip-level delay is only propagated until the next stop along the trip with a StopTimeUpdate delay value specified.
Feed providers are strongly encouraged to provide a TripUpdate.timestamp value indicating when the delay value was last updated, in order to evaluate the freshness of the data.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future.| | **trip_properties** | [TripProperties](#message-tripproperties) | Optional | One | Provides the updated properties for the trip.

**Caution:** this message is still **experimental**, and subject to change. It may be formally adopted in the future. | @@ -175,8 +175,8 @@ Note that the update can describe a trip that has already completed.To this end, Timing information for a single predicted event (either arrival or departure). Timing consists of delay and/or estimated time, and uncertainty. A scheduled time can also be added for added, replacement or duplicated trips. * delay should be used when the prediction is given relative to some existing schedule in GTFS. -* time should be given whether there is a predicted schedule or not, and must be given for added or replacement trips. If both time and delay are specified, time will take precedence (although normally, time, if given for a scheduled trip, should be equal to scheduled time in GTFS + delay). -* scheduled time may be given if the trip is an added, replacement or duplicated trip. +* time should be given whether there is a predicted schedule or not, and must be given for new or replacement trips. If both time and delay are specified, time will take precedence (although normally, time, if given for a scheduled trip, should be equal to scheduled time in GTFS + delay). +* scheduled time may be given if the trip is a new, replacement or duplicated trip. Uncertainty applies equally to both time and delay. The uncertainty roughly specifies the expected error in true delay (but note, we don't yet define its precise statistical meaning). It's possible for the uncertainty to be 0, for example for trains that are driven under computer timing control. @@ -185,27 +185,27 @@ Uncertainty applies equally to both time and delay. The uncertainty roughly spec | _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | |------------------|------------|----------------|-------------------|-------------------| | **delay** | [int32](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Delay (in seconds) can be positive (meaning that the vehicle is late) or negative (meaning that the vehicle is ahead of schedule). Delay of 0 means that the vehicle is exactly on time.
**Forbidden** if StopTimeUpdate.schedule_relationship is NO_DATA.
**Required** otherwise if delay is not given. | -| **time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Estimated or actual event as absolute time. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC).
**Forbidden** if StopTimeUpdate.schedule_relationship is NO_DATA.
**Required** otherwise if time is not given. | -| **scheduled_time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally forbidden | One | Scheduled time. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC).
**Optional** if TripUpdate.schedule_relationship is ADDED, REPLACEMENT or DUPLICATED, **forbidden** otherwise. | +| **time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Estimated or actual event as absolute time. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC).
**Forbidden** if StopTimeUpdate.schedule_relationship is NO_DATA.
**Required** otherwise if time is not given. | +| **scheduled_time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally forbidden | One | Scheduled time. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC).
**Optional** if TripUpdate.schedule_relationship is NEW, REPLACEMENT or DUPLICATED, **forbidden** otherwise. | | **uncertainty** | [int32](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | If uncertainty is omitted, it is interpreted as unknown. To specify a completely certain prediction, set its uncertainty to 0.
**Forbidden** if StopTimeUpdate.schedule_relationship is NO_DATA. | ## _message_ StopTimeUpdate Realtime update for arrival and/or departure events for a given stop on a trip. Please also refer to the general discussion of stop time updates in the [TripDescriptor](#message-tripdescriptor) and [trip updates entities](trip-updates.md) documentation. -Updates can be supplied for both past and future events. The producer is allowed, although not required, to drop past events, unless if `TripUpdate.schedule_relationship` is ADDED or REPLACEMENT, in such case past stops must not be dropped as they define the trip the vehicle is on, until the whole trip has been finished. +Updates can be supplied for both past and future events. The producer is allowed, although not required, to drop past events, unless if `TripUpdate.schedule_relationship` is NEW or REPLACEMENT, in such case past stops must not be dropped as they define the trip the vehicle is on, until the whole trip has been finished. The update is linked to a specific stop either through stop_sequence or stop_id, so one of these fields must necessarily be set. If the same stop_id is visited more than once in a trip, then stop_sequence should be provided in all StopTimeUpdates for that stop_id on that trip. -In added or replacement trips, updates are used to specify the stops visited by the trip without referring to an existing trip in the GTFS Static. In such trips, `stop_id`, `stop_sequence`, `departure` and `arrival` must all be set. +In new or replacement trips, updates are used to specify the stops visited by the trip without referring to an existing trip in the GTFS Static. In such trips, `stop_id`, `stop_sequence`, `departure` and `arrival` must all be set. **Fields** | _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | |------------------|------------|----------------|-------------------|-------------------| -| **stop_sequence** | [uint32](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Must be the same as in stop_times.txt in the corresponding GTFS feed. Either stop_sequence or stop_id must be provided within a StopTimeUpdate - both fields cannot be empty. stop_sequence is required for trips that visit the same stop_id more than once (e.g., a loop) to disambiguate which stop the prediction is for. If `StopTimeProperties.assigned_stop_id` is populated, then `stop_sequence` must be populated. **Required** if `TripUpdate.schedule_relationship` is ADDED or REPLACEMENT, and the value must be increasing along the trip. | -| **stop_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Must be the same as in stops.txt in the corresponding GTFS feed. Either stop_sequence or stop_id must be provided within a StopTimeUpdate - both fields cannot be empty. If `StopTimeProperties.assigned_stop_id` is populated, it is preferred to omit `stop_id` and use only `stop_sequence`. If `StopTimeProperties.assigned_stop_id` and `stop_id` are populated, `stop_id` must match `assigned_stop_id`. **Required** if `TripUpdate.schedule_relationship` is ADDED or REPLACEMENT. | -| **arrival** | [StopTimeEvent](#message-stoptimeevent) | Conditionally required | One | If schedule_relationship is empty or SCHEDULED, either arrival or departure must be provided within a StopTimeUpdate - both fields cannot be empty. arrival and departure may both be empty when schedule_relationship is SKIPPED. **Required** if `TripUpdate.schedule_relationship` is ADDED or REPLACEMENT. | -| **departure** | [StopTimeEvent](#message-stoptimeevent) | Conditionally required | One | If schedule_relationship is empty or SCHEDULED, either arrival or departure must be provided within a StopTimeUpdate - both fields cannot be empty. arrival and departure may both be empty when schedule_relationship is SKIPPED. **Required** if `TripUpdate.schedule_relationship` is ADDED or REPLACEMENT. | +| **stop_sequence** | [uint32](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Must be the same as in stop_times.txt in the corresponding GTFS feed. Either stop_sequence or stop_id must be provided within a StopTimeUpdate - both fields cannot be empty. stop_sequence is required for trips that visit the same stop_id more than once (e.g., a loop) to disambiguate which stop the prediction is for. If `StopTimeProperties.assigned_stop_id` is populated, then `stop_sequence` must be populated. **Required** if `TripUpdate.schedule_relationship` is NEW or REPLACEMENT, and the value must be increasing along the trip. | +| **stop_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Must be the same as in stops.txt in the corresponding GTFS feed. Either stop_sequence or stop_id must be provided within a StopTimeUpdate - both fields cannot be empty. If `StopTimeProperties.assigned_stop_id` is populated, it is preferred to omit `stop_id` and use only `stop_sequence`. If `StopTimeProperties.assigned_stop_id` and `stop_id` are populated, `stop_id` must match `assigned_stop_id`. **Required** if `TripUpdate.schedule_relationship` is NEW or REPLACEMENT. | +| **arrival** | [StopTimeEvent](#message-stoptimeevent) | Conditionally required | One | If schedule_relationship is empty or SCHEDULED, either arrival or departure must be provided within a StopTimeUpdate - both fields cannot be empty. arrival and departure may both be empty when schedule_relationship is SKIPPED. **Required** if `TripUpdate.schedule_relationship` is NEW or REPLACEMENT. | +| **departure** | [StopTimeEvent](#message-stoptimeevent) | Conditionally required | One | If schedule_relationship is empty or SCHEDULED, either arrival or departure must be provided within a StopTimeUpdate - both fields cannot be empty. arrival and departure may both be empty when schedule_relationship is SKIPPED. **Required** if `TripUpdate.schedule_relationship` is NEW or REPLACEMENT. | | **departure_occupancy_status** | [OccupancyStatus](#enum-occupancystatus) | Optional | One | The predicted state of passenger occupancy for the vehicle immediately after departure from the given stop. If provided, stop_sequence must be provided. To provide departure_occupancy_status without providing any real-time arrival or departure predictions, populate this field and set StopTimeUpdate.schedule_relationship = NO_DATA.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | | **schedule_relationship** | [ScheduleRelationship](#enum-schedulerelationship) | Optional | One | The default relationship is SCHEDULED. | | **stop_time_properties** | [StopTimeProperties](#message-stoptimeproperties) | Optional | One | Realtime updates for certain properties defined within GTFS stop_times.txt

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | @@ -220,7 +220,7 @@ The relation between this StopTime and the static schedule. |-------------|---------------| | **SCHEDULED** | The vehicle is proceeding in accordance with its static schedule of stops, although not necessarily according to the times of the schedule. This is the **default** behavior. At least one of arrival and departure must be provided. Frequency-based trips (GTFS frequencies.txt with exact_times = 0) should not have a SCHEDULED value and should use UNSCHEDULED instead. | | **SKIPPED** | The stop is skipped, i.e., the vehicle will not stop at this stop. Arrival and departure are optional. When set `SKIPPED` is not propagated to subsequent stops in the same trip (i.e., the vehicle will stop at subsequent stops in the trip unless those stops also have a `stop_time_update` with `schedule_relationship: SKIPPED`). Delay from a previous stop in the trip *does* propagate over the `SKIPPED` stop. In other words, if a `stop_time_update` with an `arrival` or `departure` prediction is not set for a stop after the `SKIPPED` stop, the prediction upstream of the `SKIPPED` stop will be propagated to the stop after the `SKIPPED` stop and subsequent stops in the trip until a `stop_time_update` for a subsequent stop is provided. | -| **NO_DATA** | No real-time data is given for this stop. It indicates that there is no realtime timing information available. When set NO_DATA is propagated through subsequent stops so this is the recommended way of specifying from which stop you do not have realtime timing information. When NO_DATA is set, arrival or departure must not be supplied, unless `TripDescriptor.schedule_relationship` is `ADDED` or `REPLACEMENT`, in such case only the scheduled time, but not predictions, must be supplied. When `TripDescriptor.schedule_relationship` is `ADDED` or `REPLACEMENT`, `arrival` and `departure` must still be given with scheduled times, as the StopTimeUpdate defines the stop list of the trip. In this case it indicates that the schedule is added or modified, but real-time prediction is not available yet. | +| **NO_DATA** | No real-time data is given for this stop. It indicates that there is no realtime timing information available. When set NO_DATA is propagated through subsequent stops so this is the recommended way of specifying from which stop you do not have realtime timing information. When NO_DATA is set, arrival or departure must not be supplied, unless `TripDescriptor.schedule_relationship` is `NEW` or `REPLACEMENT`, in such case only the scheduled time, but not predictions, must be supplied. When `TripDescriptor.schedule_relationship` is `NEW` or `REPLACEMENT`, `arrival` and `departure` must still be given with scheduled times, as the StopTimeUpdate defines the stop list of the trip. In this case it indicates that the schedule is unrelated to the static GTFS, but real-time prediction is not available yet. | | **UNSCHEDULED** | The vehicle is operating a frequency-based trip (GTFS frequencies.txt with exact_times = 0). This value should not be used for trips that are not defined in GTFS frequencies.txt, or trips in GTFS frequencies.txt with exact_times = 1. Trips containing `stop_time_updates` with `schedule_relationship: UNSCHEDULED` must also set the TripDescriptor `schedule_relationship: UNSCHEDULED`

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. ## _message_ StopTimeProperties @@ -459,7 +459,7 @@ A geographic position of a vehicle. ## _message_ TripDescriptor -A descriptor that identifies a single instance of a GTFS trip, unless `schedule_relationship` is `ADDED`, in such case, it specifies a new instance of trip to be added. +A descriptor that identifies a single instance of a GTFS trip, unless `schedule_relationship` is `NEW`, in such case, it specifies a new instance of trip to be added. To specify a single trip instance, in many cases a `trip_id` by itself is sufficient. However, the following cases require additional information to resolve to a single trip instance: @@ -475,14 +475,14 @@ Note that if the trip_id is not known, then station sequence ids in TripUpdate a TripDescriptor.route_id cannot be used within an Alert EntitySelector to specify a route-wide alert that affects all trips for a route - use EntitySelector.route_id instead. -If `schedule_relationship` is `ADDED`, `trip_id` must be set to a value not exist in the GTFS feed, and `route_id` must be set to a value listed in `routes.txt` in the GTFS static, to associate the trip to a route. `start_date` should be set, and `direction_id` may be set for the new trip. +If `schedule_relationship` is `NEW`, `trip_id` must be set to a value not exist in the GTFS feed, and `route_id` must be set to a value listed in `routes.txt` in the GTFS static, to associate the trip to a route. `start_date` should be set, and `direction_id` may be set for the new trip. **Fields** | _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | |------------------|------------|----------------|-------------------|-------------------| -| **trip_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | The trip_id from the GTFS feed that this selector refers to. For non frequency-based trips (trips not defined in GTFS frequencies.txt), this field is enough to uniquely identify the trip. For frequency-based trips defined in GTFS frequencies.txt, trip_id, start_time, and start_date are all required. For scheduled-based trips (trips not defined in GTFS frequencies.txt), trip_id can only be omitted if the trip can be uniquely identified by a combination of route_id, direction_id, start_time, and start_date, and all those fields are provided. When schedule_relationship is ADDED, it must be specified with a unique value not exist in the GTFS static, When schedule_relationship is DUPLICATED within a TripUpdate, the trip_id identifies the trip from static GTFS to be duplicated. When schedule_relationship is DUPLICATED within a VehiclePosition, the trip_id identifies the new duplicate trip and must contain the value for the corresponding TripUpdate.TripProperties.trip_id. | -| **route_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | The route_id from the GTFS that this selector refers to. If trip_id is omitted, route_id, direction_id, start_time, and schedule_relationship=SCHEDULED must all be set to identify a trip instance. TripDescriptor.route_id should not be used within an Alert EntitySelector to specify a route-wide alert that affects all trips for a route - use EntitySelector.route_id instead. When schedule_relationship is ADDED, route_id must be specified for route which the added trip belongs to. | +| **trip_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | The trip_id from the GTFS feed that this selector refers to. For non frequency-based trips (trips not defined in GTFS frequencies.txt), this field is enough to uniquely identify the trip. For frequency-based trips defined in GTFS frequencies.txt, trip_id, start_time, and start_date are all required. For scheduled-based trips (trips not defined in GTFS frequencies.txt), trip_id can only be omitted if the trip can be uniquely identified by a combination of route_id, direction_id, start_time, and start_date, and all those fields are provided. When schedule_relationship is NEW, it must be specified with a unique value not exist in the GTFS static, When schedule_relationship is DUPLICATED within a TripUpdate, the trip_id identifies the trip from static GTFS to be duplicated. When schedule_relationship is DUPLICATED within a VehiclePosition, the trip_id identifies the new duplicate trip and must contain the value for the corresponding TripUpdate.TripProperties.trip_id. | +| **route_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | The route_id from the GTFS that this selector refers to. If trip_id is omitted, route_id, direction_id, start_time, and schedule_relationship=SCHEDULED must all be set to identify a trip instance. TripDescriptor.route_id should not be used within an Alert EntitySelector to specify a route-wide alert that affects all trips for a route - use EntitySelector.route_id instead. When schedule_relationship is NEW, route_id must be specified for route which the new trip belongs to. | | **direction_id** | [uint32](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | The direction_id from the GTFS feed trips.txt file, indicating the direction of travel for trips this selector refers to. If trip_id is omitted, direction_id must be provided.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future.
| | **start_time** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | The initially scheduled start time of this trip instance. When the trip_id corresponds to a non-frequency-based trip, this field should either be omitted or be equal to the value in the GTFS feed. When the trip_id correponds to a frequency-based trip defined in GTFS frequencies.txt, start_time is required and must be specified for trip updates and vehicle positions. If the trip corresponds to exact_times=1 GTFS record, then start_time must be some multiple (including zero) of headway_secs later than frequencies.txt start_time for the corresponding time period. If the trip corresponds to exact_times=0, then its start_time may be arbitrary, and is initially expected to be the first departure of the trip. Once established, the start_time of this frequency-based exact_times=0 trip should be considered immutable, even if the first departure time changes -- that time change may instead be reflected in a StopTimeUpdate. If trip_id is omitted, start_time must be provided. Format and semantics of the field is same as that of GTFS/frequencies.txt/start_time, e.g., 11:15:35 or 25:15:35. | | **start_date** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | The start date of this trip instance in YYYYMMDD format. For scheduled trips (trips not defined in GTFS frequencies.txt), this field must be provided to disambiguate trips that are so late as to collide with a scheduled trip on a next day. For example, for a train that departs 8:00 and 20:00 every day, and is 12 hours late, there would be two distinct trips on the same time. This field can be provided but is not mandatory for schedules in which such collisions are impossible - for example, a service running on hourly schedule where a vehicle that is one hour late is not considered to be related to schedule anymore. This field is required for frequency-based trips defined in GTFS frequencies.txt. If trip_id is omitted, start_date must be provided. | @@ -491,18 +491,19 @@ If `schedule_relationship` is `ADDED`, `trip_id` must be set to a value not exis ## _enum_ ScheduleRelationship -The relation between this trip and the static schedule. If a new trip is done in accordance with temporary schedule, not reflected in GTFS, then it shouldn't be marked as SCHEDULED, but marked as ADDED. If a trip is done in accordance with a modified schedule, not reflected in GTFS, then it shouldn't be marked as SCHEDULED, but marked as REPLACEMENT. +The relation between this trip and the static schedule. If a new trip is done in accordance with temporary schedule, not reflected in GTFS, then it shouldn't be marked as SCHEDULED, but marked as NEW. If a trip is done in accordance with a modified schedule, not reflected in GTFS, then it shouldn't be marked as SCHEDULED, but marked as REPLACEMENT. **Values** | _**Value**_ | _**Comment**_ | |-------------|---------------| | **SCHEDULED** | Trip that is running in accordance with its GTFS schedule, or is close enough to the scheduled trip to be associated with it. | -| **ADDED** | An extra trip unrelated to any existing trips, for example, to respond to sudden passenger load. The complete journey of the added trip, including all stops and times, must be specified via `StopTimeUpdate`s. | +| **ADDED** | *NOTE: This value has been deprecated as the behavior was unspecified. Use **DUPLICATED** for an extra trip that is the same as a scheduled trip except the start date or time, or **NEW** for an extra trip that is unrelated to an existing trip.* | | **UNSCHEDULED** | A trip that is running with no schedule associated to it - this value is used to identify trips defined in GTFS frequencies.txt with exact_times = 0. It should not be used to describe trips not defined in GTFS frequencies.txt, or trips in GTFS frequencies.txt with exact_times = 1. Trips with `schedule_relationship: UNSCHEDULED` must also set all StopTimeUpdates `schedule_relationship: UNSCHEDULED`| | **CANCELED** | A trip that existed in the schedule but was removed. | | **REPLACEMENT** | A trip that replaces an existing scheduled trip, for example, with a changed schedule or a diverted route. The complete journey of the replacement trip must be specified via `StopTimeUpdate`s, and the original schedule from the GTFS static isn't used for the replaced instance.
`REPLACEMENT` can be used if the trip is operating on a revised schedule, but must not be used to communicate real-time schedule deviations (predictions) if the vehicle is aimed to follow the schedule listed in `stop_times.txt` the static GTFS. | | **DUPLICATED** | A new trip that is the same as an existing scheduled trip except for service start date and time. Used with `TripUpdate.TripProperties.trip_id`, `TripUpdate.TripProperties.start_date`, and `TripUpdate.TripProperties.start_time` to copy an existing trip from static GTFS but start at a different service date and/or time. Duplicating a trip is allowed if the service related to the original trip in (CSV) GTFS (in `calendar.txt` or `calendar_dates.txt`) is operating within the next 30 days. The trip to be duplicated is identified via `TripUpdate.TripDescriptor.trip_id`.

This enumeration does not modify the existing trip referenced by `TripUpdate.TripDescriptor.trip_id` - if a producer wants to cancel the original trip, it must publish a separate `TripUpdate` with the value of CANCELED. Trips defined in GTFS `frequencies.txt` with `exact_times` that is empty or equal to `0` cannot be duplicated. The `VehiclePosition.TripDescriptor.trip_id` for the new trip must contain the matching value from `TripUpdate.TripProperties.trip_id` and `VehiclePosition.TripDescriptor.ScheduleRelationship` must also be set to `DUPLICATED`.

*Existing producers and consumers that were using the ADDED enumeration to represent duplicated trips must follow the [migration guide](/gtfs-realtime/spec/en/examples/migration-duplicated.md) to transition to the DUPLICATED enumeration.* | +| **NEW** | An extra trip unrelated to any existing trips, for example, to respond to sudden passenger load. The complete journey of the new trip, including all stops and times, must be specified via `StopTimeUpdate`s.

*Existing producers and consumers that were using the ADDED enumeration to represent new trips unrelated to the static GTFS must follow the [migration guide](/gtfs-realtime/spec/en/examples/migration-new.md) to transition to the NEW enumeration.*

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | | **DELETED** | A trip that existed in the schedule but was removed that must not be shown to users.

DELETED should be used instead of CANCELED to indicate that a transit provider would like to entirely remove information about the corresponding trip from consuming applications, so the trip is not shown as cancelled to riders, e.g. a trip that is entirely being replaced by another trip. This designation becomes particularly important if several trips are cancelled and replaced with substitute service. If consumers were to show explicit information about the cancellations it would distract from the more important real-time predictions.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | ## _message_ ModifiedTripSelector diff --git a/gtfs-realtime/spec/en/trip-updates.md b/gtfs-realtime/spec/en/trip-updates.md index 79cc9748..05c5909e 100644 --- a/gtfs-realtime/spec/en/trip-updates.md +++ b/gtfs-realtime/spec/en/trip-updates.md @@ -10,7 +10,7 @@ If a vehicle is serving multiple trips within the same block (for more informati ## StopTimeUpdate -A trip update consists of one or more updates to vehicle stop times, which are referred to as [StopTimeUpdates](reference.md#message-stoptimeupdate). These can be supplied for past and future stop times. You are allowed, but not required, to drop past stop times, unless the trip is an added or replacement trip not found in the GTFS static. Producers should not drop a past `StopTimeUpdate` if it refers to a stop with a scheduled arrival time in the future for the given trip (i.e. the vehicle has passed the stop ahead of schedule), as otherwise it will be concluded that there is no update for this stop. +A trip update consists of one or more updates to vehicle stop times, which are referred to as [StopTimeUpdates](reference.md#message-stoptimeupdate). These can be supplied for past and future stop times. You are allowed, but not required, to drop past stop times, unless the trip is a new or replacement trip not found in the GTFS static. Producers should not drop a past `StopTimeUpdate` if it refers to a stop with a scheduled arrival time in the future for the given trip (i.e. the vehicle has passed the stop ahead of schedule), as otherwise it will be concluded that there is no update for this stop. For example, if the following data appears in the GTFS-rt feed: