Calculating fares using the GTFS specification

We’ve just released TransitTimes+ 2.1, and this version shows fare calculations for trips, based on the data specified in the fare_attributes.txt and fare_rules.txt file in agencies’ GTFS feeds.

(Fares are shown in footer of the trip description, if made available by the transit agency. In this case, TriMet of Portland supply this data)

Rather than describing the structure of these files, you can read the specification and then read some detailed examples.

If you read these examples, you’ll see that it can be quite complex to calculate a fare, especially when one or more transfers are involved. Here’s how we’ve done it in TransitTimes+:

  1. Find qualifying fares for each segment of a trip, disregarding transfer options
  2. Create every combination of fares possible
  3. Find the cheapest total, this time accounting for transfers

1. Find Qualifying Fares

To determine a qualifying fare for a trip, you must typically know its start and finish stop. When a transit agency includes fare information, they must also include zone information with each stop. If a stop doesn’t have a zone specified, then a fare cannot be calculated.

(Note: technically, some fares don’t rely on zone information, in which case they don’t have corresponding rules in fare_rules.txt. In this case, the zone is not required).

You can then determine qualifying fares using the route_id, origin_id, destination_id and contains_id fields.

It’s important to understand the fare examples (linked above) to see how the contains_id field works, as a trip must pass through the zone IDs as exactly specified in the rules in order to qualify.

2. Create Fare Combinations

At this point, every segment in a trip will have 0 or more fare options associated with it. If it has 0, then it’s not possible to estimate the fare.

Assuming we can calculate the fare, we use a recursive algorithm to build up every combination of fares. For instance, if Segment A has fares 1, 2, 3, and Segment B has 4, 5, 6, our combinations are 1-4, 1-5, 1-6, 2-4, 2-5, 2-6, 3-4, 3-5, 3-6.

3. Find The Cheapest Total

Once you’ve created all fare combinations, this is a case of looping over each combination and calculating the total. Lowest total wins.

When calculating the price, you must account for transfers. Transfers can be time-based (e.g. unlimited usage for 2 hours) or quantity-based (e.g. up to 1 transfer).

There is some ambiguity in the specification about when the transfer time starts (does it begin from start of initial trip, and can the transfer time expire during the subsequent segment?). For these we must make assumptions.

In TransitTimes+, we made the assumption that if the subsequent trip starts before the transfer time expires, then the transfer qualifies.


As you can see, it’s not the easiest thing to calculate fares. GTFS was designed in such a way that most transit agencies can accurately model their pricing scheme in the same generic way.

There are some drawbacks with this system, one which is that there’s no time-based information specified. This is a problem in a city such as Adelaide, where fares are cheaper between 9am and 3pm on weekdays.

Additionally, the whole GTFS fare system is designed around “adult fares” (that is, the full fare – no concessions or discounts). This means it’s not possible to specify different rates for children or seniors.

Also, it’s not possible to account for bulk purchasing of tickets, so when displaying fares using GTFS information it’s generally calculated using the one-off ticket price.