Skip to content

Commit

Permalink
Adjust trip modifications
Browse files Browse the repository at this point in the history
- Addition of start_time and start_date to `ModifiedTripSelector` for frequency service support
- Adding missing extensions fields for ModifiedTripSelector
- Explicitly allow use of `schedule_relationship` in `TripDescriptor` when using a `ModifiedTripSelector`.
- Add missing documentation in reference.md (it was only specified in the .proto)
  • Loading branch information
gcamp committed Sep 17, 2024
1 parent 3a70ff7 commit 6761069
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 4 deletions.
17 changes: 17 additions & 0 deletions gtfs-realtime/proto/gtfs-realtime.proto
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,24 @@ message TripDescriptor {

// The trip_id from the GTFS feed that is modified by the modifications_id
optional string affected_trip_id = 2;

// The initially scheduled start time of this trip instance, applied to the frequency based modified trip. Same definition as start_time in TripDescriptor.
optional string start_time = 3;

// The start date of this trip instance in YYYYMMDD format, applied to the modified trip. Same definition as start_date in TripDescriptor.
optional string start_date = 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.
extensions 1000 to 1999;

// The following extension IDs are reserved for private use by any organization.
extensions 9000 to 9999;
}

// Linkage to any modifications done to this trip (shape changes, removal or addition of stops).
// If this field is provided, the `trip_id`, `route_id`, `direction_id`, `start_time`, `start_date` fields of the `TripDescriptor` MUST be left empty, to avoid confusion by consumers that aren't looking for the `ModifiedTripSelector` value.
optional ModifiedTripSelector modified_trip = 7;

// The extensions namespace allows 3rd-party developers to extend the
Expand Down
20 changes: 18 additions & 2 deletions gtfs-realtime/spec/en/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Fields labeled as **experimental** are subject to change and not yet formally ad
* [VehiclePosition](#message-vehicleposition)
* [TripDescriptor](#message-tripdescriptor)
* [ScheduleRelationship](#enum-schedulerelationship-1)
* [ModifiedTripSelector](#message-modifiedtripselector)
* [VehicleDescriptor](#message-vehicledescriptor)
* [WheelchairAccessible](#enum-wheelchairaccessible)
* [Position](#message-position)
Expand Down Expand Up @@ -121,7 +122,7 @@ Determines whether the current fetch is incremental.

## _message_ FeedEntity

A definition (or update) of an entity in the transit feed. If the entity is not being deleted, exactly one of 'trip_update', 'vehicle', 'alert' and 'shape' fields should be populated.
A definition (or update) of an entity in the transit feed. If the entity is not being deleted, exactly one of 'trip_update', 'vehicle', 'alert', 'shape', 'stop' or 'trip_modification' fields should be populated.

**Fields**

Expand All @@ -133,6 +134,8 @@ A definition (or update) of an entity in the transit feed. If the entity is not
| **vehicle** | [VehiclePosition](#message-vehicleposition) | Conditionally required | One | Data about the realtime position of a vehicle. At least one of the fields trip_update, vehicle, alert, or shape must be provided - all these fields cannot be empty. |
| **alert** | [Alert](#message-alert) | Conditionally required | One | Data about the realtime alert. At least one of the fields trip_update, vehicle, alert, or shape must be provided - all these fields cannot be empty. |
| **shape** | [Shape](#message-shape) | Conditionally required | One | Data about the realtime added shapes, such as for a detour. At least one of the fields trip_update, vehicle, alert, or shape must be provided - all these fields cannot be empty. <br><br>**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. |
| **stop** | [Stop](#message-stop) | Conditionally required | One | A new stop added to the feed dynamically. <br><br>**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. |
| **trip_modifications** | [TripModifications)(#message-tripmodifications) | Conditionally required | One | List of trips affected by a particular modifications, such as a detour. <br><br>**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. |


## _message_ TripUpdate
Expand Down Expand Up @@ -461,6 +464,7 @@ TripDescriptor.route_id cannot be used within an Alert EntitySelector to specify
| **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.
| **modified_trip** | [ModifiedTripSelector](#message-modifiedtripselector) | Optional | One | Linkage to any modifications done to this trip (shape changes, removal or addition of stops). If this field is provided, the `trip_id`, `route_id`, `direction_id`, `start_time`, `start_date` fields of the `TripDescriptor` MUST be left empty, to avoid confusion by consumers that aren't looking for the `ModifiedTripSelector` value.

## _enum_ ScheduleRelationship

Expand All @@ -477,6 +481,18 @@ The relation between this trip and the static schedule. If a trip is done in acc
| **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`. <br><br> 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`. <br><br>*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. <br><br> 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.<br><br>**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. |

## _message_ ModifiedTripSelector

When a service is affected by a trip modification, `ModifiedTripSelector` is used to select some trip. More detail in the [Trip Modification](https://github.com/google/transit/blob/master/gtfs-realtime/spec/en/trip-modifications.md#linkage-to-tripupdates) specification.

**Values**

| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ |
| **modifications_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Required | One | The `id` of the `FeedEntity` in which the contained `TripModifications` object affects this trip.
| **affected_trip_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Required | One | The `trip_id` from the GTFS feed that is modified by the `modifications_id`
| **start_time** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The initially scheduled start time of this trip instance, applied to the frequency based modified trip. Same definition as **start_time** in [TripDescriptor](#message-tripdescriptor).
| **start_date** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The start date of this trip instance in YYYYMMDD format, applied to the modified trip. Same definition as **start_date** in [TripDescriptor](#message-tripdescriptor).

## _message_ VehicleDescriptor

Identification information for the vehicle performing the trip.
Expand Down Expand Up @@ -691,4 +707,4 @@ _If a modification affects the first stop of the trip, that stop also serves as
| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ |
|------------------|------------|----------------|-------------------|-------------------|
| **stop_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Required | One | The replacement stop ID which will now be visited by the trip. May refer to a new stop added using a GTFS-RT `Stop` message, or to an existing stop defined in the (CSV) GTFS feed’s `stops.txt`. The stop MUST have `location_type=0` (routable stops). |
| **travel_time_to_stop** | [int32](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The difference in seconds between the arrival time at this stop and the arrival time at the reference stop. The reference stop is the stop prior to `start_stop_selector`. If the modification begins at the first stop of the trip, then the first stop of the trip is the reference stop. <br/><br/>This value MUST be monotonically increasing and may only be a negative number if the first stop of the original trip is the reference stop. <br/><br/>If the value is not supplied, consumers MAY interpolate or infer the `travel_time_to_stop` based on other data. |
| **travel_time_to_stop** | [int32](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | The difference in seconds between the arrival time at this stop and the arrival time at the reference stop. The reference stop is the stop prior to `start_stop_selector`. If the modification begins at the first stop of the trip, then the first stop of the trip is the reference stop. <br/><br/>This value MUST be monotonically increasing and may only be a negative number if the first stop of the original trip is the reference stop. <br/><br/>If the value is not supplied, consumers MAY interpolate or infer the `travel_time_to_stop` based on other data. |
4 changes: 2 additions & 2 deletions gtfs-realtime/spec/en/trip-modifications.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The scheduled stop times of each replacement trip are created from those of the

* A TripUpdate SHOULD be provided using a `ModifiedTripSelector` inside the TripUpdate's `TripDescriptor`.
* When the TripUpdate refers to the replacement trip, the consumer should behave as if the static GTFS would have been modified with the TripModifications (e.g. `arrival_time`, `departure_time`, `stop_sequence`, `stop_id` on replacement stops).
* When providing a `ModifiedTripSelector`, the other fields of the `TripDescriptor` MUST be left empty, to avoid confusion by consumers that aren't looking for the `ModifiedTripSelector` value.
* When providing a `ModifiedTripSelector`, the `trip_id`, `route_id`, `direction_id`, `start_time`, `start_date` fields of the `TripDescriptor` MUST be left empty, to avoid confusion by consumers that aren't looking for the `ModifiedTripSelector` value.
* TripUpdate feeds providing updates with `ModifiedTripSelector` SHOULD also include a TripUpdate targeting clients that don't support TripModifications. In other words, there should be two TripUpdates: one for clients with modified trips (with `TripModifications`) and one for clients with the originial unmodified GTFS (without `TripModifications`).
* Providing a TripUpdate with a `ModifiedTripSelector` is the only way to create predictions at replacement stops.
* If no such TripUpdate is found, TripUpdates for the original `trip_id` will apply to the modified trip.
Expand All @@ -34,7 +34,7 @@ The scheduled stop times of each replacement trip are created from those of the

A `Modification` message describes changes to each affected trip starting at `start_stop_selector`. There can be zero, one, or more than one stop time(s) replaced by a `Modification`. The spans of the modifications MUST not overlap. Spans may not be contiguous; in this case the two modifications MUST be merged into one. These stop times are replaced with a new stop time for each replacement stop described by `replacement_stops`.

The sequence of `replacement_stops` may be of arbitrary length. For example, 3 stops could be replaced by 2, 4, or 0 stops as the situation may require.
The sequence of `replacement_stops` may be of arbitrary length. For example, 3 stops could be replaced by 2, 4, or 0 stops as the situation may require.

![](images/trip_modification.png)

Expand Down

0 comments on commit 6761069

Please sign in to comment.