From dc181de89a7ebf0fccf3acf5aefc2076c3c83e95 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Wed, 25 Sep 2024 16:05:47 +0100 Subject: [PATCH 01/39] specify ADDED and REPLACEMENT schedule relationships, and add more fields in TripProperties and StopTimeProperties to support fields needed for such trips --- gtfs-realtime/proto/gtfs-realtime.proto | 65 ++++++++++++++--- gtfs-realtime/spec/en/reference.md | 92 ++++++++++++++++--------- 2 files changed, 112 insertions(+), 45 deletions(-) diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index d3cfe529..943bc909 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -271,6 +271,28 @@ message TripUpdate { // (e.g., `VehiclePosition.stop_id`). // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. optional string assigned_stop_id = 1; + + // The updated headsign of the vehicle at the stop. + optional string stop_headsign = 2; + + // The updated pickup of the vehicle at the stop. + optional DropOffPickupType pickup_type = 3; + + // The updated drop off of the vehicle at the stop. + optional DropOffPickupType drop_off_type = 4; + + // The updated timing point status of the vehicle at the stop. + // If false, the vehicle will no longer wait at the stop; + // if true, the vehicle will wait until the scheduled time at the stop. + optional bool timepoint = 5; + + // Identifies the boarding booking rule at this stop time. + // Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`. + optional string pickup_booking_rule_id = 6; + + // Identifies the alighting booking rule at this stop time. + // Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`. + optional string drop_off_booking_rule_id = 7; // The extensions namespace allows 3rd-party developers to extend the // GTFS Realtime Specification in order to add and evaluate new features @@ -279,6 +301,20 @@ message TripUpdate { // The following extension IDs are reserved for private use by any organization. extensions 9000 to 9999; + + enum DropOffPickupType { + // Regularly scheduled pickup/dropoff. + REGULAR = 0; + + // No pickup/dropoff available + NONE = 1; + + // Must phone agency to arrange pickup/dropoff. + PHONE_AGENCY = 2; + + // Must coordinate with driver to arrange pickup/dropoff. + COORDINATE_WITH_DRIVER = 3; + } } // Realtime updates for certain properties defined within GTFS stop_times.txt @@ -378,6 +414,18 @@ message TripUpdate { // be marked as schedule_relationship=SKIPPED. // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. optional string shape_id = 4; + + // Specifies the headsign for this trip when it differs from the original. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. + optional string trip_headsign = 5; + + // Specifies the name for this trip when it differs from the original. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. + optional string trip_short_name = 6; + + // Specifies the block for this trip when it differs from the original. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. + optional string block_id = 7; // The extensions namespace allows 3rd-party developers to extend the // GTFS Realtime Specification in order to add and evaluate new features @@ -793,13 +841,7 @@ message TripDescriptor { // enough to the scheduled trip to be associated with it. SCHEDULED = 0; - // An extra trip that was added in addition to a running schedule, for - // example, to replace a broken vehicle or to respond to sudden passenger - // load. - // NOTE: Currently, behavior is unspecified for feeds that use this mode. There are discussions on the GTFS GitHub - // [(1)](https://github.com/google/transit/issues/106) [(2)](https://github.com/google/transit/pull/221) - // [(3)](https://github.com/google/transit/pull/219) around fully specifying or deprecating ADDED trips and the - // documentation will be updated when those discussions are finalized. + // An extra trip unrelated to any existing trips, for example, to respond to sudden passenger load. ADDED = 1; // A trip that is running with no schedule associated to it (GTFS frequencies.txt exact_times=0). @@ -809,8 +851,8 @@ message TripDescriptor { // A trip that existed in the schedule but was removed. CANCELED = 3; - // Should not be used - for backwards-compatibility only. - REPLACEMENT = 5 [deprecated=true]; + // A trip that replaces an existing trip in the schedule. + REPLACEMENT = 5; // An extra trip that was added in addition to a running schedule, for example, to replace a broken vehicle or to // respond to sudden passenger load. Used with TripUpdate.TripProperties.trip_id, TripUpdate.TripProperties.start_date, @@ -818,8 +860,9 @@ message TripDescriptor { // 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 or DELETED. Trips defined in GTFS frequencies.txt with exact_times that is + // TripUpdate.TripDescriptor.trip_id - if a producer wants to replace the original trip, a value of `REPLACEMENT` should be used instead. + // + // 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. diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 801762be..35b34032 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -144,6 +144,7 @@ Depending on the value of ScheduleRelationship, a TripUpdate can specify: * A trip that proceeds along the schedule. * A trip that proceeds along a route but has no fixed schedule. * A trip that has been added or removed with regard to schedule. +* A trip that replaces an existing trip in static GTFS. * A new trip that is a copy of an existing trip in static GTFS. It will run at the service date and time specified in TripProperties. The updates can be for future, predicted arrival/departure events, or for past events that already occurred. In most cases information about past events is a measured value thus its uncertainty value is recommended to be 0\. Although there could be cases when this does not hold so it is allowed to have uncertainty value different from 0 for past events. If an update's uncertainty is not 0, either the update is an approximate prediction for a trip that has not completed or the measurement is not precise or the update was a prediction for the past that has not been verified after the event occurred. @@ -157,14 +158,14 @@ Note that the update can describe a trip that has already completed.To this end, **Fields** -| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | -|------------------|------------|----------------|-------------------|-------------------| -| **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. At least one stop_time_update must be provided for the trip unless the trip.schedule_relationship is CANCELED, DELETED, or DUPLICATED. 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. | +| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | +|----------------------|------------------------------------------------------------------|------------------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **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, 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. | ## _message_ StopTimeEvent @@ -223,9 +224,26 @@ Realtime update for certain properties defined within GTFS stop_times.txt. **Fields** -| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | -|------------------|------------|----------------|-------------------|-------------------| -| **assigned_stop_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Supports real-time stop assignments. Refers to a `stop_id` defined in the GTFS `stops.txt`.
The new `assigned_stop_id` should not result in a significantly different trip experience for the end user than the `stop_id` defined in GTFS `stop_times.txt`. In other words, the end user should not view this new `stop_id` as an "unusual change" if the new stop was presented within an app without any additional context. For example, this field is intended to be used for platform assignments by using a `stop_id` that belongs to the same station as the stop originally defined in GTFS `stop_times.txt`.
To assign a stop without providing any real-time arrival or departure predictions, populate this field and set `StopTimeUpdate.schedule_relationship = NO_DATA`.
If this field is populated, `StopTimeUpdate.stop_sequence` must be populated and `StopTimeUpdate.stop_id` should not be populated. Stop assignments should be reflected in other GTFS-realtime fields as well (e.g., `VehiclePosition.stop_id`).

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | +|------------------------------|------------------------------------------------------------------|----------------|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **assigned_stop_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Supports real-time stop assignments. Refers to a `stop_id` defined in the GTFS `stops.txt`.
The new `assigned_stop_id` should not result in a significantly different trip experience for the end user than the `stop_id` defined in GTFS `stop_times.txt`. In other words, the end user should not view this new `stop_id` as an "unusual change" if the new stop was presented within an app without any additional context. For example, this field is intended to be used for platform assignments by using a `stop_id` that belongs to the same station as the stop originally defined in GTFS `stop_times.txt`.
To assign a stop without providing any real-time arrival or departure predictions, populate this field and set `StopTimeUpdate.schedule_relationship = NO_DATA`.
If this field is populated, `StopTimeUpdate.stop_sequence` must be populated and `StopTimeUpdate.stop_id` should not be populated. Stop assignments should be reflected in other GTFS-realtime fields as well (e.g., `VehiclePosition.stop_id`).

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **stop_headsign** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The updated headsign of the vehicle at the stop. | +| **drop_off_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated drop off of the vehicle at the stop. | +| **pickup_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated pickup of the vehicle at the stop. | +| **timepoint** | [bool](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The updated timing point status of the vehicle at the stop. If false, the vehicle will no longer wait at the stop; if true, the vehicle will wait until the scheduled time at the stop. | +| **pickup_booking_rule_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Identifies the boarding booking rule at this stop time. Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`.
Recommended when `pickup_type=PHONE_AGENCY`. | +| **drop_off_booking_rule_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Identifies the alighting booking rule at this stop time. Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`.
Recommended when `drop_off_type=PHONE_AGENCY`. | + +## _enum_ DropOffPickupType + +**Values** + +| _**Value**_ | _**Comment**_ | +|----------------------------|--------------------------------------------------------| +| **REGULAR** | Regularly scheduled pickup/dropoff. | +| **NONE** | No pickup/dropoff available. | +| **PHONE_AGENCY** | Must phone agency to arrange pickup/dropoff. | +| **COORDINATE_WITH_DRIVER** | Must coordinate with driver to arrange pickup/dropoff. | ## _message_ TripProperties @@ -235,12 +253,15 @@ Defines updated properties of the trip **Fields** -| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | -|------------------|------------|----------------|-------------------|-------------------| -| **trip_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Defines the identifier of a new trip that is a duplicate of an existing trip defined in (CSV) GTFS trips.txt but will start at a different service date and/or time (defined using `TripProperties.start_date` and `TripProperties.start_time`). See definition of `trips.trip_id` in (CSV) GTFS. Its value must be different than the ones used in the (CSV) GTFS. This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | -| **start_date** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Service date on which the duplicated trip will be run. Must be provided in YYYYMMDD format. This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**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 | Defines the departure start time of the trip when it’s duplicated. See definition of `stop_times.departure_time` in (CSV) GTFS. Scheduled arrival and departure times for the duplicated trip are calculated based on the offset between the original trip `departure_time` and this field. For example, if a GTFS trip has stop A with a `departure_time` of `10:00:00` and stop B with `departure_time` of `10:01:00`, and this field is populated with the value of `10:30:00`, stop B on the duplicated trip will have a scheduled `departure_time` of `10:31:00`. Real-time prediction `delay` values are applied to this calculated schedule time to determine the predicted time. For example, if a departure `delay` of `30` is provided for stop B, then the predicted departure time is `10:31:30`. Real-time prediction `time` values do not have any offset applied to them and indicate the predicted time as provided. For example, if a departure `time` representing 10:31:30 is provided for stop B, then the predicted departure time is `10:31:30`.This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | -| **shape_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the shape of the vehicle travel path for this trip when it differs from the original. Refers to a shape defined in the (CSV) GTFS or a new shape entity in a real-time feed. See definition of `trips.shape_id` in (CSV) GTFS.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | +|---------------------|------------|----------------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **trip_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Defines the identifier of a new trip that is a duplicate of an existing trip defined in (CSV) GTFS trips.txt but will start at a different service date and/or time (defined using `TripProperties.start_date` and `TripProperties.start_time`). See definition of `trips.trip_id` in (CSV) GTFS. Its value must be different than the ones used in the (CSV) GTFS. This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **start_date** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Service date on which the duplicated trip will be run. Must be provided in YYYYMMDD format. This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**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 | Defines the departure start time of the trip when it’s duplicated. See definition of `stop_times.departure_time` in (CSV) GTFS. Scheduled arrival and departure times for the duplicated trip are calculated based on the offset between the original trip `departure_time` and this field. For example, if a GTFS trip has stop A with a `departure_time` of `10:00:00` and stop B with `departure_time` of `10:01:00`, and this field is populated with the value of `10:30:00`, stop B on the duplicated trip will have a scheduled `departure_time` of `10:31:00`. Real-time prediction `delay` values are applied to this calculated schedule time to determine the predicted time. For example, if a departure `delay` of `30` is provided for stop B, then the predicted departure time is `10:31:30`. Real-time prediction `time` values do not have any offset applied to them and indicate the predicted time as provided. For example, if a departure `time` representing 10:31:30 is provided for stop B, then the predicted departure time is `10:31:30`.This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **trip_headsign** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the headsign for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **trip_short_name** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the name for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **block_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the block for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **shape_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the shape of the vehicle travel path for this trip when it differs from the original. Refers to a shape defined in the (CSV) GTFS or a new shape entity in a real-time feed. See definition of `trips.shape_id` in (CSV) GTFS.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | ## _message_ VehiclePosition @@ -453,29 +474,32 @@ TripDescriptor.route_id cannot be used within an Alert EntitySelector to specify **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 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. | -| **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. | -| **schedule_relationship** | [ScheduleRelationship](#enum-schedulerelationship-1) | Optional | One | The relation between this trip and the static schedule. If TripDescriptor is provided in an Alert `EntitySelector`, the `schedule_relationship` field is ignored by consumers when identifying the matching trip instance. +| _**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. If schedule_relationship=ADDED, route_id specifies the route which the added 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. | +| **schedule_relationship** | [ScheduleRelationship](#enum-schedulerelationship-1) | Optional | One | The relation between this trip and the static schedule. If TripDescriptor is provided in an Alert `EntitySelector`, the `schedule_relationship` field is ignored by consumers when identifying the matching trip instance. | ## _enum_ ScheduleRelationship -The relation between this trip and the static schedule. If a trip is done in accordance with temporary schedule, not reflected in GTFS, then it shouldn't be marked as SCHEDULED, but marked as ADDED. +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.
**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 that was added in addition to a running schedule, for example, to replace a broken vehicle or to respond to sudden passenger load. *NOTE: Currently, behavior is unspecified for feeds that use this mode. There are discussions on the GTFS GitHub [(1)](https://github.com/google/transit/issues/106) [(2)](https://github.com/google/transit/pull/221) [(3)](https://github.com/google/transit/pull/219) around fully specifying or deprecating ADDED trips and the documentation will be updated when those discussions are finalized.* | -| **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. | -| **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.* | -| **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. | +| _**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 must be specified via `StopTimeUpdate`s. | +| **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. | +| **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 replace the original trip, a value of `REPLACEMENT` should be used instead. 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.* | +| **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_ VehicleDescriptor From b439cf86ece12fe585bf94d2cf9d8ceabd5d19da Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Wed, 25 Sep 2024 16:19:44 +0100 Subject: [PATCH 02/39] remove the recommendation that ADDED is not specified --- gtfs-realtime/best-practices/best-practices.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gtfs-realtime/best-practices/best-practices.md b/gtfs-realtime/best-practices/best-practices.md index 4956a1b5..3e577946 100644 --- a/gtfs-realtime/best-practices/best-practices.md +++ b/gtfs-realtime/best-practices/best-practices.md @@ -71,10 +71,6 @@ 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. From 5a9853f3879a89116af14887e213eb38d4e0d129 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Wed, 25 Sep 2024 16:52:38 +0100 Subject: [PATCH 03/39] disallow TripModification on trips with TripUpdate.schedule_relationship=REPLACEMENT --- gtfs-realtime/proto/gtfs-realtime.proto | 2 +- gtfs-realtime/spec/en/reference.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index 943bc909..fa25c8b8 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -1160,7 +1160,7 @@ message TripModifications { } message SelectedTrips { - // A list of trips affected with this replacement that all have the same new `shape_id`. + // A list of trips affected with this replacement that all have the same new `shape_id`. A `TripUpdate` with `schedule_relationship=REPLACEMENT` must not already exist for the trip. repeated string trip_ids = 1; // The ID of the new shape for the modified trips in this SelectedTrips. // May refer to a new shape added using a GTFS-RT Shape message, or to an existing shape defined in the GTFS-Static feed’s shapes.txt. diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 35b34032..87ca2ea8 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -695,10 +695,10 @@ List of selected trips with an associated shape. **Fields** -| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | -|------------------|------------|----------------|-------------------|-------------------| -| **trip_ids** | [uint32](https://protobuf.dev/programming-guides/proto2/#scalar) | Many | One | A list of trip_id from the original (CSV) GTFS that are affected by the containing replacement. Need to contain at least one trip_id. | -| **shape_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Required | One | The ID of the new shape for the modified trips in this SelectedTrips. May refer to a new shape added using a GTFS-RT Shape message, or to an existing shape defined in the GTFS-Static feed’s shapes.txt. | +| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | +|------------------|------------------------------------------------------------------|----------------|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **trip_ids** | [uint32](https://protobuf.dev/programming-guides/proto2/#scalar) | Many | One | A list of trip_id from the original (CSV) GTFS that are affected by the containing replacement. Need to contain at least one trip_id. A `TripUpdate` with `schedule_relationship=REPLACEMENT` must not already exist for the trip. | +| **shape_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Required | One | The ID of the new shape for the modified trips in this SelectedTrips. May refer to a new shape added using a GTFS-RT Shape message, or to an existing shape defined in the GTFS-Static feed’s shapes.txt. | ## _message_ ReplacementStop From 21ccde59242ade4aa84639c5bf0c9ccde06c71e7 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 26 Sep 2024 14:22:15 +0100 Subject: [PATCH 04/39] revert formatting --- gtfs-realtime/spec/en/reference.md | 94 +++++++++++++++--------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 87ca2ea8..86ab0c39 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -158,14 +158,14 @@ Note that the update can describe a trip that has already completed.To this end, **Fields** -| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | -|----------------------|------------------------------------------------------------------|------------------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **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, 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. | +| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | +|------------------|------------|----------------|-------------------|-------------------| +| **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, 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. | ## _message_ StopTimeEvent @@ -224,15 +224,15 @@ Realtime update for certain properties defined within GTFS stop_times.txt. **Fields** -| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | -|------------------------------|------------------------------------------------------------------|----------------|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **assigned_stop_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Supports real-time stop assignments. Refers to a `stop_id` defined in the GTFS `stops.txt`.
The new `assigned_stop_id` should not result in a significantly different trip experience for the end user than the `stop_id` defined in GTFS `stop_times.txt`. In other words, the end user should not view this new `stop_id` as an "unusual change" if the new stop was presented within an app without any additional context. For example, this field is intended to be used for platform assignments by using a `stop_id` that belongs to the same station as the stop originally defined in GTFS `stop_times.txt`.
To assign a stop without providing any real-time arrival or departure predictions, populate this field and set `StopTimeUpdate.schedule_relationship = NO_DATA`.
If this field is populated, `StopTimeUpdate.stop_sequence` must be populated and `StopTimeUpdate.stop_id` should not be populated. Stop assignments should be reflected in other GTFS-realtime fields as well (e.g., `VehiclePosition.stop_id`).

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | -| **stop_headsign** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The updated headsign of the vehicle at the stop. | -| **drop_off_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated drop off of the vehicle at the stop. | -| **pickup_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated pickup of the vehicle at the stop. | -| **timepoint** | [bool](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The updated timing point status of the vehicle at the stop. If false, the vehicle will no longer wait at the stop; if true, the vehicle will wait until the scheduled time at the stop. | -| **pickup_booking_rule_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Identifies the boarding booking rule at this stop time. Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`.
Recommended when `pickup_type=PHONE_AGENCY`. | -| **drop_off_booking_rule_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Identifies the alighting booking rule at this stop time. Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`.
Recommended when `drop_off_type=PHONE_AGENCY`. | +| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | +|------------------|------------|----------------|-------------------|-------------------| +| **assigned_stop_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Supports real-time stop assignments. Refers to a `stop_id` defined in the GTFS `stops.txt`.
The new `assigned_stop_id` should not result in a significantly different trip experience for the end user than the `stop_id` defined in GTFS `stop_times.txt`. In other words, the end user should not view this new `stop_id` as an "unusual change" if the new stop was presented within an app without any additional context. For example, this field is intended to be used for platform assignments by using a `stop_id` that belongs to the same station as the stop originally defined in GTFS `stop_times.txt`.
To assign a stop without providing any real-time arrival or departure predictions, populate this field and set `StopTimeUpdate.schedule_relationship = NO_DATA`.
If this field is populated, `StopTimeUpdate.stop_sequence` must be populated and `StopTimeUpdate.stop_id` should not be populated. Stop assignments should be reflected in other GTFS-realtime fields as well (e.g., `VehiclePosition.stop_id`).

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **stop_headsign** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The updated headsign of the vehicle at the stop. | +| **drop_off_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated drop off of the vehicle at the stop. | +| **pickup_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated pickup of the vehicle at the stop. | +| **timepoint** | [bool](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The updated timing point status of the vehicle at the stop. If false, the vehicle will no longer wait at the stop; if true, the vehicle will wait until the scheduled time at the stop. | +| **pickup_booking_rule_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Identifies the boarding booking rule at this stop time. Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`.
Recommended when `pickup_type=PHONE_AGENCY`. | +| **drop_off_booking_rule_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Identifies the alighting booking rule at this stop time. Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`.
Recommended when `drop_off_type=PHONE_AGENCY`. | ## _enum_ DropOffPickupType @@ -253,15 +253,15 @@ Defines updated properties of the trip **Fields** -| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | -|---------------------|------------|----------------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **trip_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Defines the identifier of a new trip that is a duplicate of an existing trip defined in (CSV) GTFS trips.txt but will start at a different service date and/or time (defined using `TripProperties.start_date` and `TripProperties.start_time`). See definition of `trips.trip_id` in (CSV) GTFS. Its value must be different than the ones used in the (CSV) GTFS. This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | -| **start_date** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Service date on which the duplicated trip will be run. Must be provided in YYYYMMDD format. This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**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 | Defines the departure start time of the trip when it’s duplicated. See definition of `stop_times.departure_time` in (CSV) GTFS. Scheduled arrival and departure times for the duplicated trip are calculated based on the offset between the original trip `departure_time` and this field. For example, if a GTFS trip has stop A with a `departure_time` of `10:00:00` and stop B with `departure_time` of `10:01:00`, and this field is populated with the value of `10:30:00`, stop B on the duplicated trip will have a scheduled `departure_time` of `10:31:00`. Real-time prediction `delay` values are applied to this calculated schedule time to determine the predicted time. For example, if a departure `delay` of `30` is provided for stop B, then the predicted departure time is `10:31:30`. Real-time prediction `time` values do not have any offset applied to them and indicate the predicted time as provided. For example, if a departure `time` representing 10:31:30 is provided for stop B, then the predicted departure time is `10:31:30`.This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | -| **trip_headsign** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the headsign for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | -| **trip_short_name** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the name for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | -| **block_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the block for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | -| **shape_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the shape of the vehicle travel path for this trip when it differs from the original. Refers to a shape defined in the (CSV) GTFS or a new shape entity in a real-time feed. See definition of `trips.shape_id` in (CSV) GTFS.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | +|------------------|------------|----------------|-------------------|-------------------| +| **trip_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Defines the identifier of a new trip that is a duplicate of an existing trip defined in (CSV) GTFS trips.txt but will start at a different service date and/or time (defined using `TripProperties.start_date` and `TripProperties.start_time`). See definition of `trips.trip_id` in (CSV) GTFS. Its value must be different than the ones used in the (CSV) GTFS. This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **start_date** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Service date on which the duplicated trip will be run. Must be provided in YYYYMMDD format. This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**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 | Defines the departure start time of the trip when it’s duplicated. See definition of `stop_times.departure_time` in (CSV) GTFS. Scheduled arrival and departure times for the duplicated trip are calculated based on the offset between the original trip `departure_time` and this field. For example, if a GTFS trip has stop A with a `departure_time` of `10:00:00` and stop B with `departure_time` of `10:01:00`, and this field is populated with the value of `10:30:00`, stop B on the duplicated trip will have a scheduled `departure_time` of `10:31:00`. Real-time prediction `delay` values are applied to this calculated schedule time to determine the predicted time. For example, if a departure `delay` of `30` is provided for stop B, then the predicted departure time is `10:31:30`. Real-time prediction `time` values do not have any offset applied to them and indicate the predicted time as provided. For example, if a departure `time` representing 10:31:30 is provided for stop B, then the predicted departure time is `10:31:30`.This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **trip_headsign** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the headsign for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **trip_short_name** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the name for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **block_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the block for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **shape_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the shape of the vehicle travel path for this trip when it differs from the original. Refers to a shape defined in the (CSV) GTFS or a new shape entity in a real-time feed. See definition of `trips.shape_id` in (CSV) GTFS.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | ## _message_ VehiclePosition @@ -474,14 +474,14 @@ TripDescriptor.route_id cannot be used within an Alert EntitySelector to specify **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. If schedule_relationship=ADDED, route_id specifies the route which the added 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. | -| **schedule_relationship** | [ScheduleRelationship](#enum-schedulerelationship-1) | Optional | One | The relation between this trip and the static schedule. If TripDescriptor is provided in an Alert `EntitySelector`, the `schedule_relationship` field is ignored by consumers when identifying the matching trip instance. | +| _**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. If schedule_relationship=ADDED, route_id specifies the route which the added 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. | +| **schedule_relationship** | [ScheduleRelationship](#enum-schedulerelationship-1) | Optional | One | The relation between this trip and the static schedule. If TripDescriptor is provided in an Alert `EntitySelector`, the `schedule_relationship` field is ignored by consumers when identifying the matching trip instance. ## _enum_ ScheduleRelationship @@ -491,15 +491,15 @@ If a trip is done in accordance with a modified schedule, not reflected in GTFS, **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 must be specified via `StopTimeUpdate`s. | -| **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. | -| **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 replace the original trip, a value of `REPLACEMENT` should be used instead. 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.* | -| **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. | +| _**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 must be specified via `StopTimeUpdate`s. | +| **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. | +| **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.* | +| **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_ VehicleDescriptor @@ -695,10 +695,10 @@ List of selected trips with an associated shape. **Fields** -| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | -|------------------|------------------------------------------------------------------|----------------|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **trip_ids** | [uint32](https://protobuf.dev/programming-guides/proto2/#scalar) | Many | One | A list of trip_id from the original (CSV) GTFS that are affected by the containing replacement. Need to contain at least one trip_id. A `TripUpdate` with `schedule_relationship=REPLACEMENT` must not already exist for the trip. | -| **shape_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Required | One | The ID of the new shape for the modified trips in this SelectedTrips. May refer to a new shape added using a GTFS-RT Shape message, or to an existing shape defined in the GTFS-Static feed’s shapes.txt. | +| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | +|------------------|------------|----------------|-------------------|-------------------| +| **trip_ids** | [uint32](https://protobuf.dev/programming-guides/proto2/#scalar) | Many | One | A list of trip_id from the original (CSV) GTFS that are affected by the containing replacement. Need to contain at least one trip_id. A `TripUpdate` with `schedule_relationship=REPLACEMENT` must not already exist for the trip. | +| **shape_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Required | One | The ID of the new shape for the modified trips in this SelectedTrips. May refer to a new shape added using a GTFS-RT Shape message, or to an existing shape defined in the GTFS-Static feed’s shapes.txt. | ## _message_ ReplacementStop From b6d07cce5048f07efcd6e981799b8795960fb80c Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 26 Sep 2024 14:39:27 +0100 Subject: [PATCH 05/39] specify that route_id is required for added trips --- gtfs-realtime/spec/en/reference.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 86ab0c39..e432be96 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -456,7 +456,7 @@ A geographic position of a vehicle. ## _message_ TripDescriptor -A descriptor that identifies a single instance of a GTFS trip. +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. 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: @@ -472,12 +472,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 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. If schedule_relationship=ADDED, route_id specifies the route which the added trip belongs to. | +| **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. | | **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. | From 6bc14c8dbd9aae394654861d2ec668bce86c7572 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 26 Sep 2024 14:52:20 +0100 Subject: [PATCH 06/39] Clarify the use of StopTimeUpdate to specify the whole journey in added or replacement trips --- gtfs-realtime/spec/en/reference.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index e432be96..eedadfe5 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -191,14 +191,16 @@ Realtime update for arrival and/or departure events for a given stop on a trip. Updates can be supplied for both past and future events. The producer is allowed, although not required, to drop past events. 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 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. | -| **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`. | -| **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. If schedule_relationship is NO_DATA, arrival and departure must be empty. | -| **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. If schedule_relationship is NO_DATA, arrival and departure must be empty. | +| **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. For added and replacement trips, this field is compulsory and 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`. For added and replacement trips, this field is compulsory. | +| **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. For added and replacement trips, both must be provided. arrival and departure may both be empty when schedule_relationship is SKIPPED. If schedule_relationship is NO_DATA, arrival and departure must be empty. | +| **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. For added and replacement trips, both must be provided. arrival and departure may both be empty when schedule_relationship is SKIPPED. If schedule_relationship is NO_DATA, arrival and departure must be empty. | | **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. | @@ -213,7 +215,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 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 neither arrival nor departure should be supplied. | +| **NO_DATA** | No 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 neither arrival nor departure should be supplied. NO_DATA must not be used for added or replacement trips, as the StopTimeUpdate defines the stop list of the trip. | | **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 From 87d28c78f1a24d13fefc4831e109b3efc84d8779 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 26 Sep 2024 14:58:00 +0100 Subject: [PATCH 07/39] Clarify the time and delay for added and replacement trips --- gtfs-realtime/spec/en/reference.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index eedadfe5..ea08efcb 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -171,8 +171,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. -* 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. 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). +* delay should be used when the prediction is given relative to some existing schedule in GTFS. For added or replacement trips, the existence of the delay field indicates that there is a scheduled time, calculated by time - delay, at the stop for the trip, in addition to the estimated time. +* 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). 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. @@ -181,7 +181,7 @@ 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. Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. | -| **time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Event as absolute time. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC). Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. | +| **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). Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. For added or replacement trips, time must be provided as there is no schedule in GTFS static. | | **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. | ## _message_ StopTimeUpdate From 991caac4710d35948659170f139a10a230f8d36c Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Mon, 30 Sep 2024 11:47:42 +0100 Subject: [PATCH 08/39] Update gtfs-realtime/spec/en/reference.md Accept suggestion by @leonardehrenfried for definition of TripUpdate.ScheduleRelationship = ADDED Co-authored-by: Leonard Ehrenfried --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index ea08efcb..940043f6 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -498,7 +498,7 @@ If a trip is done in accordance with a modified schedule, not reflected in GTFS, | _**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 must be specified via `StopTimeUpdate`s. | +| **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. | | **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. | From fea9f815bd54f2f1ba41ccf0cf56185ea9d3f978 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Mon, 30 Sep 2024 11:48:19 +0100 Subject: [PATCH 09/39] Update gtfs-realtime/spec/en/reference.md formatting fix Co-authored-by: Leonard Ehrenfried --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 940043f6..e5fd92e9 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -171,7 +171,7 @@ 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. -* delay should be used when the prediction is given relative to some existing schedule in GTFS. For added or replacement trips, the existence of the delay field indicates that there is a scheduled time, calculated by time - delay, at the stop for the trip, in addition to the estimated time. +* delay should be used when the prediction is given relative to some existing schedule in GTFS. For added or replacement trips, the existence of the delay field indicates that there is a scheduled time, calculated by `time - delay`, at the stop for the trip, in addition to the estimated time. * 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). 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. From b6faa23eab094affbc1307dab1e8a31d76036c2a Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Wed, 2 Oct 2024 16:55:49 +0100 Subject: [PATCH 10/39] restore formatting --- gtfs-realtime/spec/en/reference.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index e5fd92e9..9906c5d3 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -489,9 +489,7 @@ 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 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. **Values** From 0e62760ec6884850953b82b6d82206aab136a6cf Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 8 Oct 2024 12:45:30 +0100 Subject: [PATCH 11/39] add scheduled time --- gtfs-realtime/proto/gtfs-realtime.proto | 6 ++++++ gtfs-realtime/spec/en/reference.md | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index fa25c8b8..10cbd08d 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -190,6 +190,12 @@ 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. + // In Unix time (i.e., number of seconds since January 1st 1970 00:00:00 + // UTC). + // Required if the parent StopTimeUpdate specifies stop_time_properties.timepoint = true + optional int64 scheduled_time = 4; + // The extensions namespace allows 3rd-party developers to extend the // GTFS Realtime Specification in order to add and evaluate new features // and modifications to the spec. diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 9906c5d3..e33e79f1 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -169,10 +169,11 @@ Note that the update can describe a trip that has already completed.To this end, ## _message_ StopTimeEvent -Timing information for a single predicted event (either arrival or departure). Timing consists of delay and/or estimated time, and uncertainty. +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 or replacement trips. -* delay should be used when the prediction is given relative to some existing schedule in GTFS. For added or replacement trips, the existence of the delay field indicates that there is a scheduled time, calculated by `time - delay`, at the stop for the trip, in addition to the estimated time. +* 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 or replacement trip, and must be given if the stop is specified as a timepoint. 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. @@ -182,6 +183,7 @@ Uncertainty applies equally to both time and delay. The uncertainty roughly spec |------------------|------------|----------------|-------------------|-------------------| | **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. Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. | | **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). Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. For added or replacement trips, time must be provided as there is no schedule in GTFS static. | +| **scheduled_time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Scheduled time for an added or replacement trip. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC). The vehicle will wait for this time if StopTimeUpdate.stop_time_properties.timepoint is 1 or unspecified. A scheduled time must be given if StopTimeUpdate.stop_time_properties.timepoint is true. | | **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. | ## _message_ StopTimeUpdate From 896129e0aa133c8328ce6b56ff8b934bcbba1901 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 8 Oct 2024 12:49:25 +0100 Subject: [PATCH 12/39] allow scheduled time for duplicated trip as well --- gtfs-realtime/spec/en/reference.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index e33e79f1..cb646bcf 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -169,11 +169,11 @@ Note that the update can describe a trip that has already completed.To this end, ## _message_ StopTimeEvent -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 or replacement trips. +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 or replacement trip, and must be given if the stop is specified as a timepoint. +* scheduled time may be given if the trip is an added, replacement or duplicated trip, and must be given if the stop is specified as a timepoint. 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. @@ -183,7 +183,7 @@ Uncertainty applies equally to both time and delay. The uncertainty roughly spec |------------------|------------|----------------|-------------------|-------------------| | **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. Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. | | **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). Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. For added or replacement trips, time must be provided as there is no schedule in GTFS static. | -| **scheduled_time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Scheduled time for an added or replacement trip. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC). The vehicle will wait for this time if StopTimeUpdate.stop_time_properties.timepoint is 1 or unspecified. A scheduled time must be given if StopTimeUpdate.stop_time_properties.timepoint is true. | +| **scheduled_time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Scheduled time for an added, replacement or duplicated trip. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC). The vehicle will wait for this time if StopTimeUpdate.stop_time_properties.timepoint is 1 or unspecified.
**Required** if StopTimeUpdate.stop_time_properties.timepoint is true.
**Forbidden** if TripUpdate.schedule_relationship is not ADDED, REPLACEMENT or DUPLICATED. | | **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. | ## _message_ StopTimeUpdate From 43a9b00e6630beabb2a85d39518243ff5b8d4f63 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 8 Oct 2024 12:52:12 +0100 Subject: [PATCH 13/39] fix wording --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index cb646bcf..8f547f94 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -183,7 +183,7 @@ Uncertainty applies equally to both time and delay. The uncertainty roughly spec |------------------|------------|----------------|-------------------|-------------------| | **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. Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. | | **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). Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. For added or replacement trips, time must be provided as there is no schedule in GTFS static. | -| **scheduled_time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Scheduled time for an added, replacement or duplicated trip. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC). The vehicle will wait for this time if StopTimeUpdate.stop_time_properties.timepoint is 1 or unspecified.
**Required** if StopTimeUpdate.stop_time_properties.timepoint is true.
**Forbidden** if TripUpdate.schedule_relationship is not ADDED, REPLACEMENT or DUPLICATED. | +| **scheduled_time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Scheduled time for an added, replacement or duplicated trip. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC). The vehicle will wait for this time if StopTimeUpdate.stop_time_properties.timepoint is true or unspecified.
**Required** if StopTimeUpdate.stop_time_properties.timepoint is true.
**Forbidden** if TripUpdate.schedule_relationship is not ADDED, REPLACEMENT or DUPLICATED. | | **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. | ## _message_ StopTimeUpdate From 3ff34bfb5153a61a0793d2dc8f14cfb2f370e971 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 3 Dec 2024 12:02:55 +0000 Subject: [PATCH 14/39] remove fields that I am not going to use --- gtfs-realtime/proto/gtfs-realtime.proto | 17 ----------------- gtfs-realtime/spec/en/reference.md | 4 ---- 2 files changed, 21 deletions(-) diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index 7b38f13a..01cff4ac 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -287,19 +287,6 @@ message TripUpdate { // The updated drop off of the vehicle at the stop. optional DropOffPickupType drop_off_type = 4; - // The updated timing point status of the vehicle at the stop. - // If false, the vehicle will no longer wait at the stop; - // if true, the vehicle will wait until the scheduled time at the stop. - optional bool timepoint = 5; - - // Identifies the boarding booking rule at this stop time. - // Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`. - optional string pickup_booking_rule_id = 6; - - // Identifies the alighting booking rule at this stop time. - // Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`. - optional string drop_off_booking_rule_id = 7; - // The extensions namespace allows 3rd-party developers to extend the // GTFS Realtime Specification in order to add and evaluate new features // and modifications to the spec. @@ -429,10 +416,6 @@ message TripUpdate { // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. optional string trip_short_name = 6; - // Specifies the block for this trip when it differs from the original. - // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. - optional string block_id = 7; - // The extensions namespace allows 3rd-party developers to extend the // GTFS Realtime Specification in order to add and evaluate new features // and modifications to the spec. diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 9936f4c6..17c7091d 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -237,9 +237,6 @@ Realtime update for certain properties defined within GTFS stop_times.txt. | **stop_headsign** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The updated headsign of the vehicle at the stop. | | **drop_off_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated drop off of the vehicle at the stop. | | **pickup_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated pickup of the vehicle at the stop. | -| **timepoint** | [bool](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The updated timing point status of the vehicle at the stop. If false, the vehicle will no longer wait at the stop; if true, the vehicle will wait until the scheduled time at the stop. | -| **pickup_booking_rule_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Identifies the boarding booking rule at this stop time. Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`.
Recommended when `pickup_type=PHONE_AGENCY`. | -| **drop_off_booking_rule_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Identifies the alighting booking rule at this stop time. Refers to a `booking_rule_id` defined in the GTFS `booking_rules.txt`.
Recommended when `drop_off_type=PHONE_AGENCY`. | ## _enum_ DropOffPickupType @@ -267,7 +264,6 @@ Defines updated properties of the trip | **start_time** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Defines the departure start time of the trip when it’s duplicated. See definition of `stop_times.departure_time` in (CSV) GTFS. Scheduled arrival and departure times for the duplicated trip are calculated based on the offset between the original trip `departure_time` and this field. For example, if a GTFS trip has stop A with a `departure_time` of `10:00:00` and stop B with `departure_time` of `10:01:00`, and this field is populated with the value of `10:30:00`, stop B on the duplicated trip will have a scheduled `departure_time` of `10:31:00`. Real-time prediction `delay` values are applied to this calculated schedule time to determine the predicted time. For example, if a departure `delay` of `30` is provided for stop B, then the predicted departure time is `10:31:30`. Real-time prediction `time` values do not have any offset applied to them and indicate the predicted time as provided. For example, if a departure `time` representing 10:31:30 is provided for stop B, then the predicted departure time is `10:31:30`.This field is required if `schedule_relationship` is `DUPLICATED`, otherwise this field must not be populated and will be ignored by consumers.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | | **trip_headsign** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the headsign for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | | **trip_short_name** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the name for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | -| **block_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the block for this trip when it differs from the original.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | | **shape_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the shape of the vehicle travel path for this trip when it differs from the original. Refers to a shape defined in the (CSV) GTFS or a new shape entity in a real-time feed. See definition of `trips.shape_id` in (CSV) GTFS.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | ## _message_ VehiclePosition From 573124ca994a219665529d838381ef4eb9272b23 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 3 Dec 2024 12:04:56 +0000 Subject: [PATCH 15/39] Update gtfs-realtime/spec/en/reference.md Co-authored-by: Guillaume Campagna --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 17c7091d..3fd78972 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -203,7 +203,7 @@ In added or replacement trips, updates are used to specify the stops visited by | _**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. For added and replacement trips, this field is compulsory and 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`. For added and replacement trips, this field is compulsory. | +| **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`. For added and replacement trips, this field is required. | | **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. For added and replacement trips, both must be provided. arrival and departure may both be empty when schedule_relationship is SKIPPED. If schedule_relationship is NO_DATA, arrival and departure must be empty. | | **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. For added and replacement trips, both must be provided. arrival and departure may both be empty when schedule_relationship is SKIPPED. If schedule_relationship is NO_DATA, arrival and departure must be empty. | | **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. | From ade68aecf431db49d3bcbc55dcb43090dfd0b0dc Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 3 Dec 2024 12:08:34 +0000 Subject: [PATCH 16/39] Update gtfs-realtime/spec/en/reference.md Co-authored-by: Guillaume Campagna --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 3fd78972..c5163da0 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -196,7 +196,7 @@ Realtime update for arrival and/or departure events for a given stop on a trip. Updates can be supplied for both past and future events. The producer is allowed, although not required, to drop past events. 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 the GTFS Static. In such trips, `stop_id`, `stop_sequence`, `departure` and `arrival` must all be set. +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. **Fields** From 2f019d883f59082e285662c1b8c0769d10bed02e Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 3 Dec 2024 12:07:55 +0000 Subject: [PATCH 17/39] remove reference to timepoint for scheduled time as it is removed from the change --- gtfs-realtime/proto/gtfs-realtime.proto | 1 - gtfs-realtime/spec/en/reference.md | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index 01cff4ac..5d2adaa7 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -193,7 +193,6 @@ message TripUpdate { // Scheduled time for an added or replacement trip. // In Unix time (i.e., number of seconds since January 1st 1970 00:00:00 // UTC). - // Required if the parent StopTimeUpdate specifies stop_time_properties.timepoint = true optional int64 scheduled_time = 4; // The extensions namespace allows 3rd-party developers to extend the diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 17c7091d..ebf85dd9 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -176,7 +176,7 @@ Timing information for a single predicted event (either arrival or departure). T * 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, and must be given if the stop is specified as a timepoint. +* scheduled time may be given if the trip is an added, 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. @@ -186,7 +186,7 @@ Uncertainty applies equally to both time and delay. The uncertainty roughly spec |------------------|------------|----------------|-------------------|-------------------| | **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. Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. | | **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). Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. For added or replacement trips, time must be provided as there is no schedule in GTFS static. | -| **scheduled_time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Scheduled time for an added, replacement or duplicated trip. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC). The vehicle will wait for this time if StopTimeUpdate.stop_time_properties.timepoint is true or unspecified.
**Required** if StopTimeUpdate.stop_time_properties.timepoint is true.
**Forbidden** if TripUpdate.schedule_relationship is not ADDED, REPLACEMENT or DUPLICATED. | +| **scheduled_time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Scheduled time for an added, replacement or duplicated trip. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC).
**Forbidden** if TripUpdate.schedule_relationship is not ADDED, REPLACEMENT or DUPLICATED. | | **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. | ## _message_ StopTimeUpdate From a2a0dd83e3db112f18246f904bcf7791ede37a76 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 16 Jan 2025 17:30:40 +0000 Subject: [PATCH 18/39] apply review feedback --- gtfs-realtime/spec/en/reference.md | 26 +++++++++++++------------- gtfs-realtime/spec/en/trip-updates.md | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index d8c52421..f28bb14a 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, 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 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. | | **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. | @@ -184,16 +184,16 @@ 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. Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. | -| **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). Either delay or time must be provided within a StopTimeEvent - both fields cannot be empty. For added or replacement trips, time must be provided as there is no schedule in GTFS static. | -| **scheduled_time** | [int64](https://protobuf.dev/programming-guides/proto2/#scalar) | Conditionally required | One | Scheduled time for an added, replacement or duplicated trip. In POSIX time (i.e., number of seconds since January 1st 1970 00:00:00 UTC).
**Forbidden** if TripUpdate.schedule_relationship is not ADDED, REPLACEMENT or DUPLICATED. | -| **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. | +| **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. | +| **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. +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. 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. @@ -202,10 +202,10 @@ In added or replacement trips, updates are used to specify the stops visited by | _**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. For added and replacement trips, this field is compulsory and 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`. For added and replacement trips, this field is required. | -| **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. For added and replacement trips, both must be provided. arrival and departure may both be empty when schedule_relationship is SKIPPED. If schedule_relationship is NO_DATA, arrival and departure must be empty. | -| **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. For added and replacement trips, both must be provided. arrival and departure may both be empty when schedule_relationship is SKIPPED. If schedule_relationship is NO_DATA, arrival and departure must be empty. | +| **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. | | **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 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 neither arrival nor departure should be supplied. NO_DATA must not be used for added or replacement trips, as the StopTimeUpdate defines the stop list of the trip. | +| **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. | | **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 @@ -475,7 +475,7 @@ 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 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 `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. **Fields** @@ -501,7 +501,7 @@ The relation between this trip and the static schedule. If a new trip is done in | **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. | | **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** | 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.* | | **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. | diff --git a/gtfs-realtime/spec/en/trip-updates.md b/gtfs-realtime/spec/en/trip-updates.md index b6c6894b..79cc9748 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. 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 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. For example, if the following data appears in the GTFS-rt feed: From aa902915f88400750701ea55c7c90ee2faf29d41 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 16 Jan 2025 17:34:33 +0000 Subject: [PATCH 19/39] mark new fields as experimental --- gtfs-realtime/proto/gtfs-realtime.proto | 31 ++++++++++++++----------- gtfs-realtime/spec/en/reference.md | 6 ++--- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index 5d2adaa7..4563e5a9 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -278,12 +278,29 @@ message TripUpdate { optional string assigned_stop_id = 1; // The updated headsign of the vehicle at the stop. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. optional string stop_headsign = 2; + + enum DropOffPickupType { + // Regularly scheduled pickup/dropoff. + REGULAR = 0; + // No pickup/dropoff available + NONE = 1; + + // Must phone agency to arrange pickup/dropoff. + PHONE_AGENCY = 2; + + // Must coordinate with driver to arrange pickup/dropoff. + COORDINATE_WITH_DRIVER = 3; + } + // The updated pickup of the vehicle at the stop. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. optional DropOffPickupType pickup_type = 3; // The updated drop off of the vehicle at the stop. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. optional DropOffPickupType drop_off_type = 4; // The extensions namespace allows 3rd-party developers to extend the @@ -293,20 +310,6 @@ message TripUpdate { // The following extension IDs are reserved for private use by any organization. extensions 9000 to 9999; - - enum DropOffPickupType { - // Regularly scheduled pickup/dropoff. - REGULAR = 0; - - // No pickup/dropoff available - NONE = 1; - - // Must phone agency to arrange pickup/dropoff. - PHONE_AGENCY = 2; - - // Must coordinate with driver to arrange pickup/dropoff. - COORDINATE_WITH_DRIVER = 3; - } } // Realtime updates for certain properties defined within GTFS stop_times.txt diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index f28bb14a..24328383 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -234,9 +234,9 @@ Realtime update for certain properties defined within GTFS stop_times.txt. | _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | |------------------|------------|----------------|-------------------|-------------------| | **assigned_stop_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Supports real-time stop assignments. Refers to a `stop_id` defined in the GTFS `stops.txt`.
The new `assigned_stop_id` should not result in a significantly different trip experience for the end user than the `stop_id` defined in GTFS `stop_times.txt`. In other words, the end user should not view this new `stop_id` as an "unusual change" if the new stop was presented within an app without any additional context. For example, this field is intended to be used for platform assignments by using a `stop_id` that belongs to the same station as the stop originally defined in GTFS `stop_times.txt`.
To assign a stop without providing any real-time arrival or departure predictions, populate this field and set `StopTimeUpdate.schedule_relationship = NO_DATA`.
If this field is populated, `StopTimeUpdate.stop_sequence` must be populated and `StopTimeUpdate.stop_id` should not be populated. Stop assignments should be reflected in other GTFS-realtime fields as well (e.g., `VehiclePosition.stop_id`).

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | -| **stop_headsign** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The updated headsign of the vehicle at the stop. | -| **drop_off_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated drop off of the vehicle at the stop. | -| **pickup_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated pickup of the vehicle at the stop. | +| **stop_headsign** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The updated headsign of the vehicle at the stop.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **drop_off_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated drop off of the vehicle at the stop.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **pickup_type** | [DropOffPickupType](#enum-dropoffpickuptype) | Optional | One | The updated pickup of the vehicle at the stop.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | ## _enum_ DropOffPickupType From 4361f122483f22fa3b7101ea8a6833f3cd6604b2 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 21 Jan 2025 11:48:03 +0000 Subject: [PATCH 20/39] use NEW instead of ADDED for a new trip --- .../best-practices/best-practices.md | 4 ++ gtfs-realtime/proto/gtfs-realtime.proto | 12 ++++-- gtfs-realtime/spec/en/reference.md | 37 ++++++++++--------- gtfs-realtime/spec/en/trip-updates.md | 2 +- 4 files changed, 33 insertions(+), 22 deletions(-) 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..af625ba1 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-duplicated.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: From d0843d5b6e19368a055b0b704ec2f9767b72e70a Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 21 Jan 2025 12:12:50 +0000 Subject: [PATCH 21/39] add migration guide --- .../spec/en/examples/migration-duplicated.md | 71 +++++++++++++++++-- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/gtfs-realtime/spec/en/examples/migration-duplicated.md b/gtfs-realtime/spec/en/examples/migration-duplicated.md index b617a573..1d86c54d 100644 --- a/gtfs-realtime/spec/en/examples/migration-duplicated.md +++ b/gtfs-realtime/spec/en/examples/migration-duplicated.md @@ -1,13 +1,76 @@ -## Migration Guide - Transition from ADDED to DUPLICATED trips +## Migration Guide - Transition from ADDED to NEW or DUPLICATED trips + +The GTFS-realtime `trip.schedule_relationship` of `NEW` represents a new trip that runs on a schedule unrelated to any existing scheduled trip. The GTFS-realtime `trip.schedule_relationship` of `DUPLICATED` represents a new trip that is the same as an existing scheduled trip except for service start date and time. -This migration guide defines how existing producers and consumers that were using the `ADDED` enumeration to represent duplicated trips should transition to the `DUPLICATED` enumeration. The goal is to minimize disruption to producers and consumers during the transition. +This migration guide defines how existing producers and consumers that were using the `ADDED` enumeration should transition to either the `NEW` and the `DUPLICATED` enumeration. The goal is to minimize disruption to producers and consumers during the transition. + +*If you are a producer or consumer that has **not** used the `ADDED` enumeration, no action is required - you can produce/consume `NEW` and/or `DUPLICATED` trips without producing/consuming any `ADDED` entities.* -*If you are a producer or consumer that has **not** used the `ADDED` enumeration to describe duplicated trips, no action is required - you can produce/consume `DUPLICATED` trips without producing/consuming any `ADDED` entities.* +For a full history of the `NEW` enumeration, see the [`NEW` and `REPLACEMENT` proposal on GitHub](https://github.com/google/transit/pull/504). For a full history of the `DUPLICATED` enumeration, see the [`DUPLICATED` proposal on GitHub](https://github.com/google/transit/pull/221). +### Which one to migrate to + +Both `NEW` and `DUPLICATED` enumeration are used to specify a trip which was not originally scheduled to run in the GTFS static. + +Use `NEW` if your trip cannot be described using any scheduled trips as a template. For example, if the trip calls at different stops from the regular trips of the route, or if the extra trip is pickup only at the beginning of the route despite that the regular trips allow both pickup and drop off at all stops. + +Use `DUPLICATED` if your trip is a copy of a scheduled trip, which may run at the same, or at different times of the original scheduled trip. + +### Using ADDED and NEW entities in the same feed + +If you are a producer who has been using the `ADDED` enumeration to specify trips which are unrelated to the schedule, to avoid disruption to existing consumers it is recommended that you continue to produce `ADDED` entitles for these trips but also add `NEW` entitles for the same trip. + +However, to prevent consumers from accidentally adding the same trip twice, the entities referencing the same trip **must** be linked using the same `trip_id`, `route_id` and `start_date`. +In addition, the contents of the `stop_time_update` must also be the same as well. + +#### Producers + +~~~ +entity { + id: "ei0" + trip_update { + trip: { + trip_id: "1" // <-- a trip_id not found in the static GTFS + route_id: "A" + schedule_relationship: ADDED + start_date: "20200821" // <-- New trip date + start_time: "11:30:00" // <-- New trip time + } + stop_time_update { + ... // The full list of the calling points of the trip + } + } +} + +entity { + id: "ei10" + trip_update { + trip: { + trip_id: "1" // <-- The same trip_id as the above + route_id: "A" // <-- The same route_id as the above + schedule_relationship: NEW + start_date: "20200821" // <-- The same date as the above + start_time: "11:30:00" // <-- The same time as the above + } + stop_time_update { + ... // <-- The same content as the above + } + } +} +~~~ + +It is suggested that you notify existing consumers (e.g., via a developer mailing list) that the use of `ADDED` is being deprecated by a set deadline and that consumers should start consuming the `NEW` trips instead. The above strategy being used to match `ADDED` and `NEW` trip entities should also be mentioned and a link to this migration guide should be included. After the deadline passes, you can remove the `NEW` entities from your feed and publish only the `NEW` entities for newly-added trips. + +#### Consumers + +As mentioned above, producers will transition from `ADDED` to `NEW` enumerations by initially publishing two entities for each new trip using the same `trip_id`. + +Therefore, when a consumer implements support for `NEW` trips, it is important that consumers ignore any `ADDED` trips that have the same `trip_id` as a `NEW` trip `trip_id`. + ### Using ADDED and DUPLICATED entities in same feed #### Producers @@ -93,7 +156,7 @@ entity { } ~~~ -It is suggested that you notify existing consumers (e.g., via a developer mailing list) that the use of `ADDED` for duplicated trips is being deprecated by a set deadline and that consumers should start consuming the `DUPLICATED` trips instead. The above strategy being used to match `ADDED` and `DUPLICATED` trip entities should also be mentioned and a link to this migration guide should be included. After the deadline passes, you can remove the `ADDED` entities from your feed and publish only the `DUPLICATED` entities for duplicated trips. +It is suggested that you notify existing consumers (e.g., via a developer mailing list) that the use of `ADDED` is being deprecated by a set deadline and that consumers should start consuming the `DUPLICATED` trips instead. The above strategy being used to match `ADDED` and `DUPLICATED` trip entities should also be mentioned and a link to this migration guide should be included. After the deadline passes, you can remove the `ADDED` entities from your feed and publish only the `DUPLICATED` entities for duplicated trips. #### Consumers From 7804def8a78131ba8cb214c36035e10bb19ec8ba Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 21 Jan 2025 12:34:31 +0000 Subject: [PATCH 22/39] add some best practices --- gtfs-realtime/best-practices/best-practices.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gtfs-realtime/best-practices/best-practices.md b/gtfs-realtime/best-practices/best-practices.md index 4956a1b5..2b21a819 100644 --- a/gtfs-realtime/best-practices/best-practices.md +++ b/gtfs-realtime/best-practices/best-practices.md @@ -52,7 +52,7 @@ All entities should only be removed from a GTFS Realtime feed when they are no l General guidelines for trip cancellations: * When canceling trips over a number of days, producers should provide TripUpdates referencing the given `trip_ids` and `start_dates` as `CANCELED` as well as an Alert with `NO_SERVICE` referencing the same `trip_ids` and `TimeRange` that can be shown to riders explaining the cancellation (e.g., detour). -* If no stops in a trip will be visited, the trip should be `CANCELED` instead of having all `stop_time_updates` being marked as `SKIPPED`. +* If no stops in a trip will be visited, the trip should be `CANCELED` instead of having all `stop_time_updates` being marked as `SKIPPED`, unless the trip was a `NEW` or `DUPLICATED` trip and was subsequently canceled. | Field Name | Recommendation | | --- | --- | @@ -73,7 +73,13 @@ For example, a `VehiclePosition` entity has `vehicle_id:A` and `trip_id:4`, then | Field Name | Recommendation | | --- | --- | -| `schedule_relationship` | The behavior of `ADDED` trips are unspecified and the use of this enumeration is not recommended. | +| `schedule_relationship` | The behavior of `ADDED` trips are unspecified and the use of this enumeration is not recommended.
If the trip is not scheduled to run originally, use `NEW` if it doesn't follow the stopping pattern of an existing trip, or `DUPLICATED` if it is a copy of an existing trip.
If the trip runs on a modified schedule or calling points, but can be associated to an original scheduled trip in the GTFS static, use `REPLACEMENT` and specify the full list of calling points for the modified trip. | + +### TripProperties + +| Field Name | Recommendation | +| --- | --- | +| `trip_headsign` | Should always be provided for a trip with `TripDescriptor.schedule_relationship` = `NEW`, and provided for a trip with `TripDescriptor.schedule_relationship` = `REPLACEMENT` if the trip is diverted. | ### VehicleDescriptor @@ -100,6 +106,7 @@ For example, a `VehiclePosition` entity has `vehicle_id:A` and `trip_id:4`, then | Field Name | Recommendation | | --- | --- | | `delay` | If only `delay` is provided in a `stop_time_update` `arrival` or `departure` (and not `time`), then the GTFS [`stop_times.txt`](https://gtfs.org/reference/static#stopstxt) should contain `arrival_times` and/or `departure_times` for these corresponding stops. A `delay` value in the realtime feed is meaningless unless you have a clock time to add it to in the GTFS `stop_times.txt` file. | +| `scheduled_time` | If the trip is a new or replacement trip, and the trip will run according to a schedule (which can be a modified schedule in case of a replacement trip), `scheduled_time` should be provided for all timepoints. If a duplicated trip runs have different run or dwell times compared to the original, `scheduled_time` can also be used to specify them. | ### VehiclePosition From 010c9761616a810531e297d90697145c1097f1ec Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Mon, 10 Mar 2025 16:23:50 +0000 Subject: [PATCH 23/39] apply review suggestion --- gtfs-realtime/best-practices/best-practices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/best-practices/best-practices.md b/gtfs-realtime/best-practices/best-practices.md index 2b21a819..00b72125 100644 --- a/gtfs-realtime/best-practices/best-practices.md +++ b/gtfs-realtime/best-practices/best-practices.md @@ -73,7 +73,7 @@ For example, a `VehiclePosition` entity has `vehicle_id:A` and `trip_id:4`, then | Field Name | Recommendation | | --- | --- | -| `schedule_relationship` | The behavior of `ADDED` trips are unspecified and the use of this enumeration is not recommended.
If the trip is not scheduled to run originally, use `NEW` if it doesn't follow the stopping pattern of an existing trip, or `DUPLICATED` if it is a copy of an existing trip.
If the trip runs on a modified schedule or calling points, but can be associated to an original scheduled trip in the GTFS static, use `REPLACEMENT` and specify the full list of calling points for the modified trip. | +| `schedule_relationship` | The behavior of `ADDED` trips are unspecified and the use of this enumeration is not recommended.
If the trip is not scheduled to run originally, use `NEW` if it doesn't follow the stopping pattern of an existing trip, or `DUPLICATED` if it is a copy of an existing trip.
If the trip runs on a modified schedule or stops, but can be associated to an original scheduled trip in the GTFS static, use `REPLACEMENT` and specify the full list of stop times for the modified trip. | ### TripProperties From 4a9abd343a4cbc26d3a5e10f66e90c034d4a08c2 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 1 Apr 2025 11:53:04 +0100 Subject: [PATCH 24/39] apply review suggestion Co-authored-by: Joshua Fabian --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index af625ba1..b9f92013 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -501,7 +501,7 @@ The relation between this trip and the static schedule. If a new trip is done in | **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. | +| **REPLACEMENT** | A trip that replaces an existing scheduled trip, for example, with a changed schedule or a diverted routing. 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-duplicated.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. | From f3d180064b4ca653c5c4008d1d4105f7ee75a6e9 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 1 Apr 2025 11:54:59 +0100 Subject: [PATCH 25/39] apply review suggestion (cosmetic change) Co-authored-by: Joshua Fabian --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index b9f92013..31cfa50f 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -481,7 +481,7 @@ If `schedule_relationship` is `NEW`, `trip_id` must be set to a value not exist | _**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 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. | +| **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 defined 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. | From 8aea1c8b4a75734742a158b03cee2a158e7ebe58 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Tue, 1 Apr 2025 11:55:10 +0100 Subject: [PATCH 26/39] apply review suggestion Co-authored-by: Joshua Fabian --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 31cfa50f..e10d0476 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -475,7 +475,7 @@ 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 `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. +If `schedule_relationship` is `NEW`, `trip_id` must be set to a value not listed 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** From 84dc77b59329a10a331513235fa5583adf674ae2 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 10 Apr 2025 12:05:08 +0100 Subject: [PATCH 27/39] Apply suggestions from code review apply review suggestions Co-authored-by: Sam Hickey --- gtfs-realtime/proto/gtfs-realtime.proto | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index 28684a3b..11054765 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -190,9 +190,10 @@ message TripUpdate { // To specify a completely certain prediction, set its uncertainty to 0. optional int32 uncertainty = 3; - // Scheduled time for a new or replacement trip. + // Scheduled time for a NEW, REPLACEMENT, or DUPLICATED trip. // In Unix time (i.e., number of seconds since January 1st 1970 00:00:00 // UTC). + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. optional int64 scheduled_time = 4; // The extensions namespace allows 3rd-party developers to extend the From 9a278644e621ea9cf366008a273f21edeede5d4b Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 10 Apr 2025 12:06:17 +0100 Subject: [PATCH 28/39] apply review suggestion --- gtfs-realtime/proto/gtfs-realtime.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index 28684a3b..a4fc5d3e 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -845,6 +845,7 @@ message TripDescriptor { CANCELED = 3; // A trip that replaces an existing trip in the schedule. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. REPLACEMENT = 5; // An extra trip that was added in addition to a running schedule, for example, to replace a broken vehicle or to From a956a7b6e76c4c563c057ea9226125bd3a6edd7f Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 10 Apr 2025 12:40:14 +0100 Subject: [PATCH 29/39] apply review suggestion Co-authored-by: Sam Hickey --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index e10d0476..160aa52d 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -481,7 +481,7 @@ If `schedule_relationship` is `NEW`, `trip_id` must be set to a value not listed | _**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 NEW, it must be specified with a unique value not defined 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. | +| **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 defined in the GTFS static. When schedule_relationship is REPLACEMENT, the trip_id identifies the trip from static GTFS to be replaced. 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. | From 8b15a4d2af656e2c1e117ebaa64a3aff44a8f3ab Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 10 Apr 2025 12:43:21 +0100 Subject: [PATCH 30/39] apply review suggestion Co-authored-by: Sam Hickey --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 160aa52d..db465752 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -172,7 +172,7 @@ Note that the update can describe a trip that has already completed.To this end, ## _message_ StopTimeEvent -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. +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 NEW, 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 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). From fd47558e3ddf59cdd7de710e56f5f946f725728f Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 10 Apr 2025 12:45:00 +0100 Subject: [PATCH 31/39] apply review suggestion Co-authored-by: Sam Hickey --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index db465752..a564ac9a 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 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. | +| **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 or UNSCHEDULED, 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. | From 7aafabe323cef07e7947a95cbb607fab702816d9 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 10 Apr 2025 12:45:35 +0100 Subject: [PATCH 32/39] apply review suggestion Co-authored-by: Sam Hickey --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index a564ac9a..7dd2a59b 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -184,7 +184,7 @@ 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. | +| **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 time 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 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. | From 22b5379c88e12a851897924ae7ef5377a6fb1cc2 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 10 Apr 2025 12:46:05 +0100 Subject: [PATCH 33/39] apply review suggestion Co-authored-by: Sam Hickey --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 7dd2a59b..5b0d685b 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -185,7 +185,7 @@ 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 time 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. | +| **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 delay 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. | From 7938eeb26854cbe85afca09425f7531162411b53 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 10 Apr 2025 12:33:28 +0100 Subject: [PATCH 34/39] restore a removed sentence --- gtfs-realtime/proto/gtfs-realtime.proto | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index c2b83240..a5efd957 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -855,7 +855,9 @@ message TripDescriptor { // 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 replace the original trip, a value of `REPLACEMENT` should be used instead. + // TripUpdate.TripDescriptor.trip_id - if a producer wants to cancel the original trip, it must publish a separate + // TripUpdate with the value of CANCELED or DELETED. if a producer wants to replace the original trip, a value of + // `REPLACEMENT` should be used instead. // // 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 From 3c2b9696e188e5e86af3df08c6edc25ae0eed3f9 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 10 Apr 2025 12:35:38 +0100 Subject: [PATCH 35/39] apply review suggestion (mark field as experimental) --- gtfs-realtime/spec/en/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 5b0d685b..8e9d971c 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -501,7 +501,7 @@ The relation between this trip and the static schedule. If a new trip is done in | **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 routing. 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. | +| **REPLACEMENT** | A trip that replaces an existing scheduled trip, for example, with a changed schedule or a diverted routing. 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.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | | **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-duplicated.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. | From 81c4d03b17bebab7171b5c9f8d5d81b125a699f6 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Fri, 11 Apr 2025 12:09:24 +0100 Subject: [PATCH 36/39] Add definition of conditionally forbidden --- gtfs-realtime/spec/en/reference.md | 1 + 1 file changed, 1 insertion(+) diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 8e9d971c..aca7ddcf 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -12,6 +12,7 @@ The following values are used in the *Required* field: * **Required**: This field must be provided by a GTFS-realtime feed producer. * **Conditionally required**: This field is required under certain conditions, which are outlined in the field *Description*. Outside of these conditions, the field is optional. +* **Conditionally forbidden**: This field is forbidden under certain conditions, which are outlined in the field *Description*. Outside of these conditions, the field is optional. * **Optional**: This field is optional and is not required to be implemented by producers. However, if the data is available in the underlying automatic vehicle location systems (e.g., VehiclePosition `timestamp`) it is recommended that producers provide these optional fields when possible. *Note that semantic requirements were not defined in GTFS-realtime version 1.0, and therefore feeds with `gtfs_realtime_version` of `1` may not meet these requirements (see [the proposal for semantic requirements](https://github.com/google/transit/pull/64) for details).* From 85582961da21928ef6a16618851955397e72806a Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Mon, 14 Apr 2025 16:33:49 +0100 Subject: [PATCH 37/39] capitalisation --- gtfs-realtime/proto/gtfs-realtime.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index a5efd957..4942824c 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -856,7 +856,7 @@ message TripDescriptor { // (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 or DELETED. if a producer wants to replace the original trip, a value of + // TripUpdate with the value of CANCELED or DELETED. If a producer wants to replace the original trip, a value of // `REPLACEMENT` should be used instead. // // Trips defined in GTFS frequencies.txt with exact_times that is From 9ba6c4d667e8083cec29aaa7e6108f28e44b34a5 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Mon, 14 Apr 2025 16:35:44 +0100 Subject: [PATCH 38/39] mark scheduled_time as conditionally forbidden in the proto as mentioned in reference.md --- gtfs-realtime/proto/gtfs-realtime.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index 4942824c..25cc3091 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -193,6 +193,7 @@ message TripUpdate { // Scheduled time for a NEW, REPLACEMENT, or DUPLICATED trip. // In Unix 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. // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. optional int64 scheduled_time = 4; From ff994c026268565d7f52484531eeb949bdfc6143 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Fri, 25 Apr 2025 10:29:39 +0100 Subject: [PATCH 39/39] empty commit