Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions gtfs/spec/en/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ This document defines the format and structure of the files that comprise a GTFS
- [fare\_transfer\_rules.txt](#fare_transfer_rulestxt)
- [areas.txt](#areastxt)
- [stop_areas.txt](#stop_areastxt)
- [area_sets.txt](#area_setstxt)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- [area_sets.txt](#area_setstxt)
- [area_sets.txt](#area_setstxt)
- [area_set_elements.txt](#area_set_elementstxt)

- [networks.txt](#networkstxt)
- [route_networks.txt](#route_networkstxt)
- [shapes.txt](#shapestxt)
Expand Down Expand Up @@ -126,6 +127,7 @@ This specification defines the following files:
| [fare_transfer_rules.txt](#fare_transfer_rulestxt) | Optional | Fare rules for transfers between legs of travel.<br><br>Along with [fare_leg_rules.txt](#fare_leg_rulestxt), file [fare_transfer_rules.txt](#fare_transfer_rulestxt) provides a more detailed method for modeling fare structures. As such, the use of [fare_transfer_rules.txt](#fare_transfer_rulestxt) is entirely separate from files [fare_attributes.txt](#fare_attributestxt) and [fare_rules.txt](#fare_rulestxt). |
| [areas.txt](#areastxt) | Optional | Area grouping of locations. |
| [stop_areas.txt](#stop_areastxt) | Optional | Rules to assign stops to areas. |
| [area_sets.txt](#area_setstxt) | Optional | Collections of areas. |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| [area_sets.txt](#area_setstxt) | Optional | Collections of areas. |
| [area_sets.txt](#area_setstxt) | Optional | Collections of areas. |
| [area_set_elements.txt](#area_set_elementstxt) | Optional | Rules to assign areas to area sets. |

| [networks.txt](#networkstxt) | **Conditionally Forbidden** | Network grouping of routes.<br><br>Conditionally Forbidden:<br>- **Forbidden** if `network_id` exists in [routes.txt](#routestxt).<br>- Optional otherwise. |
| [route_networks.txt](#route_networkstxt) | **Conditionally Forbidden** | Rules to assign routes to networks.<br><br>Conditionally Forbidden:<br>- **Forbidden** if `network_id` exists in [routes.txt](#routestxt).<br>- Optional otherwise. |
| [shapes.txt](#shapestxt) | Optional | Rules for mapping vehicle travel paths, sometimes referred to as route alignments. |
Expand Down Expand Up @@ -477,12 +479,16 @@ To process the cost of a leg:

<br/>

For area set predicates in `fare_leg_rules.txt` specified below, a leg “travels through an area” if any of the stops or parent stations (if the area is not defined at the stop-level) of the leg; including departure, arrival, and intermediate stops as referenced by the trip's stop-time entries; belongs to the specified area as defined by [stop_areas.txt](#stopareastxt).

| Field Name | Type | Presence | Description |
| ------ | ------ | ------ | ------ |
| `leg_group_id` | ID | Optional | Identifies a group of entries in [fare_leg_rules.txt](#fare_leg_rulestxt).<br><br> Used to describe fare transfer rules between `fare_transfer_rules.from_leg_group_id` and `fare_transfer_rules.to_leg_group_id`.<br><br>Multiple entries in [fare_leg_rules.txt](#fare_leg_rulestxt) may belong to the same `fare_leg_rules.leg_group_id`.<br><br>The same entry in [fare_leg_rules.txt](#fare_leg_rulestxt) (not including `fare_leg_rules.leg_group_id`) must not belong to multiple `fare_leg_rules.leg_group_id`.|
| `network_id` | Foreign ID referencing `routes.network_id` or `networks.network_id`| Optional | Identifies a route network that applies for the fare leg rule.<br><br>If the `rule_priority` field does not exist AND there are no matching `fare_leg_rules.network_id` values to the `network_id` being filtered, empty `fare_leg_rules.network_id` will be matched by default.<br><br> An empty entry in `fare_leg_rules.network_id` corresponds to all networks defined in [routes.txt](#routestxt) or [networks.txt](#networkstxt) excluding the ones listed under `fare_leg_rules.network_id`<br><br> If the `rule_priority` field exists in the file, an empty `fare_leg_rules.network_id` indicates that the route network of the leg does not affect the matching of this rule. |
| `from_area_id` | Foreign ID referencing `areas.area_id` | Optional | Identifies a departure area.<br><br>If the `rule_priority` field does not exist AND there are no matching `fare_leg_rules.from_area_id` values to the `area_id` being filtered, empty `fare_leg_rules.from_area_id` will be matched by default. <br><br>An empty entry in `fare_leg_rules.from_area_id` corresponds to all areas defined in `areas.area_id` excluding the ones listed under `fare_leg_rules.from_area_id`<br><br> If the `rule_priority` field exists in the file, an empty `fare_leg_rules.from_area_id` indicates that the departure area of the leg does not affect the matching of this rule. |
| `to_area_id` | Foreign ID referencing `areas.area_id` | Optional | Identifies an arrival area.<br><br>If the `rule_priority` field does not exist AND there are no matching `fare_leg_rules.to_area_id` values to the `area_id` being filtered, empty `fare_leg_rules.to_area_id` will be matched by default.<br><br> An empty entry in `fare_leg_rules.to_area_id` corresponds to all areas defined in `areas.area_id` excluding the ones listed under `fare_leg_rules.to_area_id`<br><br>If the `rule_priority` field exists in the file, an empty `fare_leg_rules.to_area_id` indicates that the arrival area of the leg does not affect the matching of this rule. |
| `contains_area_set_id` | Foreign ID referencing `area_sets.area_set_id` | Optional | Identifies an area set containing a collection of areas.<br><br> For this rule to match, a leg must travel through each and every area of the area set. The leg may travel through additional areas not contained by the area set or through stops that are not assigned to an area at all. If not specified, this predicate does not affect the matching of this rule. |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tzujenchanmbd should there also be rules of how contains_exactly_area_set_id and contains_area_set_id interact with from_area_id and to_area_id?
We resolved this in the Network Sets PR by forbidding the network_id predicate when the set predicates exist. We can do the same here.

Also, if contains_area_set_id and contains_exactly_area_set_id both exist, contains_area_set_id would have to be included in contains_exactly_area_set_id, causing a redundancy. If not, the leg rule will never be matched. Should we do the same thing we did for network sets and make them mutually exclusive as well?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there also be rules of how contains_exactly_area_set_id and contains_area_set_id interact with from_area_id and to_area_id?

@skalexch I think the from_area_id / to_area_id case is different from network_id?
The network_id predicate matches a single network, which is logically at odds with a network_set that represents multiple networks within the same leg rule. In contrast, from_area_id and to_area_id describe the origin and destination areas of a leg. Producers may want to define different fares for different origin–destination pairs within the same area_set (e.g., A→D vs. A→C within area set ABCD), especially when fare_leg_join_rule is used. Allowing them to be used together should provide more flexibility?

Also, if contains_area_set_id and contains_exactly_area_set_id both exist,

Agree that the interaction between contains_area_set_id and contains_exactly_area_set_id is similar to the network set case and that they should be mutually exclusive. I’ll update the suggestions accordingly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tzujenchanmbd 100% agree. Let's keep the intersection with from_area_id / to_area_id but enforce mutual exclusivity between contains_area_set_id and contains_exactly_area_set_id.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these be added as a primary key to this file?

| `contains_exactly_area_set_id` | Foreign ID referencing `area_sets.area_set_id` | Optional | Identifies an area set containing a collection of areas.<br><br> For this rule to match, a leg must travel through each and every area of the specified area set. Each and every stop the leg travels through must belong to at least one area in the area set. If not specified, this predicate does not affect the matching of this rule. |
| `from_timeframe_group_id` | Foreign ID referencing `timeframes.timeframe_group_id` | Optional | Defines the timeframe for the fare validation event at the start of the fare leg.<br><br>The “start time” of the fare leg is the time at which the event is scheduled to occur. For example, the time could be the scheduled departure time of a bus at the start of a fare leg where the rider boards and validates their fare. For the rule matching semantics below, the start time is computed in local time, as determined by [Local Time Semantics](#localtimesemantics) of [timeframes.txt](#timeframestxt). The stop or station of the fare leg’s departure event should be used for timezone resolution, where appropriate.<br><br>For a fare leg rule that specifies a `from_timeframe_group_id`, that rule will match a particular leg if there exists at least one record in [timeframes.txt](#timeframestxt) where all of the following conditions are true<br>- The value of `timeframe_group_id` is equal to the `from_timeframe_group_id` value.<br>- The set of days identified by the record’s `service_id` contains the “current day” of the fare leg’s start time.<br>- The “time-of-day” of the fare leg's start time is greater than or equal to the record’s `timeframes.start_time` value and less than the `timeframes.end_time` value.<br><br>An empty `fare_leg_rules.from_timeframe_group_id` indicates that the start time of the leg does not affect the matching of this rule. |
| `to_timeframe_group_id` | Foreign ID referencing `timeframes.timeframe_group_id` | Optional | Defines the timeframe for the fare validation event at the end of the fare leg.<br><br>The “end time” of the fare leg is the time at which the event is scheduled to occur. For example, the time could be the scheduled arrival time of a bus at the end of a fare leg where the rider gets off and validates their fare. For the rule matching semantics below, the end time is computed in local time, as determined by [Local Time Semantics](#localtimesemantics) of [timeframes.txt](#timeframestxt). The stop or station of the fare leg’s arrival event should be used for timezone resolution, where appropriate.<br><br>For a fare leg rule that specifies a `to_timeframe_group_id`, that rule will match a particular leg if there exists at least one record in [timeframes.txt](#timeframestxt) where all of the following conditions are true<br>- The value of `timeframe_group_id` is equal to the `to_timeframe_group_id` value.<br>- The set of days identified by the record’s `service_id` contains the “current day” of the fare leg’s end time.<br>- The “time-of-day” of the fare leg's end time is greater than or equal to the record’s `timeframes.start_time` value and less than the `timeframes.end_time` value.<br><br>An empty `fare_leg_rules.to_timeframe_group_id` indicates that the end time of the leg does not affect the matching of this rule. |
| `fare_product_id` | Foreign ID referencing `fare_products.fare_product_id` | **Required** | The fare product required to travel the leg. |
Expand Down Expand Up @@ -550,6 +556,19 @@ Assigns stops from [stops.txt](#stopstxt) to areas.
| `area_id` | Foreign ID referencing `areas.area_id` | **Required** | Identifies an area to which one or multiple `stop_id`s belong. The same `stop_id` may be defined in many `area_id`s. |
| `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies a stop. If a station (i.e. a stop with `stops.location_type=1`) is defined in this field, it is assumed that all of its platforms (i.e. all stops with `stops.location_type=0` that have this station defined as `stops.parent_station`) are part of the same area. This behavior can be overridden by assigning platforms to other areas. |

### area_sets.txt

File: **Optional**

Primary key (`*`)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Primary key (`*`)
Primary key (`area_set_id`)


Groups collections of areas into sets.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Groups collections of areas into sets.
Defines area set identifiers that apply for fare leg rules.


| Field Name | Type | Presence | Description |
| ------ | ------ | ------ | ------ |
| `area_set_id` | Unique ID | **Required** | Identifies an area set. Must be unique in [area_sets.txt](#area_setstxt). |
| `area_id` | Foreign ID referencing `areas.area_id` | **Required** | Identifies an area to be included in the set. The same `area_id` may be defined in multiple area sets. |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| `area_id` | Foreign ID referencing `areas.area_id` | **Required** | Identifies an area to be included in the set. The same `area_id` may be defined in multiple area sets. |

Copy link
Collaborator

@skalexch skalexch Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name also needs to be added.
| `area_set_name` | Text | **Required** | The name of the area set. |


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### area_set_elements.txt
File: **Optional**
Primary key (`*`)
Groups collections of areas into sets.
| Field Name | Type | Presence | Description |
| ------ | ------ | ------ | ------ |
| `area_set_id` | Foreign ID referencing `area_sets.area_set_id` | **Required** | Identifies an area set to which one or multiple `area_id`s belong. |
| `area_id` | Foreign ID referencing `areas.area_id` | **Required** | Identifies an area to be included in the set. The same `area_id` may be defined in multiple area sets. |

### networks.txt

File: **Conditionally Forbidden**
Expand Down